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
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/CMakeLists.txt4
-rw-r--r--source/blender/blenfont/BLF_api.h12
-rw-r--r--source/blender/blenfont/CMakeLists.txt2
-rw-r--r--source/blender/blenfont/intern/blf_internal.h6
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h17
-rw-r--r--source/blender/blenkernel/BKE_action.h32
-rw-r--r--source/blender/blenkernel/BKE_anim_data.h15
-rw-r--r--source/blender/blenkernel/BKE_animsys.h80
-rw-r--r--source/blender/blenkernel/BKE_appdir.h21
-rw-r--r--source/blender/blenkernel/BKE_armature.h26
-rw-r--r--source/blender/blenkernel/BKE_asset_catalog.hh2
-rw-r--r--source/blender/blenkernel/BKE_asset_library.hh2
-rw-r--r--source/blender/blenkernel/BKE_attribute.h17
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh56
-rw-r--r--source/blender/blenkernel/BKE_attribute_math.hh67
-rw-r--r--source/blender/blenkernel/BKE_blender_copybuffer.h6
-rw-r--r--source/blender/blenkernel/BKE_blender_undo.h4
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h6
-rw-r--r--source/blender/blenkernel/BKE_blendfile_link_append.h20
-rw-r--r--source/blender/blenkernel/BKE_bpath.h10
-rw-r--r--source/blender/blenkernel/BKE_brush.h30
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h58
-rw-r--r--source/blender/blenkernel/BKE_cachefile.h16
-rw-r--r--source/blender/blenkernel/BKE_callbacks.h4
-rw-r--r--source/blender/blenkernel/BKE_camera.h6
-rw-r--r--source/blender/blenkernel/BKE_collection.h24
-rw-r--r--source/blender/blenkernel/BKE_collision.h6
-rw-r--r--source/blender/blenkernel/BKE_colorband.h2
-rw-r--r--source/blender/blenkernel/BKE_colortools.h4
-rw-r--r--source/blender/blenkernel/BKE_constraint.h8
-rw-r--r--source/blender/blenkernel/BKE_context.h12
-rw-r--r--source/blender/blenkernel/BKE_crazyspace.h29
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.h2
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.hh2
-rw-r--r--source/blender/blenkernel/BKE_curve.h111
-rw-r--r--source/blender/blenkernel/BKE_curve_to_mesh.hh2
-rw-r--r--source/blender/blenkernel/BKE_curveprofile.h10
-rw-r--r--source/blender/blenkernel/BKE_customdata.h51
-rw-r--r--source/blender/blenkernel/BKE_data_transfer.h64
-rw-r--r--source/blender/blenkernel/BKE_deform.h93
-rw-r--r--source/blender/blenkernel/BKE_displist.h6
-rw-r--r--source/blender/blenkernel/BKE_duplilist.h2
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h13
-rw-r--r--source/blender/blenkernel/BKE_editmesh_bvh.h18
-rw-r--r--source/blender/blenkernel/BKE_editmesh_tangent.h2
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h26
-rw-r--r--source/blender/blenkernel/BKE_fcurve_driver.h10
-rw-r--r--source/blender/blenkernel/BKE_fluid.h6
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h4
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh198
-rw-r--r--source/blender/blenkernel/BKE_global.h4
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h40
-rw-r--r--source/blender/blenkernel/BKE_gpencil_curve.h18
-rw-r--r--source/blender/blenkernel/BKE_gpencil_geom.h81
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h20
-rw-r--r--source/blender/blenkernel/BKE_icons.h24
-rw-r--r--source/blender/blenkernel/BKE_idprop.h33
-rw-r--r--source/blender/blenkernel/BKE_idprop.hh93
-rw-r--r--source/blender/blenkernel/BKE_idtype.h30
-rw-r--r--source/blender/blenkernel/BKE_image.h94
-rw-r--r--source/blender/blenkernel/BKE_key.h22
-rw-r--r--source/blender/blenkernel/BKE_lattice.h30
-rw-r--r--source/blender/blenkernel/BKE_layer.h25
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h66
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h52
-rw-r--r--source/blender/blenkernel/BKE_lib_query.h18
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h83
-rw-r--r--source/blender/blenkernel/BKE_lightprobe.h2
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h10
-rw-r--r--source/blender/blenkernel/BKE_main.h14
-rw-r--r--source/blender/blenkernel/BKE_main_idmap.h7
-rw-r--r--source/blender/blenkernel/BKE_mask.h62
-rw-r--r--source/blender/blenkernel/BKE_material.h6
-rw-r--r--source/blender/blenkernel/BKE_mball.h11
-rw-r--r--source/blender/blenkernel/BKE_mesh.h252
-rw-r--r--source/blender/blenkernel/BKE_mesh_boolean_convert.hh6
-rw-r--r--source/blender/blenkernel/BKE_mesh_fair.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh_iterators.h17
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h79
-rw-r--r--source/blender/blenkernel/BKE_mesh_mirror.h15
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h75
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h12
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.hh6
-rw-r--r--source/blender/blenkernel/BKE_mesh_tangent.h13
-rw-r--r--source/blender/blenkernel/BKE_mesh_wrapper.h3
-rw-r--r--source/blender/blenkernel/BKE_modifier.h14
-rw-r--r--source/blender/blenkernel/BKE_multires.h26
-rw-r--r--source/blender/blenkernel/BKE_nla.h20
-rw-r--r--source/blender/blenkernel/BKE_node.h339
-rw-r--r--source/blender/blenkernel/BKE_node_tree_update.h110
-rw-r--r--source/blender/blenkernel/BKE_object.h62
-rw-r--r--source/blender/blenkernel/BKE_object_deform.h12
-rw-r--r--source/blender/blenkernel/BKE_ocean.h10
-rw-r--r--source/blender/blenkernel/BKE_packedFile.h2
-rw-r--r--source/blender/blenkernel/BKE_paint.h23
-rw-r--r--source/blender/blenkernel/BKE_particle.h32
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h18
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h2
-rw-r--r--source/blender/blenkernel/BKE_pointcloud.h4
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h8
-rw-r--r--source/blender/blenkernel/BKE_scene.h28
-rw-r--r--source/blender/blenkernel/BKE_screen.h33
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h6
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h10
-rw-r--r--source/blender/blenkernel/BKE_spline.hh74
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h40
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h13
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h95
-rw-r--r--source/blender/blenkernel/BKE_subdiv_foreach.h93
-rw-r--r--source/blender/blenkernel/BKE_subdiv_modifier.h79
-rw-r--r--source/blender/blenkernel/BKE_text.h46
-rw-r--r--source/blender/blenkernel/BKE_text_suggestions.h2
-rw-r--r--source/blender/blenkernel/BKE_texture.h2
-rw-r--r--source/blender/blenkernel/BKE_tracking.h10
-rw-r--r--source/blender/blenkernel/BKE_undo_system.h8
-rw-r--r--source/blender/blenkernel/BKE_vfont.h4
-rw-r--r--source/blender/blenkernel/BKE_vfontdata.h2
-rw-r--r--source/blender/blenkernel/BKE_volume.h13
-rw-r--r--source/blender/blenkernel/BKE_volume_to_mesh.hh23
-rw-r--r--source/blender/blenkernel/BKE_workspace.h8
-rw-r--r--source/blender/blenkernel/BKE_writeavi.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt22
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc334
-rw-r--r--source/blender/blenkernel/intern/action.c22
-rw-r--r--source/blender/blenkernel/intern/anim_data.c35
-rw-r--r--source/blender/blenkernel/intern/armature.c82
-rw-r--r--source/blender/blenkernel/intern/asset_catalog.cc18
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_test.cc40
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc2
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh10
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c56
-rw-r--r--source/blender/blenkernel/intern/bpath.c6
-rw-r--r--source/blender/blenkernel/intern/brush.c23
-rw-r--r--source/blender/blenkernel/intern/bvhutils.cc4
-rw-r--r--source/blender/blenkernel/intern/cachefile.c47
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c4
-rw-r--r--source/blender/blenkernel/intern/cloth.c3
-rw-r--r--source/blender/blenkernel/intern/collection.c94
-rw-r--r--source/blender/blenkernel/intern/constraint.c44
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c85
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc4
-rw-r--r--source/blender/blenkernel/intern/curve.cc (renamed from source/blender/blenkernel/intern/curve.c)604
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc10
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc15
-rw-r--r--source/blender/blenkernel/intern/curveprofile.cc2
-rw-r--r--source/blender/blenkernel/intern/customdata.cc (renamed from source/blender/blenkernel/intern/customdata.c)1047
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c31
-rw-r--r--source/blender/blenkernel/intern/data_transfer_intern.h51
-rw-r--r--source/blender/blenkernel/intern/displist.cc32
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c26
-rw-r--r--source/blender/blenkernel/intern/editmesh.c42
-rw-r--r--source/blender/blenkernel/intern/effect.c4
-rw-r--r--source/blender/blenkernel/intern/fcurve.c4
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c7
-rw-r--r--source/blender/blenkernel/intern/fluid.c67
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc94
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc64
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc411
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc56
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc20
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc28
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c8
-rw-r--r--source/blender/blenkernel/intern/hair.cc (renamed from source/blender/blenkernel/intern/hair.c)114
-rw-r--r--source/blender/blenkernel/intern/idprop_create.cc140
-rw-r--r--source/blender/blenkernel/intern/idprop_serialize.cc844
-rw-r--r--source/blender/blenkernel/intern/idprop_serialize_test.cc448
-rw-r--r--source/blender/blenkernel/intern/image.c392
-rw-r--r--source/blender/blenkernel/intern/image_gpu.cc2
-rw-r--r--source/blender/blenkernel/intern/image_save.c53
-rw-r--r--source/blender/blenkernel/intern/key.c13
-rw-r--r--source/blender/blenkernel/intern/lattice.c6
-rw-r--r--source/blender/blenkernel/intern/layer.c68
-rw-r--r--source/blender/blenkernel/intern/lib_id.c54
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c42
-rw-r--r--source/blender/blenkernel/intern/lib_id_remapper.cc175
-rw-r--r--source/blender/blenkernel/intern/lib_id_remapper_test.cc83
-rw-r--r--source/blender/blenkernel/intern/lib_override.c331
-rw-r--r--source/blender/blenkernel/intern/lib_query.c2
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c348
-rw-r--r--source/blender/blenkernel/intern/lib_remap_test.cc369
-rw-r--r--source/blender/blenkernel/intern/linestyle.c3
-rw-r--r--source/blender/blenkernel/intern/mask.c3
-rw-r--r--source/blender/blenkernel/intern/material.c5
-rw-r--r--source/blender/blenkernel/intern/mesh.cc147
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc75
-rw-r--r--source/blender/blenkernel/intern/mesh_debug.cc115
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c59
-rw-r--r--source/blender/blenkernel/intern/mesh_merge.c16
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c16
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc243
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c66
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c128
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c11
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c19
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.c91
-rw-r--r--source/blender/blenkernel/intern/modifier.c18
-rw-r--r--source/blender/blenkernel/intern/movieclip.c19
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.h13
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_smooth.c89
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_util.c6
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_vertcos.c3
-rw-r--r--source/blender/blenkernel/intern/multires_versioning.c2
-rw-r--r--source/blender/blenkernel/intern/node.cc1456
-rw-r--r--source/blender/blenkernel/intern/node_tree_update.cc1670
-rw-r--r--source/blender/blenkernel/intern/object.cc125
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc86
-rw-r--r--source/blender/blenkernel/intern/object_update.c18
-rw-r--r--source/blender/blenkernel/intern/packedFile.c2
-rw-r--r--source/blender/blenkernel/intern/paint.c1
-rw-r--r--source/blender/blenkernel/intern/particle.c19
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c3
-rw-r--r--source/blender/blenkernel/intern/pbvh.c24
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h3
-rw-r--r--source/blender/blenkernel/intern/pointcache.c57
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc83
-rw-r--r--source/blender/blenkernel/intern/screen.c26
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c48
-rw-r--r--source/blender/blenkernel/intern/simulation.cc2
-rw-r--r--source/blender/blenkernel/intern/softbody.c2
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc45
-rw-r--r--source/blender/blenkernel/intern/spline_bezier.cc55
-rw-r--r--source/blender/blenkernel/intern/spline_nurbs.cc89
-rw-r--r--source/blender/blenkernel/intern/spline_poly.cc8
-rw-r--r--source/blender/blenkernel/intern/subdiv.c12
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c3
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter_mesh.c15
-rw-r--r--source/blender/blenkernel/intern/subdiv_deform.c6
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c250
-rw-r--r--source/blender/blenkernel/intern/subdiv_foreach.c3
-rw-r--r--source/blender/blenkernel/intern/subdiv_inline.h6
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c112
-rw-r--r--source/blender/blenkernel/intern/subdiv_modifier.c160
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c64
-rw-r--r--source/blender/blenkernel/intern/texture.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_region_tracker.c7
-rw-r--r--source/blender/blenkernel/intern/tracking_test.cc2
-rw-r--r--source/blender/blenkernel/intern/type_conversions.cc3
-rw-r--r--source/blender/blenkernel/intern/undo_system.c3
-rw-r--r--source/blender/blenkernel/intern/volume.cc62
-rw-r--r--source/blender/blenkernel/intern/volume_render.cc2
-rw-r--r--source/blender/blenkernel/intern/volume_to_mesh.cc11
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c2
-rw-r--r--source/blender/blenkernel/nla_private.h14
-rw-r--r--source/blender/blenlib/BLI_any.hh2
-rw-r--r--source/blender/blenlib/BLI_array.h6
-rw-r--r--source/blender/blenlib/BLI_array.hh8
-rw-r--r--source/blender/blenlib/BLI_array_store.h2
-rw-r--r--source/blender/blenlib/BLI_array_store_utils.h6
-rw-r--r--source/blender/blenlib/BLI_array_utils.h4
-rw-r--r--source/blender/blenlib/BLI_assert.h5
-rw-r--r--source/blender/blenlib/BLI_astar.h25
-rw-r--r--source/blender/blenlib/BLI_bitmap_draw_2d.h10
-rw-r--r--source/blender/blenlib/BLI_boxpack_2d.h2
-rw-r--r--source/blender/blenlib/BLI_buffer.h4
-rw-r--r--source/blender/blenlib/BLI_color.hh19
-rw-r--r--source/blender/blenlib/BLI_compiler_compat.h2
-rw-r--r--source/blender/blenlib/BLI_convexhull_2d.h4
-rw-r--r--source/blender/blenlib/BLI_delaunay_2d.h6
-rw-r--r--source/blender/blenlib/BLI_dlrbTree.h6
-rw-r--r--source/blender/blenlib/BLI_double2.hh143
-rw-r--r--source/blender/blenlib/BLI_double3.hh246
-rw-r--r--source/blender/blenlib/BLI_edgehash.h8
-rw-r--r--source/blender/blenlib/BLI_endian_switch.h18
-rw-r--r--source/blender/blenlib/BLI_endian_switch_inline.h3
-rw-r--r--source/blender/blenlib/BLI_fileops.h19
-rw-r--r--source/blender/blenlib/BLI_fileops.hh52
-rw-r--r--source/blender/blenlib/BLI_filereader.h12
-rw-r--r--source/blender/blenlib/BLI_float2.hh218
-rw-r--r--source/blender/blenlib/BLI_float3.hh304
-rw-r--r--source/blender/blenlib/BLI_float4.hh138
-rw-r--r--source/blender/blenlib/BLI_float4x4.hh5
-rw-r--r--source/blender/blenlib/BLI_function_ref.hh6
-rw-r--r--source/blender/blenlib/BLI_ghash.h38
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h2
-rw-r--r--source/blender/blenlib/BLI_hash.hh10
-rw-r--r--source/blender/blenlib/BLI_index_range.hh2
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h8
-rw-r--r--source/blender/blenlib/BLI_kdtree_impl.h12
-rw-r--r--source/blender/blenlib/BLI_lasso_2d.h13
-rw-r--r--source/blender/blenlib/BLI_linklist_lockfree.h11
-rw-r--r--source/blender/blenlib/BLI_listbase.h57
-rw-r--r--source/blender/blenlib/BLI_math_base.h20
-rw-r--r--source/blender/blenlib/BLI_math_bits.h5
-rw-r--r--source/blender/blenlib/BLI_math_boolean.hh6
-rw-r--r--source/blender/blenlib/BLI_math_color.h23
-rw-r--r--source/blender/blenlib/BLI_math_geom.h152
-rw-r--r--source/blender/blenlib/BLI_math_interp.h8
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h60
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h113
-rw-r--r--source/blender/blenlib/BLI_math_solvers.h4
-rw-r--r--source/blender/blenlib/BLI_math_statistics.h10
-rw-r--r--source/blender/blenlib/BLI_math_vec_mpq_types.hh92
-rw-r--r--source/blender/blenlib/BLI_math_vec_types.hh566
-rw-r--r--source/blender/blenlib/BLI_math_vector.h189
-rw-r--r--source/blender/blenlib/BLI_math_vector.hh404
-rw-r--r--source/blender/blenlib/BLI_memarena.h4
-rw-r--r--source/blender/blenlib/BLI_memory_utils.h2
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh6
-rw-r--r--source/blender/blenlib/BLI_mempool.h8
-rw-r--r--source/blender/blenlib/BLI_mesh_intersect.hh7
-rw-r--r--source/blender/blenlib/BLI_mpq2.hh184
-rw-r--r--source/blender/blenlib/BLI_mpq3.hh297
-rw-r--r--source/blender/blenlib/BLI_noise.hh213
-rw-r--r--source/blender/blenlib/BLI_path_util.h57
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d.h8
-rw-r--r--source/blender/blenlib/BLI_polyfill_2d_beautify.h4
-rw-r--r--source/blender/blenlib/BLI_quadric.h13
-rw-r--r--source/blender/blenlib/BLI_rand.hh3
-rw-r--r--source/blender/blenlib/BLI_rect.h39
-rw-r--r--source/blender/blenlib/BLI_scanfill.h7
-rw-r--r--source/blender/blenlib/BLI_serialize.hh25
-rw-r--r--source/blender/blenlib/BLI_session_uuid.h7
-rw-r--r--source/blender/blenlib/BLI_smallhash.h4
-rw-r--r--source/blender/blenlib/BLI_sort.h2
-rw-r--r--source/blender/blenlib/BLI_span.hh15
-rw-r--r--source/blender/blenlib/BLI_stack.h6
-rw-r--r--source/blender/blenlib/BLI_string.h48
-rw-r--r--source/blender/blenlib/BLI_string_ref.hh28
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h22
-rw-r--r--source/blender/blenlib/BLI_string_utils.h10
-rw-r--r--source/blender/blenlib/BLI_sys_types.h2
-rw-r--r--source/blender/blenlib/BLI_system.h10
-rw-r--r--source/blender/blenlib/BLI_task.h12
-rw-r--r--source/blender/blenlib/BLI_threads.h11
-rw-r--r--source/blender/blenlib/BLI_timecode.h21
-rw-r--r--source/blender/blenlib/BLI_timer.h11
-rw-r--r--source/blender/blenlib/BLI_utildefines.h16
-rw-r--r--source/blender/blenlib/BLI_vector.hh16
-rw-r--r--source/blender/blenlib/BLI_vector_set.hh10
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh14
-rw-r--r--source/blender/blenlib/BLI_virtual_vector_array.hh6
-rw-r--r--source/blender/blenlib/BLI_winstuff.h7
-rw-r--r--source/blender/blenlib/CMakeLists.txt21
-rw-r--r--source/blender/blenlib/intern/BLI_mempool_private.h5
-rw-r--r--source/blender/blenlib/intern/array_store.c2
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.cc45
-rw-r--r--source/blender/blenlib/intern/fileops.cc51
-rw-r--r--source/blender/blenlib/intern/kdtree_impl.h4
-rw-r--r--source/blender/blenlib/intern/list_sort_impl.h2
-rw-r--r--source/blender/blenlib/intern/listbase.c20
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c16
-rw-r--r--source/blender/blenlib/intern/math_boolean.cc7
-rw-r--r--source/blender/blenlib/intern/math_color_blend_inline.c16
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c2
-rw-r--r--source/blender/blenlib/intern/math_geom.c2
-rw-r--r--source/blender/blenlib/intern/math_vec.cc133
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c7
-rw-r--r--source/blender/blenlib/intern/mesh_boolean.cc51
-rw-r--r--source/blender/blenlib/intern/mesh_intersect.cc92
-rw-r--r--source/blender/blenlib/intern/noise.cc79
-rw-r--r--source/blender/blenlib/intern/path_util.c66
-rw-r--r--source/blender/blenlib/intern/polyfill_2d.c4
-rw-r--r--source/blender/blenlib/intern/polyfill_2d_beautify.c2
-rw-r--r--source/blender/blenlib/intern/scanfill.c4
-rw-r--r--source/blender/blenlib/intern/serialize.cc23
-rw-r--r--source/blender/blenlib/intern/string_cursor_utf8.c2
-rw-r--r--source/blender/blenlib/intern/task_graph.cc2
-rw-r--r--source/blender/blenlib/intern/task_scheduler.cc6
-rw-r--r--source/blender/blenlib/intern/threads.cc112
-rw-r--r--source/blender/blenlib/intern/timecode.c2
-rw-r--r--source/blender/blenlib/tests/BLI_any_test.cc20
-rw-r--r--source/blender/blenlib/tests/BLI_delaunay_2d_test.cc3
-rw-r--r--source/blender/blenlib/tests/BLI_fileops_test.cc40
-rw-r--r--source/blender/blenlib/tests/BLI_listbase_test.cc25
-rw-r--r--source/blender/blenlib/tests/BLI_math_vec_types_test.cc149
-rw-r--r--source/blender/blenlib/tests/BLI_memory_utils_test.cc9
-rw-r--r--source/blender/blenlib/tests/BLI_mesh_boolean_test.cc2
-rw-r--r--source/blender/blenlib/tests/BLI_mesh_intersect_test.cc2
-rw-r--r--source/blender/blenlib/tests/BLI_serialize_test.cc4
-rw-r--r--source/blender/blenlib/tests/BLI_task_test.cc4
-rw-r--r--source/blender/blenlib/tests/BLI_vector_test.cc11
-rw-r--r--source/blender/blenlib/tests/performance/CMakeLists.txt1
-rw-r--r--source/blender/blenloader/BLO_readfile.h20
-rw-r--r--source/blender/blenloader/BLO_writefile.h2
-rw-r--r--source/blender/blenloader/CMakeLists.txt1
-rw-r--r--source/blender/blenloader/intern/readfile.c3
-rw-r--r--source/blender/blenloader/intern/readfile.h2
-rw-r--r--source/blender/blenloader/intern/versioning_250.c19
-rw-r--r--source/blender/blenloader/intern/versioning_260.c1
-rw-r--r--source/blender/blenloader/intern/versioning_280.c5
-rw-r--r--source/blender/blenloader/intern/versioning_300.c121
-rw-r--r--source/blender/blenloader/intern/versioning_common.cc16
-rw-r--r--source/blender/blenloader/intern/versioning_common.h19
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c31
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c5
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c3
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c4
-rw-r--r--source/blender/blenloader/intern/writefile.c38
-rw-r--r--source/blender/blenloader/tests/blendfile_loading_base_test.cc8
-rw-r--r--source/blender/blentranslation/msgfmt/CMakeLists.txt1
-rw-r--r--source/blender/bmesh/CMakeLists.txt6
-rw-r--r--source/blender/bmesh/bmesh.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c42
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h45
-rw-r--r--source/blender/bmesh/intern/bmesh_core.h53
-rw-r--r--source/blender/bmesh/intern/bmesh_delete.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.h6
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h30
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.h23
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c15
-rw-r--r--source/blender/bmesh/intern/bmesh_log.h11
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.h68
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h30
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc (renamed from source/blender/bmesh/intern/bmesh_mesh_convert.c)333
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_debug.c86
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_debug.h30
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.h16
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_partial_update.h10
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h36
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c1
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h89
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h56
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c7
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h14
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h14
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h90
-rw-r--r--source/blender/bmesh/intern/bmesh_query_uv.h28
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h5
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.c16
-rw-r--r--source/blender/bmesh/operators/bmo_create.c2
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c39
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.h14
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h40
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.h10
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.h24
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate.h26
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.h2
-rw-r--r--source/blender/bmesh/tools/bmesh_edgesplit.h5
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.h18
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.h2
-rw-r--r--source/blender/bmesh/tools/bmesh_path_region_uv.h6
-rw-r--r--source/blender/bmesh/tools/bmesh_triangulate.h8
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.h28
-rw-r--r--source/blender/compositor/CMakeLists.txt22
-rw-r--r--source/blender/compositor/COM_defines.h2
-rw-r--r--source/blender/compositor/COM_precomp.h33
-rw-r--r--source/blender/compositor/intern/COM_ConstantFolder.cc6
-rw-r--r--source/blender/compositor/intern/COM_Converter.cc8
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc6
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.h8
-rw-r--r--source/blender/compositor/intern/COM_FullFrameExecutionModel.h6
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cc17
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h27
-rw-r--r--source/blender/compositor/intern/COM_MemoryProxy.cc1
-rw-r--r--source/blender/compositor/intern/COM_Node.h4
-rw-r--r--source/blender/compositor/intern/COM_compositor.cc2
-rw-r--r--source/blender/compositor/nodes/COM_ConvertColorSpaceNode.cc100
-rw-r--r--source/blender/compositor/nodes/COM_ConvertColorSpaceNode.h46
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cc5
-rw-r--r--source/blender/compositor/nodes/COM_SceneTimeNode.cc50
-rw-r--r--source/blender/compositor/nodes/COM_SceneTimeNode.h36
-rw-r--r--source/blender/compositor/operations/COM_ConvertColorSpaceOperation.cc91
-rw-r--r--source/blender/compositor/operations/COM_ConvertColorSpaceOperation.h57
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.cc30
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc5
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h9
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc5
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc5
-rw-r--r--source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h8
-rw-r--r--source/blender/compositor/operations/COM_GlareBaseOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_KeyingBlurOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_KeyingClipOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.cc11
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_RotateOperation.h24
-rw-r--r--source/blender/compositor/operations/COM_ScaleOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cc16
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.h4
-rw-r--r--source/blender/datatoc/CMakeLists.txt4
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h11
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cache.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cache.h10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc88
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h24
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc17
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc105
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc20
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc12
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc14
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc52
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc25
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.cc4
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.h8
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.cc2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h20
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_factory.h2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc3
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.h3
-rw-r--r--source/blender/draw/CMakeLists.txt558
-rw-r--r--source/blender/draw/DRW_engine.h12
-rw-r--r--source/blender/draw/DRW_select_buffer.h17
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.h15
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h10
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c8
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_vert.glsl3
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h8
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_fx.c7
-rw-r--r--source/blender/draw/engines/image/image_private.hh4
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c204
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_mesh.c6
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_uv.c16
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h30
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.c6
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c9
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl2
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl6
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl12
-rw-r--r--source/blender/draw/engines/select/select_draw_utils.c2
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh41
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh64
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh31
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_effect_dof_info.hh55
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_effect_outline_info.hh11
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh9
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh149
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh98
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_transparent_resolve_info.hh10
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh114
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl8
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl13
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl11
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl8
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl31
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl8
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl39
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl4
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl5
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl7
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl12
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl10
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl6
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl9
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl16
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl13
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl18
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl15
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl49
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl6
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl36
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl14
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl13
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl7
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl32
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl14
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl8
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_cavity.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_dof.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_outline.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c9
-rw-r--r--source/blender/draw/engines/workbench/workbench_opaque.c14
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h3
-rw-r--r--source/blender/draw/engines/workbench/workbench_shader.c562
-rw-r--r--source/blender/draw/engines/workbench/workbench_shader.cc398
-rw-r--r--source/blender/draw/engines/workbench/workbench_shader_shared.h (renamed from source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl)26
-rw-r--r--source/blender/draw/engines/workbench/workbench_transparent.c14
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c8
-rw-r--r--source/blender/draw/intern/DRW_gpu_wrapper.hh812
-rw-r--r--source/blender/draw/intern/DRW_render.h24
-rw-r--r--source/blender/draw/intern/draw_cache.c44
-rw-r--r--source/blender/draw/intern/draw_cache.h2
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h50
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc128
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.c22
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h44
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.cc2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_hair.cc (renamed from source/blender/draw/intern/draw_cache_impl_hair.c)45
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c191
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc1944
-rw-r--r--source/blender/draw/intern/draw_common.h2
-rw-r--r--source/blender/draw/intern/draw_debug.h6
-rw-r--r--source/blender/draw/intern/draw_hair.c4
-rw-r--r--source/blender/draw/intern/draw_manager.c111
-rw-r--r--source/blender/draw/intern/draw_manager.h2
-rw-r--r--source/blender/draw/intern/draw_manager_data.c18
-rw-r--r--source/blender/draw/intern/draw_manager_text.h2
-rw-r--r--source/blender/draw/intern/draw_shader.c7
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h52
-rw-r--r--source/blender/draw/intern/draw_subdivision.h231
-rw-r--r--source/blender/draw/intern/draw_view_data.h4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.h96
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc227
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc31
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc88
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc67
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc30
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc97
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc88
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc125
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc79
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc59
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc65
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc48
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc31
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc132
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc109
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc97
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc1
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc89
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc111
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc48
-rw-r--r--source/blender/draw/intern/shaders/common_fullscreen_vert.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl9
-rw-r--r--source/blender/draw/intern/shaders/common_hair_refine_comp.glsl5
-rw-r--r--source/blender/draw/intern/shaders/common_pointcloud_lib.glsl17
-rw-r--r--source/blender/draw/intern/shaders/common_smaa_lib.glsl6
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl230
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl57
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl43
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_lib.glsl176
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl56
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl34
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl416
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl97
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl80
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl31
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl52
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl47
-rw-r--r--source/blender/draw/intern/shaders/common_view_clipping_lib.glsl33
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl136
-rw-r--r--source/blender/draw/intern/shaders/draw_fullscreen_info.hh8
-rw-r--r--source/blender/draw/intern/shaders/draw_hair_refine_info.hh42
-rw-r--r--source/blender/draw/intern/shaders/draw_object_infos_info.hh6
-rw-r--r--source/blender/draw/intern/shaders/draw_view_info.hh105
-rw-r--r--source/blender/draw/tests/shaders_test.cc2
-rw-r--r--source/blender/editors/animation/drivers.c20
-rw-r--r--source/blender/editors/animation/keyframes_draw.c2
-rw-r--r--source/blender/editors/animation/keyframes_edit.c55
-rw-r--r--source/blender/editors/animation/keyframes_general.c80
-rw-r--r--source/blender/editors/animation/keyframes_keylist.cc3
-rw-r--r--source/blender/editors/animation/keyframes_keylist_test.cc12
-rw-r--r--source/blender/editors/animation/keyframing.c2
-rw-r--r--source/blender/editors/armature/armature_intern.h2
-rw-r--r--source/blender/editors/armature/meshlaplacian.c3
-rw-r--r--source/blender/editors/armature/pose_edit.c2
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_select.c2
-rw-r--r--source/blender/editors/asset/CMakeLists.txt1
-rw-r--r--source/blender/editors/asset/ED_asset_catalog.h2
-rw-r--r--source/blender/editors/asset/ED_asset_mark_clear.h5
-rw-r--r--source/blender/editors/asset/ED_asset_type.h5
-rw-r--r--source/blender/editors/asset/intern/asset_indexer.cc85
-rw-r--r--source/blender/editors/asset/intern/asset_list.cc6
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc8
-rw-r--r--source/blender/editors/asset/intern/asset_temp_id_consumer.cc5
-rw-r--r--source/blender/editors/asset/intern/asset_type.cc2
-rw-r--r--source/blender/editors/curve/curve_intern.h2
-rw-r--r--source/blender/editors/curve/editcurve.c11
-rw-r--r--source/blender/editors/curve/editcurve_add.c6
-rw-r--r--source/blender/editors/geometry/CMakeLists.txt8
-rw-r--r--source/blender/editors/geometry/geometry_attributes.c182
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc385
-rw-r--r--source/blender/editors/geometry/geometry_intern.hh (renamed from source/blender/editors/geometry/geometry_intern.h)7
-rw-r--r--source/blender/editors/geometry/geometry_ops.cc (renamed from source/blender/editors/geometry/geometry_ops.c)5
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_intern.h21
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c14
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c61
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c29
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c13
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h4
-rw-r--r--source/blender/editors/gpencil/gpencil_mesh.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c135
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c60
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_trace.h10
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c12
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c4
-rw-r--r--source/blender/editors/include/BIF_glutil.h146
-rw-r--r--source/blender/editors/include/ED_armature.h26
-rw-r--r--source/blender/editors/include/ED_buttons.h4
-rw-r--r--source/blender/editors/include/ED_curve.h2
-rw-r--r--source/blender/editors/include/ED_file_indexer.h2
-rw-r--r--source/blender/editors/include/ED_fileselect.h8
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h10
-rw-r--r--source/blender/editors/include/ED_gpencil.h42
-rw-r--r--source/blender/editors/include/ED_image.h12
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h43
-rw-r--r--source/blender/editors/include/ED_keyframes_keylist.h27
-rw-r--r--source/blender/editors/include/ED_keyframing.h12
-rw-r--r--source/blender/editors/include/ED_lattice.h2
-rw-r--r--source/blender/editors/include/ED_mask.h29
-rw-r--r--source/blender/editors/include/ED_mesh.h203
-rw-r--r--source/blender/editors/include/ED_node.h29
-rw-r--r--source/blender/editors/include/ED_numinput.h2
-rw-r--r--source/blender/editors/include/ED_object.h59
-rw-r--r--source/blender/editors/include/ED_particle.h9
-rw-r--r--source/blender/editors/include/ED_render.h16
-rw-r--r--source/blender/editors/include/ED_screen.h40
-rw-r--r--source/blender/editors/include/ED_sculpt.h2
-rw-r--r--source/blender/editors/include/ED_select_utils.h16
-rw-r--r--source/blender/editors/include/ED_space_api.h2
-rw-r--r--source/blender/editors/include/ED_transform.h17
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h4
-rw-r--r--source/blender/editors/include/ED_transverts.h2
-rw-r--r--source/blender/editors/include/ED_util.h12
-rw-r--r--source/blender/editors/include/ED_uvedit.h78
-rw-r--r--source/blender/editors/include/ED_view3d.h140
-rw-r--r--source/blender/editors/include/ED_view3d_offscreen.h8
-rw-r--r--source/blender/editors/include/UI_interface.h256
-rw-r--r--source/blender/editors/include/UI_interface.hh6
-rw-r--r--source/blender/editors/include/UI_interface_icons.h29
-rw-r--r--source/blender/editors/include/UI_resources.h2
-rw-r--r--source/blender/editors/include/UI_tree_view.hh2
-rw-r--r--source/blender/editors/include/UI_view2d.h4
-rw-r--r--source/blender/editors/interface/CMakeLists.txt4
-rw-r--r--source/blender/editors/interface/interface.c409
-rw-r--r--source/blender/editors/interface/interface_draw.c55
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c8
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c22
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_intern.h2
-rw-r--r--source/blender/editors/interface/interface_handlers.c112
-rw-r--r--source/blender/editors/interface/interface_icons.c125
-rw-r--r--source/blender/editors/interface/interface_intern.h51
-rw-r--r--source/blender/editors/interface/interface_layout.c5
-rw-r--r--source/blender/editors/interface/interface_ops.c128
-rw-r--r--source/blender/editors/interface/interface_panel.c1
-rw-r--r--source/blender/editors/interface/interface_region_search.cc4
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c15
-rw-r--r--source/blender/editors/interface/interface_style.c23
-rw-r--r--source/blender/editors/interface/interface_template_list.cc1
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.cc3
-rw-r--r--source/blender/editors/interface/interface_templates.c227
-rw-r--r--source/blender/editors/interface/interface_view.cc4
-rw-r--r--source/blender/editors/interface/interface_widgets.c7
-rw-r--r--source/blender/editors/io/CMakeLists.txt4
-rw-r--r--source/blender/editors/io/io_cache.c168
-rw-r--r--source/blender/editors/io/io_cache.h4
-rw-r--r--source/blender/editors/io/io_obj.c369
-rw-r--r--source/blender/editors/io/io_obj.h25
-rw-r--r--source/blender/editors/io/io_ops.c7
-rw-r--r--source/blender/editors/mask/mask_draw.c9
-rw-r--r--source/blender/editors/mask/mask_intern.h12
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c18
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c3
-rw-r--r--source/blender/editors/mesh/editmesh_path.c2
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c28
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c14
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c5
-rw-r--r--source/blender/editors/mesh/mesh_data.c9
-rw-r--r--source/blender/editors/mesh/mesh_intern.h8
-rw-r--r--source/blender/editors/mesh/meshtools.c3
-rw-r--r--source/blender/editors/object/object_add.c21
-rw-r--r--source/blender/editors/object/object_bake.c15
-rw-r--r--source/blender/editors/object/object_bake_api.c38
-rw-r--r--source/blender/editors/object/object_constraint.c8
-rw-r--r--source/blender/editors/object/object_edit.c10
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c15
-rw-r--r--source/blender/editors/object/object_hook.c2
-rw-r--r--source/blender/editors/object/object_intern.h4
-rw-r--r--source/blender/editors/object/object_relations.c7
-rw-r--r--source/blender/editors/object/object_remesh.cc6
-rw-r--r--source/blender/editors/object/object_shapekey.c3
-rw-r--r--source/blender/editors/object/object_transform.c17
-rw-r--r--source/blender/editors/object/object_utils.c2
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c14
-rw-r--r--source/blender/editors/physics/particle_object.c19
-rw-r--r--source/blender/editors/render/CMakeLists.txt17
-rw-r--r--source/blender/editors/render/render_intern.hh (renamed from source/blender/editors/render/render_intern.h)0
-rw-r--r--source/blender/editors/render/render_internal.cc (renamed from source/blender/editors/render/render_internal.c)144
-rw-r--r--source/blender/editors/render/render_opengl.cc (renamed from source/blender/editors/render/render_opengl.c)186
-rw-r--r--source/blender/editors/render/render_ops.cc (renamed from source/blender/editors/render/render_ops.c)6
-rw-r--r--source/blender/editors/render/render_preview.cc (renamed from source/blender/editors/render/render_preview.c)454
-rw-r--r--source/blender/editors/render/render_shading.cc (renamed from source/blender/editors/render/render_shading.c)189
-rw-r--r--source/blender/editors/render/render_update.cc (renamed from source/blender/editors/render/render_update.c)64
-rw-r--r--source/blender/editors/render/render_view.cc (renamed from source/blender/editors/render/render_view.c)52
-rw-r--r--source/blender/editors/screen/area.c4
-rw-r--r--source/blender/editors/screen/glutil.c375
-rw-r--r--source/blender/editors/screen/screen_context.c2
-rw-r--r--source/blender/editors/screen/screen_draw.c4
-rw-r--r--source/blender/editors/screen/screen_intern.h25
-rw-r--r--source/blender/editors/screen/screen_ops.c76
-rw-r--r--source/blender/editors/screen/screendump.c8
-rw-r--r--source/blender/editors/screen/workspace_edit.c2
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt3
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c23
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h79
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c45
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c102
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_proj.c26
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c4045
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brush_types.c2847
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h1685
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c1141
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c45
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/space_action/action_edit.c4
-rw-r--r--source/blender/editors/space_action/space_action.c18
-rw-r--r--source/blender/editors/space_api/spacetypes.c7
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c4
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c68
-rw-r--r--source/blender/editors/space_clip/CMakeLists.txt7
-rw-r--r--source/blender/editors/space_clip/clip_editor.c11
-rw-r--r--source/blender/editors/space_clip/clip_intern.h2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c6
-rw-r--r--source/blender/editors/space_clip/space_clip.c35
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc7
-rw-r--r--source/blender/editors/space_file/file_draw.c32
-rw-r--r--source/blender/editors/space_file/file_intern.h8
-rw-r--r--source/blender/editors/space_file/file_ops.c8
-rw-r--r--source/blender/editors/space_file/filelist.c22
-rw-r--r--source/blender/editors/space_file/filelist.h38
-rw-r--r--source/blender/editors/space_file/filesel.c7
-rw-r--r--source/blender/editors/space_file/fsmenu.c4
-rw-r--r--source/blender/editors/space_file/fsmenu.h2
-rw-r--r--source/blender/editors/space_file/space_file.c14
-rw-r--r--source/blender/editors/space_graph/graph_edit.c97
-rw-r--r--source/blender/editors/space_graph/graph_intern.h16
-rw-r--r--source/blender/editors/space_graph/graph_ops.c3
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c262
-rw-r--r--source/blender/editors/space_graph/space_graph.c18
-rw-r--r--source/blender/editors/space_image/image_draw.c2
-rw-r--r--source/blender/editors/space_image/image_ops.c32
-rw-r--r--source/blender/editors/space_image/image_sequence.c68
-rw-r--r--source/blender/editors/space_image/space_image.c27
-rw-r--r--source/blender/editors/space_info/info_ops.c10
-rw-r--r--source/blender/editors/space_info/info_stats.cc3
-rw-r--r--source/blender/editors/space_info/textview.h2
-rw-r--r--source/blender/editors/space_nla/nla_draw.c2
-rw-r--r--source/blender/editors/space_nla/space_nla.c16
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_node/drawnode.cc2085
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc327
-rw-r--r--source/blender/editors/space_node/node_add.cc140
-rw-r--r--source/blender/editors/space_node/node_context_path.cc4
-rw-r--r--source/blender/editors/space_node/node_draw.cc102
-rw-r--r--source/blender/editors/space_node/node_edit.cc359
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc12
-rw-r--r--source/blender/editors/space_node/node_gizmo.cc12
-rw-r--r--source/blender/editors/space_node/node_group.cc120
-rw-r--r--source/blender/editors/space_node/node_intern.hh92
-rw-r--r--source/blender/editors/space_node/node_ops.cc22
-rw-r--r--source/blender/editors/space_node/node_relationships.cc477
-rw-r--r--source/blender/editors/space_node/node_select.cc125
-rw-r--r--source/blender/editors/space_node/node_templates.cc75
-rw-r--r--source/blender/editors/space_node/node_view.cc12
-rw-r--r--source/blender/editors/space_node/space_node.cc136
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt33
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.cc (renamed from source/blender/editors/space_outliner/outliner_collections.c)260
-rw-r--r--source/blender/editors/space_outliner/outliner_context.cc (renamed from source/blender/editors/space_outliner/outliner_context.c)4
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.cc (renamed from source/blender/editors/space_outliner/outliner_dragdrop.c)233
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc (renamed from source/blender/editors/space_outliner/outliner_draw.c)448
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc (renamed from source/blender/editors/space_outliner/outliner_edit.c)227
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.hh (renamed from source/blender/editors/space_outliner/outliner_intern.h)74
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.cc (renamed from source/blender/editors/space_outliner/outliner_ops.c)2
-rw-r--r--source/blender/editors/space_outliner/outliner_select.cc (renamed from source/blender/editors/space_outliner/outliner_select.c)164
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.cc (renamed from source/blender/editors/space_outliner/outliner_sync.c)31
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc (renamed from source/blender/editors/space_outliner/outliner_tools.c)447
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.cc (renamed from source/blender/editors/space_outliner/outliner_tree.c)427
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.cc (renamed from source/blender/editors/space_outliner/outliner_utils.c)39
-rw-r--r--source/blender/editors/space_outliner/space_outliner.cc (renamed from source/blender/editors/space_outliner/space_outliner.c)142
-rw-r--r--source/blender/editors/space_outliner/tree/common.cc38
-rw-r--r--source/blender/editors/space_outliner/tree/common.hh28
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.cc45
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.h76
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh35
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_data.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_libraries.cc12
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_orphaned.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library.cc10
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_scenes.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_sequencer.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.cc145
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.h48
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.hh51
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_anim_data.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_collection.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_driver.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.cc13
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.hh5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_library.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id_scene.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_nla.cc4
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_rna.cc268
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_rna.hh86
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc6
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_seq.cc111
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_seq.hh60
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_view_layer.cc5
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c63
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c37
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c148
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_proxy.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_thumbnails.c2
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c16
-rw-r--r--source/blender/editors/space_spreadsheet/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc68
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh64
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc43
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.hh2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh60
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_context.cc9
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc438
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_intern.hh4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc170
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.hh2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_panels.cc2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc412
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh8
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc10
-rw-r--r--source/blender/editors/space_text/space_text.c15
-rw-r--r--source/blender/editors/space_text/text_format.h6
-rw-r--r--source/blender/editors/space_text/text_intern.h2
-rw-r--r--source/blender/editors/space_text/text_ops.c2
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c60
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c4
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c77
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c68
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_armature.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h16
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c7
-rw-r--r--source/blender/editors/transform/transform.h6
-rw-r--r--source/blender/editors/transform/transform_convert.c4
-rw-r--r--source/blender/editors/transform/transform_convert.h21
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c2
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c35
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c7
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c9
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_edge.c4
-rw-r--r--source/blender/editors/transform/transform_convert_node.c3
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c5
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c45
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c10
-rw-r--r--source/blender/editors/transform/transform_data.h4
-rw-r--r--source/blender/editors/transform/transform_generics.c5
-rw-r--r--source/blender/editors/transform/transform_gizmo_extrude_3d.c5
-rw-r--r--source/blender/editors/transform/transform_mode.c9
-rw-r--r--source/blender/editors/transform/transform_mode.h9
-rw-r--r--source/blender/editors/transform/transform_mode_edge_crease.c13
-rw-r--r--source/blender/editors/transform/transform_mode_edge_slide.c2
-rw-r--r--source/blender/editors/transform/transform_mode_timetranslate.c15
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c7
-rw-r--r--source/blender/editors/transform/transform_ops.c31
-rw-r--r--source/blender/editors/transform/transform_orientations.c4
-rw-r--r--source/blender/editors/transform/transform_orientations.h8
-rw-r--r--source/blender/editors/transform/transform_snap.c30
-rw-r--r--source/blender/editors/transform/transform_snap.h10
-rw-r--r--source/blender/editors/transform/transform_snap_object.c244
-rw-r--r--source/blender/editors/undo/ed_undo.c123
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/util/ed_draw.c34
-rw-r--r--source/blender/editors/util/ed_transverts.c12
-rw-r--r--source/blender/editors/util/ed_util.c28
-rw-r--r--source/blender/editors/util/ed_util_imbuf.c28
-rw-r--r--source/blender/editors/util/ed_util_ops.cc63
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h20
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c2
-rw-r--r--source/blender/freestyle/CMakeLists.txt5
-rw-r--r--source/blender/freestyle/FRS_precomp.cpp2
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp15
-rw-r--r--source/blender/freestyle/intern/image/GaussianFilter.h4
-rw-r--r--source/blender/freestyle/intern/scene_graph/FrsMaterial.h18
-rw-r--r--source/blender/freestyle/intern/stroke/ChainingIterators.h6
-rw-r--r--source/blender/freestyle/intern/stroke/Curve.h2
-rw-r--r--source/blender/freestyle/intern/stroke/Operators.cpp6
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapIO.h6
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.h4
-rw-r--r--source/blender/freestyle/intern/winged_edge/WXEdge.h2
-rw-r--r--source/blender/functions/FN_field.hh50
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh60
-rw-r--r--source/blender/functions/FN_generic_virtual_vector_array.hh22
-rw-r--r--source/blender/functions/FN_multi_function_procedure.hh13
-rw-r--r--source/blender/functions/intern/cpp_types.cc3
-rw-r--r--source/blender/functions/intern/field.cc209
-rw-r--r--source/blender/functions/intern/multi_function_procedure_optimization.cc2
-rw-r--r--source/blender/geometry/CMakeLists.txt4
-rw-r--r--source/blender/geometry/GEO_mesh_merge_by_distance.hh55
-rw-r--r--source/blender/geometry/GEO_point_merge_by_distance.hh38
-rw-r--r--source/blender/geometry/intern/mesh_merge_by_distance.cc1729
-rw-r--r--source/blender/geometry/intern/mesh_to_curve_convert.cc108
-rw-r--r--source/blender/geometry/intern/point_merge_by_distance.cc183
-rw-r--r--source/blender/geometry/intern/realize_instances.cc2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c15
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h16
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c7
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h14
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c58
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c144
-rw-r--r--source/blender/gpu/CMakeLists.txt478
-rw-r--r--source/blender/gpu/GPU_batch.h3
-rw-r--r--source/blender/gpu/GPU_batch_presets.h4
-rw-r--r--source/blender/gpu/GPU_buffers.h17
-rw-r--r--source/blender/gpu/GPU_context.h2
-rw-r--r--source/blender/gpu/GPU_immediate.h1
-rw-r--r--source/blender/gpu/GPU_immediate_util.h2
-rw-r--r--source/blender/gpu/GPU_index_buffer.h12
-rw-r--r--source/blender/gpu/GPU_material.h10
-rw-r--r--source/blender/gpu/GPU_shader.h82
-rw-r--r--source/blender/gpu/GPU_shader_shared.h84
-rw-r--r--source/blender/gpu/GPU_state.h6
-rw-r--r--source/blender/gpu/GPU_texture.h2
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h7
-rw-r--r--source/blender/gpu/GPU_viewport.h4
-rw-r--r--source/blender/gpu/intern/gpu_backend.hh14
-rw-r--r--source/blender/gpu/intern/gpu_batch_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c3
-rw-r--r--source/blender/gpu/intern/gpu_capabilities_private.hh4
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c2
-rw-r--r--source/blender/gpu/intern/gpu_context.cc9
-rw-r--r--source/blender/gpu/intern/gpu_context_private.hh14
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc2
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer_private.hh8
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc6
-rw-r--r--source/blender/gpu/intern/gpu_immediate_private.hh8
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer.cc19
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer_private.hh10
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c8
-rw-r--r--source/blender/gpu/intern/gpu_material.c6
-rw-r--r--source/blender/gpu/intern/gpu_material_library.c9
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h2
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c5
-rw-r--r--source/blender/gpu/intern/gpu_platform_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_query.hh4
-rw-r--r--source/blender/gpu/intern/gpu_select.c44
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c2
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc208
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder.cc102
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder_stubs.cc258
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c347
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.cc308
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.hh613
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info_private.hh46
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc388
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency_private.h44
-rw-r--r--source/blender/gpu/intern/gpu_shader_info_baked.cc24
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc2
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.hh53
-rw-r--r--source/blender/gpu/intern/gpu_shader_private.hh34
-rw-r--r--source/blender/gpu/intern/gpu_shader_shared_utils.h116
-rw-r--r--source/blender/gpu/intern/gpu_state_private.hh10
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc8
-rw-r--r--source/blender/gpu/intern/gpu_texture_private.hh22
-rw-r--r--source/blender/gpu/intern/gpu_uniform_buffer_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc18
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer_private.hh26
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c6
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc12
-rw-r--r--source/blender/gpu/opengl/gl_backend.hh20
-rw-r--r--source/blender/gpu/opengl/gl_batch.hh8
-rw-r--r--source/blender/gpu/opengl/gl_context.hh16
-rw-r--r--source/blender/gpu/opengl/gl_debug.hh4
-rw-r--r--source/blender/gpu/opengl/gl_drawlist.hh4
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.hh8
-rw-r--r--source/blender/gpu/opengl/gl_immediate.hh10
-rw-r--r--source/blender/gpu/opengl/gl_index_buffer.cc10
-rw-r--r--source/blender/gpu/opengl/gl_index_buffer.hh8
-rw-r--r--source/blender/gpu/opengl/gl_query.hh4
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc518
-rw-r--r--source/blender/gpu/opengl/gl_shader.hh23
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.cc156
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.hh2
-rw-r--r--source/blender/gpu/opengl/gl_state.cc2
-rw-r--r--source/blender/gpu/opengl/gl_state.hh44
-rw-r--r--source/blender/gpu/opengl/gl_texture.hh16
-rw-r--r--source/blender/gpu/opengl/gl_uniform_buffer.hh4
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.hh4
-rw-r--r--source/blender/gpu/opengl/gl_vertex_buffer.cc16
-rw-r--r--source/blender/gpu/opengl/gl_vertex_buffer.hh17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_frag.glsl30
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl38
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl19
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl26
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl44
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl98
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl54
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl28
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_vert.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl15
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl21
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl33
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl11
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_checker_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl138
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl9
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl10
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl18
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl33
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_frag.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_vert.glsl3
-rw-r--r--source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl17
-rw-r--r--source/blender/gpu/shaders/infos/gpu_clip_planes_info.hh (renamed from source/blender/editors/space_node/node_toolbar.cc)24
-rw-r--r--source/blender/gpu/shaders/infos/gpu_interface_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_area_borders_info.hh39
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_checker_info.hh35
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_diag_stripes_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_flat_color_info.hh37
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_color_info.hh30
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh31
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_info.hh39
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh13
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh39
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_rect_color_info.hh37
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh31
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_line_dashed_uniform_color_info.hh34
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_nodelink_info.hh72
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh38
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_point_varying_size_varying_color_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_smooth_color_info.hh36
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_2D_uniform_color_info.hh34
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh37
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh40
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh37
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_line_dashed_uniform_color_info.hh34
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh60
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh32
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh40
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh38
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh50
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh38
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_keyframe_shape_info.hh46
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_simple_lighting_info.hh40
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_text_info.hh45
-rw-r--r--source/blender/gpu/shaders/infos/gpu_srgb_to_framebuffer_space_info.hh27
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl11
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl13
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl8
-rw-r--r--source/blender/gpu/tests/gpu_shader_builtin_test.cc21
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp4
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h24
-rw-r--r--source/blender/imbuf/IMB_imbuf.h46
-rw-r--r--source/blender/imbuf/IMB_metadata.h5
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h22
-rw-r--r--source/blender/imbuf/intern/anim_movie.c143
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.c4
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.cpp22
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.h9
-rw-r--r--source/blender/imbuf/intern/dds/Stream.cpp25
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp9
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.h2
-rw-r--r--source/blender/imbuf/intern/divers.c2
-rw-r--r--source/blender/imbuf/intern/indexer.c134
-rw-r--r--source/blender/imbuf/intern/iris.c4
-rw-r--r--source/blender/imbuf/intern/jp2.c14
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.h2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp8
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h2
-rw-r--r--source/blender/imbuf/intern/radiance_hdr.c31
-rw-r--r--source/blender/imbuf/intern/rotate.c62
-rw-r--r--source/blender/imbuf/intern/tiff.c8
-rw-r--r--source/blender/imbuf/intern/transform.cc24
-rw-r--r--source/blender/io/CMakeLists.txt1
-rw-r--r--source/blender/io/alembic/ABC_alembic.h10
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_hair.cc33
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_mesh.cc62
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc14
-rw-r--r--source/blender/io/alembic/intern/abc_reader_archive.cc49
-rw-r--r--source/blender/io/alembic/intern/abc_reader_archive.h10
-rw-r--r--source/blender/io/alembic/intern/abc_reader_curves.h8
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc121
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.h10
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.cc25
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.h10
-rw-r--r--source/blender/io/alembic/intern/abc_reader_points.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_points.h2
-rw-r--r--source/blender/io/alembic/intern/abc_util.h2
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc22
-rw-r--r--source/blender/io/collada/AnimationImporter.cpp4
-rw-r--r--source/blender/io/collada/AnimationImporter.h2
-rw-r--r--source/blender/io/collada/ArmatureImporter.h2
-rw-r--r--source/blender/io/collada/BCAnimationCurve.h16
-rw-r--r--source/blender/io/collada/BCMath.h18
-rw-r--r--source/blender/io/collada/BCSampleData.h2
-rw-r--r--source/blender/io/collada/GeometryExporter.cpp3
-rw-r--r--source/blender/io/collada/Materials.cpp4
-rw-r--r--source/blender/io/collada/collada_utils.h14
-rw-r--r--source/blender/io/common/IO_abstract_hierarchy_iterator.h2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.cc5
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.hh5
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh9
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.cc2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.hh16
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_import_base.hh2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_import_svg.cc2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_import_svg.hh4
-rw-r--r--source/blender/io/usd/intern/usd_reader_material.cc3
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc61
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.h1
-rw-r--r--source/blender/io/usd/intern/usd_reader_xform.h2
-rw-r--r--source/blender/io/usd/intern/usd_writer_mesh.cc56
-rw-r--r--source/blender/io/usd/usd.h4
-rw-r--r--source/blender/io/wavefront_obj/CMakeLists.txt84
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.cc34
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h97
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc521
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh217
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_io.hh353
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc468
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh226
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc360
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh104
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc105
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh72
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.cc291
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.hh101
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc430
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh149
-rw-r--r--source/blender/makesdna/DNA_ID.h33
-rw-r--r--source/blender/makesdna/DNA_action_types.h2
-rw-r--r--source/blender/makesdna/DNA_anim_types.h2
-rw-r--r--source/blender/makesdna/DNA_armature_types.h4
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h6
-rw-r--r--source/blender/makesdna/DNA_brush_types.h2
-rw-r--r--source/blender/makesdna/DNA_cachefile_types.h19
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h11
-rw-r--r--source/blender/makesdna/DNA_defaults.h4
-rw-r--r--source/blender/makesdna/DNA_genfile.h4
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h3
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h1
-rw-r--r--source/blender/makesdna/DNA_lineart_types.h3
-rw-r--r--source/blender/makesdna/DNA_material_types.h2
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h35
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h6
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h288
-rw-r--r--source/blender/makesdna/DNA_movieclip_defaults.h28
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h10
-rw-r--r--source/blender/makesdna/DNA_nla_types.h4
-rw-r--r--source/blender/makesdna/DNA_node_types.h212
-rw-r--r--source/blender/makesdna/DNA_object_force_types.h2
-rw-r--r--source/blender/makesdna/DNA_object_types.h69
-rw-r--r--source/blender/makesdna/DNA_particle_types.h47
-rw-r--r--source/blender/makesdna/DNA_pointcloud_types.h2
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h16
-rw-r--r--source/blender/makesdna/DNA_scene_defaults.h4
-rw-r--r--source/blender/makesdna/DNA_scene_types.h74
-rw-r--r--source/blender/makesdna/DNA_screen_types.h8
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h71
-rw-r--r--source/blender/makesdna/DNA_shader_fx_types.h2
-rw-r--r--source/blender/makesdna/DNA_simulation_types.h2
-rw-r--r--source/blender/makesdna/DNA_space_defaults.h67
-rw-r--r--source/blender/makesdna/DNA_space_types.h158
-rw-r--r--source/blender/makesdna/DNA_texture_types.h14
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h40
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h24
-rw-r--r--source/blender/makesdna/DNA_view2d_types.h18
-rw-r--r--source/blender/makesdna/DNA_view3d_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h10
-rw-r--r--source/blender/makesdna/DNA_volume_types.h22
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h30
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h4
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt1
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c14
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c2
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h1
-rw-r--r--source/blender/makesdna/intern/dna_utils.h14
-rw-r--r--source/blender/makesrna/RNA_access.h100
-rw-r--r--source/blender/makesrna/RNA_define.h2
-rw-r--r--source/blender/makesrna/RNA_enum_items.h1
-rw-r--r--source/blender/makesrna/RNA_enum_types.h4
-rw-r--r--source/blender/makesrna/RNA_types.h5
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt6
-rw-r--r--source/blender/makesrna/intern/makesrna.c2
-rw-r--r--source/blender/makesrna/intern/rna_ID.c16
-rw-r--r--source/blender/makesrna/intern/rna_access.c8
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c41
-rw-r--r--source/blender/makesrna/intern/rna_action.c4
-rw-r--r--source/blender/makesrna/intern/rna_animviz.c6
-rw-r--r--source/blender/makesrna/intern/rna_armature.c4
-rw-r--r--source/blender/makesrna/intern/rna_armature_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c9
-rw-r--r--source/blender/makesrna/intern/rna_cachefile.c167
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c19
-rw-r--r--source/blender/makesrna/intern/rna_color.c5
-rw-r--r--source/blender/makesrna/intern/rna_curve.c8
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c1
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c3
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c1
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c27
-rw-r--r--source/blender/makesrna/intern/rna_image.c2
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_internal.h30
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h18
-rw-r--r--source/blender/makesrna/intern/rna_layer.c2
-rw-r--r--source/blender/makesrna/intern/rna_light.c2
-rw-r--r--source/blender/makesrna/intern/rna_main.c9
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_mask.c3
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c182
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c11
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c457
-rw-r--r--source/blender/makesrna/intern/rna_object.c4
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c82
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c30
-rw-r--r--source/blender/makesrna/intern/rna_particle.c3
-rw-r--r--source/blender/makesrna/intern/rna_render.c17
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c1
-rw-r--r--source/blender/makesrna/intern/rna_rna.c10
-rw-r--r--source/blender/makesrna/intern/rna_scene.c49
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c2
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c2
-rw-r--r--source/blender/makesrna/intern/rna_space.c15
-rw-r--r--source/blender/makesrna/intern/rna_texture.c2
-rw-r--r--source/blender/makesrna/intern/rna_texture_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c9
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c70
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c35
-rw-r--r--source/blender/makesrna/intern/rna_wm.c2
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c2
-rw-r--r--source/blender/modifiers/CMakeLists.txt3
-rw-r--r--source/blender/modifiers/intern/MOD_array.c44
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.cc11
-rw-r--r--source/blender/modifiers/intern/MOD_build.c4
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c2
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c9
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc66
-rw-r--r--source/blender/modifiers/intern/MOD_mesh_to_volume.cc4
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_util.h53
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c95
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc28
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc170
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c47
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c2
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c6
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c57
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c10
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c91
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c16
-rw-r--r--source/blender/modifiers/intern/MOD_util.c4
-rw-r--r--source/blender/modifiers/intern/MOD_util.h6
-rw-r--r--source/blender/modifiers/intern/MOD_volume_displace.cc7
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c8
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c27
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.h22
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c2081
-rw-r--r--source/blender/modifiers/intern/MOD_weld.cc239
-rw-r--r--source/blender/nodes/CMakeLists.txt163
-rw-r--r--source/blender/nodes/NOD_composite.h71
-rw-r--r--source/blender/nodes/NOD_geometry.h14
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh12
-rw-r--r--source/blender/nodes/NOD_math_functions.hh81
-rw-r--r--source/blender/nodes/NOD_node_declaration.hh97
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh11
-rw-r--r--source/blender/nodes/NOD_shader.h22
-rw-r--r--source/blender/nodes/NOD_socket_declarations.hh44
-rw-r--r--source/blender/nodes/NOD_socket_declarations_geometry.hh3
-rw-r--r--source/blender/nodes/NOD_socket_search_link.hh151
-rw-r--r--source/blender/nodes/NOD_static_types.h17
-rw-r--r--source/blender/nodes/NOD_texture.h16
-rw-r--r--source/blender/nodes/composite/CMakeLists.txt163
-rw-r--r--source/blender/nodes/composite/node_composite_tree.cc71
-rw-r--r--source/blender/nodes/composite/node_composite_util.cc7
-rw-r--r--source/blender/nodes/composite/node_composite_util.hh3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_alpha_over.cc (renamed from source/blender/nodes/composite/nodes/node_composite_alphaOver.cc)29
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_antialiasing.cc34
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc33
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_blur.cc64
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehblur.cc28
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehimage.cc38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_boxmask.cc38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.cc25
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_channelMatte.cc65
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_channel_matte.cc114
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_chroma_matte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc)37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorSpill.cc61
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_color_matte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_colorMatte.cc)38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_color_spill.cc115
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.cc114
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc238
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_common.cc3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_composite.cc21
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc83
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cornerpin.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_crop.cc44
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc90
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_curves.cc53
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_defocus.cc65
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_denoise.cc40
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_despeckle.cc28
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_diff_matte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_diffMatte.cc)32
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_dilate.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_directionalblur.cc44
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_displace.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_distance_matte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc)38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_double_edge_mask.cc (renamed from source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc)29
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_exposure.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_filter.cc20
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_flip.cc19
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_gamma.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_glare.cc60
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc (renamed from source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc)10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_huecorrect.cc14
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_id_mask.cc (renamed from source/blender/nodes/composite/nodes/node_composite_idMask.cc)20
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.cc127
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_inpaint.cc19
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_invert.cc28
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keying.cc40
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc50
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lensdist.cc35
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_levels.cc24
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_luma_matte.cc (renamed from source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc)32
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_map_range.cc (renamed from source/blender/nodes/composite/nodes/node_composite_mapRange.cc)22
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_map_uv.cc (renamed from source/blender/nodes/composite/nodes/node_composite_mapUV.cc)19
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_map_value.cc (renamed from source/blender/nodes/composite/nodes/node_composite_mapValue.cc)41
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mask.cc52
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_math.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mixrgb.cc12
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_movieclip.cc69
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc49
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normal.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normalize.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_output_file.cc (renamed from source/blender/nodes/composite/nodes/node_composite_outputFile.cc)185
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_pixelate.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc73
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_posterize.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_premulkey.cc19
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rgb.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rotate.cc23
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scale.cc38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scene_time.cc39
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc (renamed from source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc)20
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc (renamed from source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc)20
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc (renamed from source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc)28
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc (renamed from source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc)20
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_setalpha.cc25
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_split_viewer.cc (renamed from source/blender/nodes/composite/nodes/node_composite_splitViewer.cc)36
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc43
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sunbeams.cc31
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switch.cc22
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switchview.cc37
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_texture.cc11
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_tonemap.cc44
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_trackpos.cc71
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_transform.cc19
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_translate.cc27
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc (renamed from source/blender/nodes/composite/nodes/node_composite_valToRgb.cc)24
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_value.cc10
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_vec_blur.cc (renamed from source/blender/nodes/composite/nodes/node_composite_vecBlur.cc)38
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_viewer.cc46
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_zcombine.cc27
-rw-r--r--source/blender/nodes/function/CMakeLists.txt75
-rw-r--r--source/blender/nodes/function/node_function_util.cc7
-rw-r--r--source/blender/nodes/function/node_function_util.hh5
-rw-r--r--source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc16
-rw-r--r--source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc22
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc71
-rw-r--r--source/blender/nodes/function/nodes/node_fn_compare.cc99
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_to_int.cc18
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_bool.cc20
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_color.cc20
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_int.cc20
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_special_characters.cc15
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_string.cc24
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_vector.cc21
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_value.cc75
-rw-r--r--source/blender/nodes/function/nodes/node_fn_replace_string.cc14
-rw-r--r--source/blender/nodes/function/nodes/node_fn_rotate_euler.cc19
-rw-r--r--source/blender/nodes/function/nodes/node_fn_slice_string.cc14
-rw-r--r--source/blender/nodes/function/nodes/node_fn_string_length.cc14
-rw-r--r--source/blender/nodes/function/nodes/node_fn_value_to_string.cc14
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt18
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc13
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc32
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh43
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc15
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc9
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc93
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc430
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc50
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_collection_info.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_common.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_length.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc391
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc53
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc79
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc167
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc50
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc75
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc90
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc1365
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc193
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc114
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_image_texture.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc86
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_id.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_index.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc222
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc68
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_normal.cc241
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_position.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_radius.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_replace.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc108
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc142
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc53
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_object_info.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_proximity.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc485
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_components.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc52
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material.cc52
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_join.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc159
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc36
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc65
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc59
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc20
-rw-r--r--source/blender/nodes/intern/derived_node_tree.cc3
-rw-r--r--source/blender/nodes/intern/node_common.cc43
-rw-r--r--source/blender/nodes/intern/node_declaration.cc8
-rw-r--r--source/blender/nodes/intern/node_exec.cc64
-rw-r--r--source/blender/nodes/intern/node_exec.h20
-rw-r--r--source/blender/nodes/intern/node_socket.cc59
-rw-r--r--source/blender/nodes/intern/node_socket_declarations.cc164
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc18
-rw-r--r--source/blender/nodes/intern/node_util.c183
-rw-r--r--source/blender/nodes/intern/socket_search_link.cc199
-rw-r--r--source/blender/nodes/shader/CMakeLists.txt152
-rw-r--r--source/blender/nodes/shader/node_shader_tree.cc (renamed from source/blender/nodes/shader/node_shader_tree.c)288
-rw-r--r--source/blender/nodes/shader/node_shader_util.cc17
-rw-r--r--source/blender/nodes/shader/node_shader_util.hh (renamed from source/blender/nodes/shader/node_shader_util.h)82
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_add_shader.cc (renamed from source/blender/nodes/shader/nodes/node_shader_add_shader.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc (renamed from source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c)50
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.cc (renamed from source/blender/nodes/shader/nodes/node_shader_attribute.c)50
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_background.cc (renamed from source/blender/nodes/shader/nodes/node_shader_background.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bevel.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bevel.c)42
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_blackbody.cc (renamed from source/blender/nodes/shader/nodes/node_shader_blackbody.c)33
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.cc (renamed from source/blender/nodes/shader/nodes/node_shader_brightness.c)36
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c)58
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c)40
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c)45
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c)41
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c)59
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c109
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc145
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c)191
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c)43
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c)53
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c)32
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c)40
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bump.c)56
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_camera.cc (renamed from source/blender/nodes/shader/nodes/node_shader_camera.c)30
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.cc31
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_color_ramp.cc169
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.c266
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.cc130
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc112
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_displacement.cc (renamed from source/blender/nodes/shader/nodes/node_shader_displacement.c)39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc (renamed from source/blender/nodes/shader/nodes/node_shader_eevee_specular.c)86
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_emission.cc (renamed from source/blender/nodes/shader/nodes/node_shader_emission.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_fresnel.cc (renamed from source/blender/nodes/shader/nodes/node_shader_fresnel.c)41
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.c73
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.cc57
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geometry.cc (renamed from source/blender/nodes/shader/nodes/node_shader_geometry.c)48
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hair_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_hair_info.c)39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_holdout.cc (renamed from source/blender/nodes/shader/nodes/node_shader_holdout.c)30
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.c99
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc61
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ies_light.c53
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ies_light.cc74
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_invert.c78
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_invert.cc57
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_layer_weight.cc (renamed from source/blender/nodes/shader/nodes/node_shader_layer_weight.c)44
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_falloff.cc (renamed from source/blender/nodes/shader/nodes/node_shader_light_falloff.c)40
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_path.c62
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_path.cc64
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc117
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c77
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.cc110
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc56
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc45
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_shader.cc (renamed from source/blender/nodes/shader/nodes/node_shader_mix_shader.c)36
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal.cc (renamed from source/blender/nodes/shader/nodes/node_shader_normal.c)55
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.cc (renamed from source/blender/nodes/shader/nodes/node_shader_normal_map.c)76
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_object_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_object_info.c)32
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_aov.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_aov.c)39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_light.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_light.c)25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_linestyle.c44
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc72
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_material.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_material.c)39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_world.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_world.c)28
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_particle_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_particle_info.c)48
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_point_info.cc54
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_rgb.c)25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc195
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_script.c70
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_script.cc112
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c118
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc96
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc68
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_squeeze.c71
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_squeeze.cc58
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc (renamed from source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c)70
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tangent.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tangent.c)62
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.cc51
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.cc26
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_coord.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tex_coord.c)61
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tex_environment.c)38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.cc23
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.cc33
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc46
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.cc47
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c82
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc131
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_sky.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tex_sky.c)87
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc102
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.cc42
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc (renamed from source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c)32
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvmap.cc (renamed from source/blender/nodes/shader/nodes/node_shader_uvmap.c)50
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.cc20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc (renamed from source/blender/nodes/shader/nodes/node_shader_vector_displacement.c)38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.cc72
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc30
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_transform.cc (renamed from source/blender/nodes/shader/nodes/node_shader_vector_transform.c)71
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.cc (renamed from source/blender/nodes/shader/nodes/node_shader_vertex_color.c)57
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_absorption.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_info.c)30
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_principled.c)75
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_scatter.c)40
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wavelength.cc (renamed from source/blender/nodes/shader/nodes/node_shader_wavelength.c)33
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wireframe.cc (renamed from source/blender/nodes/shader/nodes/node_shader_wireframe.c)40
-rw-r--r--source/blender/nodes/texture/CMakeLists.txt89
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c78
-rw-r--r--source/blender/nodes/texture/node_texture_util.c22
-rw-r--r--source/blender/nodes/texture/node_texture_util.h19
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_at.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_bricks.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_checker.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_common.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_compose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_coord.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_curves.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_decompose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_distance.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_hueSatVal.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_image.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_invert.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_math.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_mixRgb.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_output.c6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_proc.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_rotate.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_scale.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_texture.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_translate.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_valToNor.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_valToRgb.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_viewer.c11
-rw-r--r--source/blender/python/BPY_extern.h2
-rw-r--r--source/blender/python/BPY_extern_run.h6
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.h20
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.h6
-rw-r--r--source/blender/python/generic/py_capi_utils.h27
-rw-r--r--source/blender/python/gpu/gpu_py_buffer.h4
-rw-r--r--source/blender/python/gpu/gpu_py_framebuffer.c2
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c29
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_buffer.c2
-rw-r--r--source/blender/python/intern/bpy_capi_utils.h6
-rw-r--r--source/blender/python/intern/bpy_interface_run.c2
-rw-r--r--source/blender/python/intern/bpy_operator.c2
-rw-r--r--source/blender/python/intern/bpy_props.c4
-rw-r--r--source/blender/python/intern/bpy_rna.h7
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c4
-rw-r--r--source/blender/python/intern/bpy_rna_array.c2
-rw-r--r--source/blender/python/intern/bpy_rna_callback.c19
-rw-r--r--source/blender/python/intern/bpy_rna_gizmo.c2
-rw-r--r--source/blender/python/intern/bpy_rna_operator.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.h6
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h16
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.h6
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c2
-rw-r--r--source/blender/render/CMakeLists.txt2
-rw-r--r--source/blender/render/RE_bake.h44
-rw-r--r--source/blender/render/RE_engine.h8
-rw-r--r--source/blender/render/RE_multires_bake.h3
-rw-r--r--source/blender/render/RE_pipeline.h18
-rw-r--r--source/blender/render/RE_texture.h16
-rw-r--r--source/blender/render/RE_texture_margin.h54
-rw-r--r--source/blender/render/intern/bake.c32
-rw-r--r--source/blender/render/intern/engine.c28
-rw-r--r--source/blender/render/intern/multires_bake.c29
-rw-r--r--source/blender/render/intern/pipeline.c10
-rw-r--r--source/blender/render/intern/render_result.c8
-rw-r--r--source/blender/render/intern/render_result.h8
-rw-r--r--source/blender/render/intern/render_types.h2
-rw-r--r--source/blender/render/intern/texture_common.h4
-rw-r--r--source/blender/render/intern/texture_image.c2
-rw-r--r--source/blender/render/intern/texture_margin.cc555
-rw-r--r--source/blender/render/intern/texture_pointdensity.c17
-rw-r--r--source/blender/render/intern/texture_procedural.c8
-rw-r--r--source/blender/render/intern/zbuf.c3
-rw-r--r--source/blender/render/intern/zbuf.h2
-rw-r--r--source/blender/sequencer/CMakeLists.txt2
-rw-r--r--source/blender/sequencer/SEQ_add.h8
-rw-r--r--source/blender/sequencer/SEQ_animation.h41
-rw-r--r--source/blender/sequencer/SEQ_clipboard.h1
-rw-r--r--source/blender/sequencer/SEQ_edit.h8
-rw-r--r--source/blender/sequencer/SEQ_effects.h20
-rw-r--r--source/blender/sequencer/SEQ_iterator.h4
-rw-r--r--source/blender/sequencer/SEQ_proxy.h3
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h8
-rw-r--r--source/blender/sequencer/SEQ_time.h10
-rw-r--r--source/blender/sequencer/SEQ_transform.h6
-rw-r--r--source/blender/sequencer/SEQ_utils.h12
-rw-r--r--source/blender/sequencer/intern/animation.c122
-rw-r--r--source/blender/sequencer/intern/clipboard.c15
-rw-r--r--source/blender/sequencer/intern/effects.c1404
-rw-r--r--source/blender/sequencer/intern/multiview.h6
-rw-r--r--source/blender/sequencer/intern/prefetch.c17
-rw-r--r--source/blender/sequencer/intern/proxy.c13
-rw-r--r--source/blender/sequencer/intern/proxy.h2
-rw-r--r--source/blender/sequencer/intern/render.c56
-rw-r--r--source/blender/sequencer/intern/render.h3
-rw-r--r--source/blender/sequencer/intern/sequencer.c156
-rw-r--r--source/blender/sequencer/intern/sequencer.h8
-rw-r--r--source/blender/sequencer/intern/sound.c9
-rw-r--r--source/blender/sequencer/intern/strip_add.c9
-rw-r--r--source/blender/sequencer/intern/strip_edit.c40
-rw-r--r--source/blender/sequencer/intern/strip_time.c4
-rw-r--r--source/blender/sequencer/intern/strip_time.h2
-rw-r--r--source/blender/sequencer/intern/strip_transform.c1
-rw-r--r--source/blender/sequencer/intern/utils.c7
-rw-r--r--source/blender/sequencer/intern/utils.h2
-rw-r--r--source/blender/simulation/intern/SIM_mass_spring.cpp5
-rw-r--r--source/blender/simulation/intern/hair_volume.cpp6
-rw-r--r--source/blender/simulation/intern/implicit_blender.c2
-rw-r--r--source/blender/windowmanager/WM_api.h45
-rw-r--r--source/blender/windowmanager/WM_keymap.h61
-rw-r--r--source/blender/windowmanager/WM_types.h2
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h21
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h8
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c176
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c28
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c37
-rw-r--r--source/blender/windowmanager/intern/wm_files.c129
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c5
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c2
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c9
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c1
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c3
-rw-r--r--source/blender/windowmanager/intern/wm_window.c7
-rw-r--r--source/blender/windowmanager/message_bus/wm_message_bus.h43
-rw-r--r--source/blender/windowmanager/wm_event_types.h171
-rw-r--r--source/blender/windowmanager/wm_window.h12
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_operators.c2
-rw-r--r--source/creator/CMakeLists.txt10
-rw-r--r--source/creator/blender_launcher_win32.c21
-rw-r--r--source/creator/creator.c5
-rw-r--r--source/creator/creator_args.c1
m---------source/tools0
1977 files changed, 67837 insertions, 38118 deletions
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 0ce2341fc2e..6c2cbb5df33 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -25,6 +25,10 @@ endif()
if(WITH_CLANG_TIDY AND NOT MSVC)
if(NOT CMAKE_C_COMPILER_ID MATCHES "Clang")
message(WARNING "Currently Clang-Tidy might fail with GCC toolchain, switch to Clang toolchain if that happens")
+ if(COMMAND target_precompile_headers)
+ message(STATUS "Clang-Tidy and GCC precompiled headers are incompatible, disabling precompiled headers")
+ set(CMAKE_DISABLE_PRECOMPILE_HEADERS On)
+ endif()
endif()
find_package(ClangTidy REQUIRED)
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index bd1fa4ce4e5..169107b19cb 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -122,9 +122,9 @@ void BLF_draw(int fontid, const char *str, size_t str_len) ATTR_NONNULL(2);
int BLF_draw_mono(int fontid, const char *str, size_t str_len, int cwidth) ATTR_NONNULL(2);
typedef bool (*BLF_GlyphBoundsFn)(const char *str,
- const size_t str_step_ofs,
+ size_t str_step_ofs,
const struct rcti *glyph_step_bounds,
- const int glyph_advance_x,
+ int glyph_advance_x,
const struct rctf *glyph_bounds,
const int glyph_bearing[2],
void *user_data);
@@ -298,9 +298,9 @@ void BLF_dir_free(char **dirs, int count) ATTR_NONNULL();
void BLF_thumb_preview(const char *filename,
const char **draw_str,
const char **i18n_draw_str,
- const unsigned char draw_str_lines,
+ unsigned char draw_str_lines,
const float font_color[4],
- const int font_size,
+ int font_size,
unsigned char *buf,
int w,
int h,
@@ -326,8 +326,8 @@ int BLF_set_default(void);
/* blf_font_default.c */
-int BLF_load_default(const bool unique);
-int BLF_load_mono_default(const bool unique);
+int BLF_load_default(bool unique);
+int BLF_load_mono_default(bool unique);
#ifdef DEBUG
void BLF_state_print(int fontid);
diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt
index cc6e298b322..dd22bc2e7e0 100644
--- a/source/blender/blenfont/CMakeLists.txt
+++ b/source/blender/blenfont/CMakeLists.txt
@@ -54,7 +54,7 @@ set(LIB
bf_gpu
bf_intern_guardedalloc
- ${FREETYPE_LIBRARY}
+ ${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}
)
if(WIN32)
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 02e4a896a31..4e36f522981 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -121,9 +121,9 @@ void blf_font_boundbox_foreach_glyph(struct FontBLF *font,
const char *str,
size_t str_len,
bool (*user_fn)(const char *str,
- const size_t str_step_ofs,
+ size_t str_step_ofs,
const struct rcti *glyph_step_bounds,
- const int glyph_advance_x,
+ int glyph_advance_x,
const struct rctf *glyph_bounds,
const int glyph_bearing[2],
void *user_data),
@@ -132,7 +132,7 @@ void blf_font_boundbox_foreach_glyph(struct FontBLF *font,
int blf_font_count_missing_chars(struct FontBLF *font,
const char *str,
- const size_t str_len,
+ size_t str_len,
int *r_tot_chars);
void blf_font_free(struct FontBLF *font);
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 0fff6d27031..1801c1ee1c9 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -376,7 +376,7 @@ void DM_interp_vert_data(struct DerivedMesh *source,
int count,
int dest_index);
-void mesh_get_mapped_verts_coords(struct Mesh *me_eval, float (*r_cos)[3], const int totcos);
+void mesh_get_mapped_verts_coords(struct Mesh *me_eval, float (*r_cos)[3], int totcos);
/**
* Same as above but won't use render settings.
@@ -390,12 +390,6 @@ struct Mesh *editbmesh_get_eval_cage_from_orig(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *obedit,
const struct CustomData_MeshMasks *dataMask);
-struct Mesh *editbmesh_get_eval_cage_and_final(struct Depsgraph *depsgraph,
- struct Scene *scene,
- struct Object *,
- struct BMEditMesh *em,
- const struct CustomData_MeshMasks *dataMask,
- struct Mesh **r_final);
float (*editbmesh_vert_coords_alloc(struct BMEditMesh *em, int *r_vert_len))[3];
bool editbmesh_modifier_is_enabled(struct Scene *scene,
@@ -405,7 +399,6 @@ bool editbmesh_modifier_is_enabled(struct Scene *scene,
void makeDerivedMesh(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
- struct BMEditMesh *em,
const struct CustomData_MeshMasks *dataMask);
void DM_calc_loop_tangents(DerivedMesh *dm,
@@ -413,14 +406,6 @@ void DM_calc_loop_tangents(DerivedMesh *dm,
const char (*tangent_names)[MAX_NAME],
int tangent_names_len);
-/* debug only */
-#ifndef NDEBUG
-char *DM_debug_info(DerivedMesh *dm);
-void DM_debug_print(DerivedMesh *dm);
-
-bool DM_is_valid(DerivedMesh *dm);
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index ea8ee3f93b1..0b09bfd8730 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -235,9 +235,9 @@ void BKE_pose_free_ex(struct bPose *pose, bool do_id_user);
*/
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);
+ int flag,
+ bool copy_constraints);
+void BKE_pose_copy_data(struct bPose **dst, const struct bPose *src, bool copy_constraints);
/**
* Copy the internal members of each pose channel including constraints
* and ID-Props, used when duplicating bones in edit-mode.
@@ -253,12 +253,28 @@ void BKE_pose_channel_session_uuid_generate(struct bPoseChannel *pchan);
*/
struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name);
/**
+ * Checks if the bone is on a visible armature layer
+ *
+ * \return true if on a visible layer, false otherwise.
+ */
+bool BKE_pose_is_layer_visible(const struct bArmature *arm, const struct bPoseChannel *pchan);
+/**
* Find the active pose-channel for an object
- * (we can't just use pose, as layer info is in armature)
*
- * \note #Object, not #bPose is used here, as we need layer info from Armature.
+ * \param check_arm_layer: checks if the bone is on a visible armature layer (this might be skipped
+ * (e.g. for "Show Active" from the Outliner).
+ * \return #bPoseChannel if found or NULL.
+ * \note #Object, not #bPose is used here, as we need info (layer/active bone) from Armature.
+ */
+struct bPoseChannel *BKE_pose_channel_active(struct Object *ob, bool check_arm_layer);
+/**
+ * Find the active pose-channel for an object if it is on a visible armature layer
+ * (calls #BKE_pose_channel_active with check_arm_layer set to true)
+ *
+ * \return #bPoseChannel if found or NULL.
+ * \note #Object, not #bPose is used here, as we need info (layer/active bone) from Armature.
*/
-struct bPoseChannel *BKE_pose_channel_active(struct Object *ob);
+struct bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob);
/**
* Use this when detecting the "other selected bone",
* when we have multiple armatures in pose mode.
@@ -330,11 +346,11 @@ struct bActionGroup *BKE_pose_add_group(struct bPose *pose, const char *name);
* 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);
+void BKE_pose_remove_group(struct bPose *pose, struct bActionGroup *grp, int 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);
+void BKE_pose_remove_group_index(struct bPose *pose, int index);
/* Assorted Evaluation ----------------- */
diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h
index a65efbd707c..81c49917b63 100644
--- a/source/blender/blenkernel/BKE_anim_data.h
+++ b/source/blender/blenkernel/BKE_anim_data.h
@@ -46,7 +46,7 @@ struct bAction;
/**
* Check if the given ID-block can have AnimData.
*/
-bool id_type_can_have_animdata(const short id_type);
+bool id_type_can_have_animdata(short id_type);
bool id_can_have_animdata(const struct ID *id);
/**
@@ -84,7 +84,7 @@ bool BKE_animdata_action_ensure_idroot(const struct ID *owner, struct bAction *a
/**
* 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);
+void BKE_animdata_free(struct ID *id, bool do_id_user);
/**
* Return true if the ID-block has non-empty AnimData.
@@ -103,26 +103,21 @@ void BKE_animdata_foreach_id(struct AnimData *adt, struct LibraryForeachIDData *
* 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);
+struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, int flag);
/**
* \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);
+bool BKE_animdata_copy_id(struct Main *bmain, struct ID *id_to, struct ID *id_from, int flag);
/**
* Copy AnimData Actions.
*/
void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id);
-void BKE_animdata_duplicate_id_action(struct Main *bmain,
- struct ID *id,
- const uint duplicate_flags);
+void BKE_animdata_duplicate_id_action(struct Main *bmain, struct ID *id, uint duplicate_flags);
/* Merge copies of data from source AnimData block */
typedef enum eAnimData_MergeCopy_Modes {
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 6197cb93c95..4845807de39 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -121,7 +121,15 @@ void BKE_keyingsets_blend_read_expand(struct BlendExpander *expander, struct Lis
/* ************************************* */
/* Path Fixing API */
-/* Get a "fixed" version of the given path (oldPath) */
+/**
+ * Get a "fixed" version of the given path `old_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(struct ID *owner_id,
char *old_path,
const char *prefix,
@@ -131,7 +139,15 @@ char *BKE_animsys_fix_rna_path_rename(struct ID *owner_id,
int newSubscript,
bool verify_paths);
-/* Fix all the paths for the given ID + Action */
+/**
+ * Fix all the paths for the given ID + Action.
+ *
+ * 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(struct ID *owner_id,
struct bAction *act,
const char *prefix,
@@ -141,7 +157,12 @@ void BKE_action_fix_paths_rename(struct ID *owner_id,
int newSubscript,
bool verify_paths);
-/* Fix all the paths for the given ID+AnimData */
+/**
+ * Fix all the paths for the given ID+AnimData
+ *
+ * \note it is assumed that the structure we're replacing is `<prefix><["><name><"]>`
+ * i.e. `pose.bones["Bone"]`.
+ */
void BKE_animdata_fix_paths_rename(struct ID *owner_id,
struct AnimData *adt,
struct ID *ref_id,
@@ -152,24 +173,31 @@ void BKE_animdata_fix_paths_rename(struct ID *owner_id,
int newSubscript,
bool verify_paths);
-/* Fix all the paths for the entire database... */
-void BKE_animdata_fix_paths_rename_all(struct ID *ref_id,
- const char *prefix,
- const char *oldName,
- const char *newName);
-
-/* Fix all the paths for the entire bmain with extra parameters. */
+/**
+ * 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_ex(struct Main *bmain,
struct ID *ref_id,
const char *prefix,
const char *oldName,
const char *newName,
- const int oldSubscript,
- const int newSubscript,
- const bool verify_paths);
+ int oldSubscript,
+ int newSubscript,
+ bool verify_paths);
+
+/** See #BKE_animdata_fix_paths_rename_all_ex */
+void BKE_animdata_fix_paths_rename_all(struct ID *ref_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName);
-/* Fix the path after removing elements that are not ID (e.g., node).
- * Return true if any animation data was affected. */
+/**
+ * Fix the path after removing elements that are not ID (e.g., node).
+ * Return true if any animation data was affected.
+ */
bool BKE_animdata_fix_paths_remove(struct ID *id, const char *path);
/* -------------------------------------- */
@@ -180,17 +208,19 @@ typedef struct AnimationBasePathChange {
const char *dst_basepath;
} AnimationBasePathChange;
-/* Move animation data from src to destination if its paths are based on basepaths */
+/**
+ * Move animation data from source to destination if its paths are based on `basepaths`.
+ *
+ * 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.
+ *
+ * \param basepaths: A list of #AnimationBasePathChange.
+ */
void BKE_animdata_transfer_by_basepath(struct Main *bmain,
struct ID *srcID,
struct ID *dstID,
struct ListBase *basepaths);
-char *BKE_animdata_driver_path_hack(struct bContext *C,
- struct PointerRNA *ptr,
- struct PropertyRNA *prop,
- char *base_path);
-
/* ************************************* */
/* Batch AnimData API */
@@ -203,7 +233,7 @@ typedef void (*ID_FCurve_Edit_Callback)(struct ID *id, struct FCurve *fcu, void
/* Loop over all datablocks applying callback */
void BKE_animdata_main_cb(struct Main *bmain, ID_AnimData_Edit_Callback func, void *user_data);
-/* Loop over all datablocks applying callback to all its F-Curves */
+/** Apply the given callback function on all F-Curves attached to data in `main` database. */
void BKE_fcurves_main_cb(struct Main *bmain, ID_FCurve_Edit_Callback func, void *user_data);
/* Look over all f-curves of a given ID. */
@@ -269,13 +299,13 @@ typedef enum eAnimData_Recalc {
bool BKE_animsys_rna_path_resolve(struct PointerRNA *ptr,
const char *rna_path,
- const int array_index,
+ 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);
+bool BKE_animsys_write_to_rna_path(struct PathResolvedRNA *anim_rna, float value);
/**
* Evaluation loop for evaluation animation data
@@ -288,7 +318,7 @@ 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);
+ bool flush_to_original);
/**
* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index dd589282bdd..a7baaed141f 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -88,26 +88,21 @@ bool BKE_appdir_folder_caches(char *r_path, size_t path_len);
* 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);
+bool BKE_appdir_folder_id_ex(int folder_id, const char *subfolder, char *path, size_t path_len);
+const char *BKE_appdir_folder_id(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);
+const char *BKE_appdir_folder_id_create(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);
+const char *BKE_appdir_folder_id_user_notest(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);
+const char *BKE_appdir_folder_id_version(int folder_id, int version, bool check_is_dir);
/**
* Check if this is an install with user files kept together
@@ -145,9 +140,9 @@ bool BKE_appdir_font_folder_default(char *dir);
* Find Python executable.
*/
bool BKE_appdir_program_python_search(char *fullpath,
- const size_t fullpath_len,
- const int version_major,
- const int version_minor);
+ size_t fullpath_len,
+ int version_major,
+ int version_minor);
/**
* Initialize path to temporary directory.
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index fcba7d9d365..8584ce6f508 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -152,13 +152,13 @@ typedef struct PoseTree {
struct bArmature *BKE_armature_add(struct Main *bmain, const char *name);
struct bArmature *BKE_armature_from_object(struct Object *ob);
int BKE_armature_bonelist_count(const struct ListBase *lb);
-void BKE_armature_bonelist_free(struct ListBase *lb, const bool do_id_user);
-void BKE_armature_editbonelist_free(struct ListBase *lb, const bool do_id_user);
+void BKE_armature_bonelist_free(struct ListBase *lb, bool do_id_user);
+void BKE_armature_editbonelist_free(struct ListBase *lb, bool do_id_user);
void BKE_armature_copy_bone_transforms(struct bArmature *armature_dst,
const struct bArmature *armature_src);
-void BKE_armature_transform(struct bArmature *arm, const float mat[4][4], const bool do_props);
+void BKE_armature_transform(struct bArmature *arm, const float mat[4][4], bool do_props);
/* Bounding box. */
struct BoundBox *BKE_armature_boundbox_get(struct Object *ob);
@@ -206,7 +206,7 @@ void BKE_armature_where_is(struct bArmature *arm);
*/
void BKE_armature_where_is_bone(struct Bone *bone,
const struct Bone *bone_parent,
- const bool use_recursion);
+ bool use_recursion);
/**
* Clear pointers of object's pose
* (needed in remap case, since we cannot always wait for a complete pose rebuild).
@@ -217,7 +217,7 @@ 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);
+void BKE_pose_channels_clear_with_null_bone(struct bPose *pose, bool do_id_user);
/**
* Only after leave edit-mode, duplicating, validating older files, library syncing.
*
@@ -228,7 +228,7 @@ void BKE_pose_channels_clear_with_null_bone(struct bPose *pose, const bool do_id
void BKE_pose_rebuild(struct Main *bmain,
struct Object *ob,
struct bArmature *arm,
- const bool do_id_user);
+ bool do_id_user);
/**
* Ensures object's pose is rebuilt if needed.
*
@@ -237,7 +237,7 @@ void BKE_pose_rebuild(struct Main *bmain,
void BKE_pose_ensure(struct Main *bmain,
struct Object *ob,
struct bArmature *arm,
- const bool do_id_user);
+ bool do_id_user);
/**
* \note This is the only function adding poses.
* \note This only reads anim data from channels, and writes to channels.
@@ -279,12 +279,12 @@ void BKE_pose_apply_action_blend(struct Object *ob,
struct AnimationEvalContext *anim_eval_context,
float blend_factor);
-void vec_roll_to_mat3(const float vec[3], const float roll, float r_mat[3][3]);
+void vec_roll_to_mat3(const float vec[3], 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]);
+void vec_roll_to_mat3_normalized(const float nor[3], float roll, float r_mat[3][3]);
/**
* Computes vector and roll based on a rotation.
* "mat" must contain only a rotation, and no scaling.
@@ -484,7 +484,7 @@ void BKE_pchan_bbone_handles_get(struct bPoseChannel *pchan,
* Compute B-Bone spline parameters for the given channel.
*/
void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
- const bool rest,
+ bool rest,
struct BBoneSplineParameters *r_param);
/**
@@ -492,8 +492,8 @@ void BKE_pchan_bbone_spline_params_get(struct bPoseChannel *pchan,
* This calculation is done within unit bone space.
*/
void BKE_pchan_bbone_spline_setup(struct bPoseChannel *pchan,
- const bool rest,
- const bool for_deform,
+ bool rest,
+ bool for_deform,
Mat4 *result_array);
/**
@@ -511,7 +511,7 @@ void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param,
* This calculation is done within unit bone space.
*/
int BKE_pchan_bbone_spline_compute(struct BBoneSplineParameters *param,
- const bool for_deform,
+ bool for_deform,
Mat4 *result_array);
/**
diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh
index ecc839050b7..004b70c2925 100644
--- a/source/blender/blenkernel/BKE_asset_catalog.hh
+++ b/source/blender/blenkernel/BKE_asset_catalog.hh
@@ -141,7 +141,7 @@ class AssetCatalogService {
AssetCatalogFilter create_catalog_filter(CatalogID active_catalog_id) const;
/** Create a catalog with some sensible auto-generated catalog ID.
- * The catalog will be saved to the default catalog file.*/
+ * The catalog will be saved to the default catalog file. */
AssetCatalog *create_catalog(const AssetCatalogPath &catalog_path);
/**
diff --git a/source/blender/blenkernel/BKE_asset_library.hh b/source/blender/blenkernel/BKE_asset_library.hh
index 15f7991e75e..37e2ad38a29 100644
--- a/source/blender/blenkernel/BKE_asset_library.hh
+++ b/source/blender/blenkernel/BKE_asset_library.hh
@@ -63,7 +63,7 @@ struct AssetLibrary {
void on_blend_save_handler_register();
void on_blend_save_handler_unregister();
- void on_blend_save_post(struct Main *, struct PointerRNA **pointers, const int num_pointers);
+ void on_blend_save_post(struct Main *, struct PointerRNA **pointers, int num_pointers);
private:
bCallbackFuncStore on_save_callback_store_{};
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index 2c83bef7517..6020da08f51 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -38,10 +38,6 @@ struct ID;
struct ReportList;
/* Attribute.domain */
-/**
- * \warning Careful when changing existing items.
- * Arrays may be initialized from this (e.g. #DATASET_layout_hierarchy).
- */
typedef enum AttributeDomain {
ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */
@@ -58,19 +54,16 @@ typedef enum AttributeDomain {
bool BKE_id_attributes_supported(struct ID *id);
-struct CustomDataLayer *BKE_id_attribute_new(struct ID *id,
- const char *name,
- const int type,
- const AttributeDomain domain,
- struct ReportList *reports);
+struct CustomDataLayer *BKE_id_attribute_new(
+ struct ID *id, const char *name, int type, AttributeDomain domain, struct ReportList *reports);
bool BKE_id_attribute_remove(struct ID *id,
struct CustomDataLayer *layer,
struct ReportList *reports);
struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
const char *name,
- const int type,
- const AttributeDomain domain);
+ int type,
+ AttributeDomain domain);
AttributeDomain BKE_id_attribute_domain(struct ID *id, struct CustomDataLayer *layer);
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
@@ -80,7 +73,7 @@ bool BKE_id_attribute_rename(struct ID *id,
const char *new_name,
struct ReportList *reports);
-int BKE_id_attributes_length(struct ID *id, const CustomDataMask mask);
+int BKE_id_attributes_length(struct ID *id, CustomDataMask mask);
struct CustomDataLayer *BKE_id_attributes_active_get(struct ID *id);
void BKE_id_attributes_active_set(struct ID *id, struct CustomDataLayer *layer);
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index fd30813a506..3ffdcee05eb 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -26,9 +26,41 @@
#include "BKE_attribute.h"
#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_function_ref.hh"
+#include "BLI_math_vec_types.hh"
+
+/**
+ * This file defines classes that help to provide access to attribute data on a #GeometryComponent.
+ * The API for retrieving attributes is defined in `BKE_geometry_set.hh`, but this comment has some
+ * general comments about the system.
+ *
+ * Attributes are stored in geometry data, though they can also be stored in instances. Their
+ * storage is often tied to `CustomData`, which is a system to store "layers" of data with specific
+ * types and names. However, since `CustomData` was added to Blender before attributes were
+ * conceptualized, it combines the "legacy" style of task-specific attribute types with generic
+ * types like "Float". The attribute API here only provides access to generic types.
+ *
+ * Attributes are retrieved from geometry components by providing an "id" (#AttributeIDRef). This
+ * is most commonly just an attribute name. The attribute API on geometry components has some more
+ * advanced capabilities:
+ * 1. Read-only access: With a `const` geometry component, an attribute on the geometry cannot be
+ * modified, so the `for_write` and `for_output` versions of the API are not available. This is
+ * extremely important for writing coherent bug-free code. When an attribute is retrieved with
+ * write access, via #WriteAttributeLookup or #OutputAttribute, the geometry component must be
+ * tagged to clear caches that depend on the changed data.
+ * 2. Domain interpolation: When retrieving an attribute, a domain (#AttributeDomain) can be
+ * provided. If the attribute is stored on a different domain and conversion is possible, a
+ * version of the data interpolated to the requested domain will be provided. These conversions
+ * are implemented in each #GeometryComponent by `attribute_try_adapt_domain_impl`.
+ * 3. Implicit type conversion: In addition to interpolating domains, attribute types can be
+ * converted, using the conversions in `BKE_type_conversions.hh`. The #VArray / #GVArray system
+ * makes it possible to only convert necessary indices on-demand.
+ * 4. Anonymous attributes: The "id" used to look up an attribute can also be an anonymous
+ * attribute reference. Currently anonymous attributes are only used in geometry nodes.
+ * 5. Abstracted storage: Since the data returned from the API is usually a virtual array,
+ * it doesn't have to be stored contiguously (even though that is generally preferred). This
+ * allows accessing "legacy" attributes like `material_index`, which is stored in `MPoly`.
+ */
namespace blender::bke {
@@ -181,11 +213,14 @@ struct ReadAttributeLookup {
* Used when looking up a "plain attribute" based on a name for reading from it and writing to it.
*/
struct WriteAttributeLookup {
- /* The virtual array that is used to read from and write to the attribute. */
+ /** The virtual array that is used to read from and write to the attribute. */
GVMutableArray varray;
- /* Domain the attributes lives on in the geometry. */
+ /** Domain the attributes lives on in the geometry component. */
AttributeDomain domain;
- /* Call this after changing the attribute to invalidate caches that depend on this attribute. */
+ /**
+ * Call this after changing the attribute to invalidate caches that depend on this attribute.
+ * \note Do not call this after the component the attribute is from has been destructed.
+ */
std::function<void()> tag_modified_fn;
/* Convenience function to check if the attribute has been found. */
@@ -205,6 +240,10 @@ struct WriteAttributeLookup {
* VMutableArray_Span in many cases).
* - An output attribute can live side by side with an existing attribute with a different domain
* or data type. The old attribute will only be overwritten when the #save function is called.
+ *
+ * \note The lifetime of an output attribute should not be longer than the the lifetime of the
+ * geometry component it comes from, since it can keep a reference to the component for use in
+ * the #save method.
*/
class OutputAttribute {
public:
@@ -224,7 +263,7 @@ class OutputAttribute {
OutputAttribute(GVMutableArray varray,
AttributeDomain domain,
SaveFn save,
- const bool ignore_old_values);
+ bool ignore_old_values);
~OutputAttribute();
@@ -347,7 +386,7 @@ class CustomDataAttributes {
CustomDataAttributes(CustomDataAttributes &&other);
CustomDataAttributes &operator=(const CustomDataAttributes &other);
- void reallocate(const int size);
+ void reallocate(int size);
void clear();
@@ -383,8 +422,7 @@ class CustomDataAttributes {
*/
void reorder(Span<AttributeIDRef> new_order);
- bool foreach_attribute(const AttributeForeachCallback callback,
- const AttributeDomain domain) const;
+ bool foreach_attribute(const AttributeForeachCallback callback, AttributeDomain domain) const;
};
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh
index 2ce41e95b65..90f349125c9 100644
--- a/source/blender/blenkernel/BKE_attribute_math.hh
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -18,8 +18,7 @@
#include "BLI_array.hh"
#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "DNA_customdata_types.h"
@@ -141,7 +140,7 @@ inline ColorGeometry4f mix3(const float3 &weights,
* This is just basic linear interpolation.
* \{ */
-template<typename T> T mix2(const float factor, const T &a, const T &b);
+template<typename T> T mix2(float factor, const T &a, const T &b);
template<> inline bool mix2(const float factor, const bool &a, const bool &b)
{
@@ -160,12 +159,12 @@ template<> inline float mix2(const float factor, const float &a, const float &b)
template<> inline float2 mix2(const float factor, const float2 &a, const float2 &b)
{
- return float2::interpolate(a, b, factor);
+ return math::interpolate(a, b, factor);
}
template<> inline float3 mix2(const float factor, const float3 &a, const float3 &b)
{
- return float3::interpolate(a, b, factor);
+ return math::interpolate(a, b, factor);
}
template<>
@@ -232,6 +231,43 @@ template<typename T> class SimpleMixer {
};
/**
+ * Mixes together booleans with "or" while fitting the same interface as the other
+ * mixers in order to be simpler to use. This mixing method has a few benefits:
+ * - An "average" for selections is relatively meaningless.
+ * - Predictable selection propagation is very super important.
+ * - It's generally easier to remove an element from a selection that is slightly too large than
+ * the opposite.
+ */
+class BooleanPropagationMixer {
+ private:
+ MutableSpan<bool> buffer_;
+
+ public:
+ /**
+ * \param buffer: Span where the interpolated values should be stored.
+ */
+ BooleanPropagationMixer(MutableSpan<bool> buffer) : buffer_(buffer)
+ {
+ buffer_.fill(false);
+ }
+
+ /**
+ * Mix a #value into the element with the given #index.
+ */
+ void mix_in(const int64_t index, const bool value, [[maybe_unused]] const float weight = 1.0f)
+ {
+ buffer_[index] |= value;
+ }
+
+ /**
+ * Does not do anything, since the mixing is trivial.
+ */
+ void finalize()
+ {
+ }
+};
+
+/**
* This mixer accumulates values in a type that is different from the one that is mixed.
* Some types cannot encode the floating point weights in their values (e.g. int and bool).
*/
@@ -287,12 +323,12 @@ class ColorGeometryMixer {
public:
ColorGeometryMixer(MutableSpan<ColorGeometry4f> buffer,
ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
- void mix_in(const int64_t index, const ColorGeometry4f &color, const float weight = 1.0f);
+ void mix_in(int64_t index, const ColorGeometry4f &color, float weight = 1.0f);
void finalize();
};
template<typename T> struct DefaultMixerStruct {
- /* Use void by default. This can be check for in `if constexpr` statements. */
+ /* Use void by default. This can be checked for in `if constexpr` statements. */
using type = void;
};
template<> struct DefaultMixerStruct<float> {
@@ -328,6 +364,23 @@ template<> struct DefaultMixerStruct<bool> {
using type = SimpleMixerWithAccumulationType<bool, float, float_to_bool>;
};
+template<typename T> struct DefaultPropatationMixerStruct {
+ /* Use void by default. This can be checked for in `if constexpr` statements. */
+ using type = typename DefaultMixerStruct<T>::type;
+};
+
+template<> struct DefaultPropatationMixerStruct<bool> {
+ using type = BooleanPropagationMixer;
+};
+
+/**
+ * This mixer is meant for propagating attributes when creating new geometry. A key difference
+ * with the default mixer is that booleans are mixed with "or" instead of "at least half"
+ * (the default mixing for booleans).
+ */
+template<typename T>
+using DefaultPropatationMixer = typename DefaultPropatationMixerStruct<T>::type;
+
/* Utility to get a good default mixer for a given type. This is `void` when there is no default
* mixer for the given type. */
template<typename T> using DefaultMixer = typename DefaultMixerStruct<T>::type;
diff --git a/source/blender/blenkernel/BKE_blender_copybuffer.h b/source/blender/blenkernel/BKE_blender_copybuffer.h
index abfb37ef959..d1faf88a90c 100644
--- a/source/blender/blenkernel/BKE_blender_copybuffer.h
+++ b/source/blender/blenkernel/BKE_blender_copybuffer.h
@@ -63,7 +63,7 @@ bool BKE_copybuffer_copy_end(struct Main *bmain_src,
bool BKE_copybuffer_read(struct Main *bmain_dst,
const char *libname,
struct ReportList *reports,
- const uint64_t id_types_mask);
+ uint64_t id_types_mask);
/**
* Paste data-blocks from the given .blend file 'buffer' (i.e. append them).
*
@@ -80,9 +80,9 @@ bool BKE_copybuffer_read(struct Main *bmain_dst,
*/
int BKE_copybuffer_paste(struct bContext *C,
const char *libname,
- const int flag,
+ int flag,
struct ReportList *reports,
- const uint64_t id_types_mask);
+ uint64_t id_types_mask);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h
index 1febe75b6f2..d60d048ee5f 100644
--- a/source/blender/blenkernel/BKE_blender_undo.h
+++ b/source/blender/blenkernel/BKE_blender_undo.h
@@ -34,8 +34,8 @@ enum eUndoStepDir;
struct MemFileUndoData *BKE_memfile_undo_encode(struct Main *bmain,
struct MemFileUndoData *mfu_prev);
bool BKE_memfile_undo_decode(struct MemFileUndoData *mfu,
- const enum eUndoStepDir undo_direction,
- const bool use_old_bmain_data,
+ enum eUndoStepDir undo_direction,
+ bool use_old_bmain_data,
struct bContext *C);
void BKE_memfile_undo_free(struct MemFileUndoData *mfu);
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index b3211b1dbbc..db86d4685b7 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -46,7 +46,7 @@ void BKE_blendfile_read_setup_ex(struct bContext *C,
const struct BlendFileReadParams *params,
struct BlendFileReadReport *reports,
/* Extra args. */
- const bool startup_update_defaults,
+ bool startup_update_defaults,
const char *startup_app_template);
void BKE_blendfile_read_setup(struct bContext *C,
@@ -127,8 +127,8 @@ void BKE_blendfile_write_partial_begin(struct Main *bmain_src);
*/
bool BKE_blendfile_write_partial(struct Main *bmain_src,
const char *filepath,
- const int write_flags,
- const int remap_mode,
+ int write_flags,
+ int remap_mode,
struct ReportList *reports);
void BKE_blendfile_write_partial_end(struct Main *bmain_src);
diff --git a/source/blender/blenkernel/BKE_blendfile_link_append.h b/source/blender/blenkernel/BKE_blendfile_link_append.h
index aaa31352316..983c93223a1 100644
--- a/source/blender/blenkernel/BKE_blendfile_link_append.h
+++ b/source/blender/blenkernel/BKE_blendfile_link_append.h
@@ -30,8 +30,8 @@ struct LibraryLink_Params;
struct Main;
struct ReportList;
struct Scene;
-struct ViewLayer;
struct View3D;
+struct ViewLayer;
typedef struct BlendfileLinkAppendContext BlendfileLinkAppendContext;
typedef struct BlendfileLinkAppendContextItem BlendfileLinkAppendContextItem;
@@ -54,8 +54,8 @@ void BKE_blendfile_link_append_context_free(struct BlendfileLinkAppendContext *l
* \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);
+ int flag,
+ bool do_set);
/**
* Store reference to a Blender's embedded memfile into the context.
@@ -98,7 +98,7 @@ void BKE_blendfile_link_append_context_library_add(struct BlendfileLinkAppendCon
struct BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add(
struct BlendfileLinkAppendContext *lapp_context,
const char *idname,
- const short idcode,
+ short idcode,
void *userdata);
#define BLENDFILE_LINK_APPEND_INVALID -1
@@ -119,8 +119,8 @@ struct BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_ad
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);
+ uint64_t id_types_filter,
+ int library_index);
/**
* Enable search of the given \a item into the library stored at given index in the link/append
@@ -129,7 +129,7 @@ int BKE_blendfile_link_append_context_item_idtypes_from_library_add(
void BKE_blendfile_link_append_context_item_library_index_enable(
struct BlendfileLinkAppendContext *lapp_context,
struct BlendfileLinkAppendContextItem *item,
- const int library_index);
+ int library_index);
/**
* Check if given link/append context is empty (has no items to process) or not.
*/
@@ -150,7 +150,7 @@ typedef enum eBlendfileLinkAppendForeachItemFlag {
*
* 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,
+ BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT = 1 << 1,
} eBlendfileLinkAppendForeachItemFlag;
/**
* Callback called by #BKE_blendfile_link_append_context_item_foreach over each (or a subset of
@@ -175,7 +175,7 @@ typedef bool (*BKE_BlendfileLinkAppendContexteItemFunction)(
void BKE_blendfile_link_append_context_item_foreach(
struct BlendfileLinkAppendContext *lapp_context,
BKE_BlendfileLinkAppendContexteItemFunction callback_function,
- const eBlendfileLinkAppendForeachItemFlag flag,
+ eBlendfileLinkAppendForeachItemFlag flag,
void *userdata);
/**
@@ -215,7 +215,7 @@ void BKE_blendfile_link(struct BlendfileLinkAppendContext *lapp_context,
void BKE_blendfile_library_relocate(struct BlendfileLinkAppendContext *lapp_context,
struct ReportList *reports,
struct Library *library,
- const bool do_reload);
+ bool do_reload);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h
index bae151f6a72..ccbd0d4cbe4 100644
--- a/source/blender/blenkernel/BKE_bpath.h
+++ b/source/blender/blenkernel/BKE_bpath.h
@@ -49,6 +49,8 @@ typedef enum eBPathForeachFlag {
BKE_BPATH_FOREACH_PATH_SKIP_LINKED = (1 << 1),
/** Skip paths when their matching data is packed. */
BKE_BPATH_FOREACH_PATH_SKIP_PACKED = (1 << 2),
+ /** Resolve tokens within a virtual filepath to a single, concrete, filepath. */
+ BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN = (1 << 3),
/* Skip weak reference paths. Those paths are typically 'nice to have' extra information, but are
* not used as actual source of data by the current .blend file.
*
@@ -169,7 +171,7 @@ void BKE_bpath_missing_files_check(struct Main *bmain, struct ReportList *report
void BKE_bpath_missing_files_find(struct Main *bmain,
const char *searchpath,
struct ReportList *reports,
- const bool find_all);
+ 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,
@@ -191,16 +193,14 @@ void BKE_bpath_absolute_convert(struct Main *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);
+void *BKE_bpath_list_backup(struct Main *bmain, 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);
+void BKE_bpath_list_restore(struct Main *bmain, eBPathForeachFlag flag, void *path_list_handle);
/** Free the temp backup of paths in \a path_list_handle.
*
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index a0f3733588a..ee5ab905d70 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -50,7 +50,7 @@ void BKE_brush_system_exit(void);
* \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);
+struct Brush *BKE_brush_add(struct Main *bmain, const char *name, eObjectMode ob_mode);
/**
* Add a new gp-brush.
*/
@@ -66,35 +66,27 @@ 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);
+struct Brush *BKE_brush_first_search(struct Main *bmain, 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);
+void BKE_brush_gpencil_paint_presets(struct Main *bmain, struct ToolSettings *ts, 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);
+void BKE_brush_gpencil_vertex_presets(struct Main *bmain, struct ToolSettings *ts, 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);
+void BKE_brush_gpencil_sculpt_presets(struct Main *bmain, struct ToolSettings *ts, 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);
+void BKE_brush_gpencil_weight_presets(struct Main *bmain, struct ToolSettings *ts, bool reset);
+void BKE_gpencil_brush_preset_set(struct Main *bmain, struct Brush *brush, short type);
void BKE_brush_jitter_pos(const struct Scene *scene,
struct Brush *brush,
@@ -111,11 +103,11 @@ void BKE_brush_curve_preset(struct Brush *b, enum eCurveMappingPreset preset);
/**
* 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);
+float BKE_brush_curve_strength_clamped(const struct Brush *br, float p, 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);
+float BKE_brush_curve_strength(const struct Brush *br, float p, float len);
/* Sampling. */
@@ -130,12 +122,12 @@ float BKE_brush_sample_tex_3d(const struct Scene *scene,
const struct Brush *br,
const float point[3],
float rgba[4],
- const int thread,
+ int thread,
struct ImagePool *pool);
float BKE_brush_sample_masktex(const struct Scene *scene,
struct Brush *br,
const float point[2],
- const int thread,
+ int thread,
struct ImagePool *pool);
/* Texture. */
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 45c3a8ec159..c454e441551 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -71,6 +71,7 @@ typedef struct BVHTreeFromMesh {
/* Vertex array, so that callbacks have instant access to data. */
const struct MVert *vert;
+ const float (*vert_normals)[3];
const struct MEdge *edge; /* only used for #BVHTreeFromMeshEdges */
const struct MFace *face;
const struct MLoop *loop;
@@ -128,7 +129,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
@@ -141,14 +142,14 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
*/
BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
- const int verts_num,
- const bool vert_allocated,
+ int verts_num,
+ bool vert_allocated,
const BLI_bitmap *verts_mask,
int verts_num_active,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
@@ -165,7 +166,7 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
@@ -179,16 +180,16 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
*/
BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
- const bool vert_allocated,
+ bool vert_allocated,
const struct MEdge *edge,
- const int edges_num,
- const bool edge_allocated,
+ int edges_num,
+ bool edge_allocated,
const BLI_bitmap *edges_mask,
int edges_num_active,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
@@ -203,16 +204,16 @@ BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
*/
BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
- const bool vert_allocated,
+ bool vert_allocated,
const struct MFace *face,
- const int numFaces,
- const bool face_allocated,
+ int numFaces,
+ bool face_allocated,
const BLI_bitmap *faces_mask,
int faces_num_active,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
@@ -229,7 +230,7 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
@@ -240,18 +241,18 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
*/
BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
- const bool vert_allocated,
+ bool vert_allocated,
const struct MLoop *mloop,
- const bool loop_allocated,
+ bool loop_allocated,
const struct MLoopTri *looptri,
- const int looptri_num,
- const bool looptri_allocated,
+ int looptri_num,
+ bool looptri_allocated,
const BLI_bitmap *mask,
int looptri_num_active,
float epsilon,
int tree_type,
int axis,
- const BVHCacheType bvh_cache_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
@@ -263,16 +264,16 @@ BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
*/
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
const struct Mesh *mesh,
- const BVHCacheType bvh_cache_type,
- const int tree_type);
+ BVHCacheType bvh_cache_type,
+ 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,
- const BVHCacheType bvh_cache_type,
+ int tree_type,
+ BVHCacheType bvh_cache_type,
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
@@ -288,14 +289,11 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data);
/**
* Math functions used by callbacks
*/
-float bvhtree_ray_tri_intersection(const BVHTreeRay *ray,
- const float m_dist,
- const float v0[3],
- const float v1[3],
- const float v2[3]);
+float bvhtree_ray_tri_intersection(
+ const BVHTreeRay *ray, float m_dist, const float v0[3], const float v1[3], const float v2[3]);
float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray,
float radius,
- const float m_dist,
+ float m_dist,
const float v0[3],
const float v1[3],
const float v2[3]);
@@ -310,7 +308,7 @@ typedef struct BVHTreeFromPointCloud {
BVHTree *BKE_bvhtree_from_pointcloud_get(struct BVHTreeFromPointCloud *data,
const struct PointCloud *pointcloud,
- const int tree_type);
+ int tree_type);
void free_bvhtree_from_pointcloud(struct BVHTreeFromPointCloud *data);
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h
index ac621bfdcb9..c6821d88d2a 100644
--- a/source/blender/blenkernel/BKE_cachefile.h
+++ b/source/blender/blenkernel/BKE_cachefile.h
@@ -28,6 +28,7 @@ extern "C" {
#endif
struct CacheFile;
+struct CacheFileLayer;
struct CacheReader;
struct Depsgraph;
struct Main;
@@ -50,9 +51,7 @@ bool BKE_cachefile_filepath_get(const struct Main *bmain,
const struct CacheFile *cache_file,
char r_filename[1024]);
-float BKE_cachefile_time_offset(const struct CacheFile *cache_file,
- const float time,
- const float fps);
+float BKE_cachefile_time_offset(const struct CacheFile *cache_file, float time, float fps);
/* Modifiers and constraints open and free readers through these. */
void BKE_cachefile_reader_open(struct CacheFile *cache_file,
@@ -69,7 +68,16 @@ void BKE_cachefile_reader_free(struct CacheFile *cache_file, struct CacheReader
*/
bool BKE_cache_file_uses_render_procedural(const struct CacheFile *cache_file,
struct Scene *scene,
- const int dag_eval_mode);
+ int dag_eval_mode);
+
+/* Add a layer to the cache_file. Return NULL if the filename is already that of an existing layer
+ * or if the number of layers exceeds the maximum allowed layer count. */
+struct CacheFileLayer *BKE_cachefile_add_layer(struct CacheFile *cache_file,
+ const char filename[1024]);
+
+struct CacheFileLayer *BKE_cachefile_get_active_layer(struct CacheFile *cache_file);
+
+void BKE_cachefile_remove_layer(struct CacheFile *cache_file, struct CacheFileLayer *layer);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h
index c125b081b49..2e4923ff3d2 100644
--- a/source/blender/blenkernel/BKE_callbacks.h
+++ b/source/blender/blenkernel/BKE_callbacks.h
@@ -114,14 +114,14 @@ typedef enum {
typedef struct bCallbackFuncStore {
struct bCallbackFuncStore *next, *prev;
- void (*func)(struct Main *, struct PointerRNA **, const int num_pointers, void *arg);
+ void (*func)(struct Main *, struct PointerRNA **, int num_pointers, void *arg);
void *arg;
short alloc;
} bCallbackFuncStore;
void BKE_callback_exec(struct Main *bmain,
struct PointerRNA **pointers,
- const int num_pointers,
+ int num_pointers,
eCbEvent evt);
void BKE_callback_exec_null(struct Main *bmain, eCbEvent evt);
void BKE_callback_exec_id(struct Main *bmain, struct ID *id, eCbEvent evt);
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index 45bfef82302..ee78621c11f 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -110,8 +110,8 @@ void BKE_camera_params_compute_matrix(CameraParams *params);
void BKE_camera_view_frame_ex(const struct Scene *scene,
const struct Camera *camera,
- const float drawsize,
- const bool do_clip,
+ float drawsize,
+ bool do_clip,
const float scale[3],
float r_asp[2],
float r_shift[2],
@@ -151,7 +151,7 @@ struct Object *BKE_camera_multiview_render(const struct Scene *scene,
*/
void BKE_camera_multiview_view_matrix(const struct RenderData *rd,
const struct Object *camera,
- const bool is_left,
+ bool is_left,
float r_viewmat[4][4]);
void BKE_camera_multiview_model_matrix(const struct RenderData *rd,
const struct Object *camera,
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index 46c1fe0d33d..402bffea91d 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -102,8 +102,8 @@ bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bo
struct Collection *BKE_collection_duplicate(struct Main *bmain,
struct Collection *parent,
struct Collection *collection,
- const uint duplicate_flags,
- const uint duplicate_options);
+ uint duplicate_flags,
+ uint duplicate_options);
/* Master Collection for Scene */
@@ -144,7 +144,7 @@ void BKE_collection_object_add_from(struct Main *bmain,
bool BKE_collection_object_remove(struct Main *bmain,
struct Collection *collection,
struct Object *object,
- const bool free_us);
+ bool free_us);
/**
* Move object from a collection into another
*
@@ -162,8 +162,22 @@ void BKE_collection_object_move(struct Main *bmain,
bool BKE_scene_collections_object_remove(struct Main *bmain,
struct Scene *scene,
struct Object *object,
- const bool free_us);
+ bool free_us);
+
+/**
+ * Check all collections in \a bmain (including embedded ones in scenes) for CollectionObject with
+ * NULL object pointer, and remove them.
+ */
void BKE_collections_object_remove_nulls(struct Main *bmain);
+
+/**
+ * Check all collections in \a bmain (including embedded ones in scenes) for duplicate
+ * CollectionObject with a same object pointer within a same object, and remove them.
+ *
+ * NOTE: Always keeps the first of the detected duplicates.
+ */
+void BKE_collections_object_remove_duplicates(struct Main *bmain);
+
/**
* Remove all NULL children from parent collections of changed \a collection.
* This is used for library remapping, where these pointers have been set to NULL.
@@ -204,7 +218,7 @@ struct Base *BKE_collection_or_layer_objects(const struct ViewLayer *view_layer,
*
* 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);
+struct Collection *BKE_collection_from_index(struct Scene *scene, int index);
/**
* The automatic/fallback name of a new collection.
*/
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index 71929d1797c..d4c5c03ea79 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -122,9 +122,9 @@ void bvhtree_update_from_mvert(struct BVHTree *bvhtree,
* \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,
- const bool moving_bvh);
+ float step,
+ float prevstep,
+ bool moving_bvh);
void collision_get_collider_velocity(float vel_old[3],
float vel_new[3],
diff --git a/source/blender/blenkernel/BKE_colorband.h b/source/blender/blenkernel/BKE_colorband.h
index 0f46ced8b06..554b0f36b60 100644
--- a/source/blender/blenkernel/BKE_colorband.h
+++ b/source/blender/blenkernel/BKE_colorband.h
@@ -34,7 +34,7 @@ struct ColorBand;
void BKE_colorband_init(struct ColorBand *coba, bool rangetype);
void BKE_colorband_init_from_table_rgba(struct ColorBand *coba,
const float (*array)[4],
- const int array_len,
+ int array_len,
bool filter_sample);
struct ColorBand *BKE_colorband_add(bool rangetype);
bool BKE_colorband_evaluate(const struct ColorBand *coba, float in, float out[4]);
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index 17fb48cdd27..5ded49106da 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -67,7 +67,7 @@ void BKE_curvemap_reset(struct CurveMap *cuma, const struct rctf *clipr, int pre
/**
* Removes with flag set.
*/
-void BKE_curvemap_remove(struct CurveMap *cuma, const short flag);
+void BKE_curvemap_remove(struct CurveMap *cuma, short flag);
/**
* Remove specified point.
*/
@@ -81,7 +81,7 @@ 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(struct CurveMapping *cumap, bool rem_doubles);
void BKE_curvemapping_changed_all(struct CurveMapping *cumap);
/**
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index 1f59efbb0f3..55e5cd0a149 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -162,9 +162,7 @@ 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);
+struct bConstraint *BKE_constraint_duplicate_ex(struct bConstraint *src, int flag, bool do_extern);
/**
* Add a copy of the given constraint for the given bone.
@@ -188,7 +186,7 @@ void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool
*/
void BKE_constraints_copy_ex(struct ListBase *dst,
const struct ListBase *src,
- const int flag,
+ int flag,
bool do_extern);
/**
* Run the given callback on all ID-blocks in list of constraints.
@@ -319,7 +317,7 @@ void BKE_constraint_mat_convertspace(struct Object *ob,
float mat[4][4],
short from,
short to,
- const bool keep_scale);
+ bool keep_scale);
/**
* This function is a relic from the prior implementations of the constraints system, when all
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index ac864c7f82c..18c1848b737 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -253,10 +253,7 @@ ListBase CTX_data_collection_get(const bContext *C, const char *member);
* \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,
- const bool use_all);
+ListBase CTX_data_dir_get_ex(const bContext *C, bool use_store, bool use_rna, bool use_all);
ListBase CTX_data_dir_get(const bContext *C);
int /*eContextResult*/ CTX_data_get(
const bContext *C, const char *member, PointerRNA *r_ptr, ListBase *r_lb, short *r_type);
@@ -282,8 +279,9 @@ bool CTX_data_dir(const char *member);
ListBase ctx_data_list; \
CollectionPointerLink *ctx_link; \
CTX_data_##member(C, &ctx_data_list); \
- for (ctx_link = ctx_data_list.first; ctx_link; ctx_link = ctx_link->next) { \
- Type instance = ctx_link->ptr.data;
+ for (ctx_link = (CollectionPointerLink *)ctx_data_list.first; ctx_link; \
+ ctx_link = ctx_link->next) { \
+ Type instance = (Type)ctx_link->ptr.data;
#define CTX_DATA_END \
} \
@@ -319,7 +317,7 @@ struct ToolSettings *CTX_data_tool_settings(const bContext *C);
const char *CTX_data_mode_string(const bContext *C);
enum eContextObjectMode CTX_data_mode_enum_ex(const struct Object *obedit,
const struct Object *ob,
- const eObjectMode object_mode);
+ eObjectMode object_mode);
enum eContextObjectMode CTX_data_mode_enum(const bContext *C);
void CTX_data_main_set(bContext *C, struct Main *bmain);
diff --git a/source/blender/blenkernel/BKE_crazyspace.h b/source/blender/blenkernel/BKE_crazyspace.h
index f5266ed7a10..42d85c70bc1 100644
--- a/source/blender/blenkernel/BKE_crazyspace.h
+++ b/source/blender/blenkernel/BKE_crazyspace.h
@@ -26,10 +26,12 @@
#ifdef __cplusplus
extern "C" {
#endif
+
struct BMEditMesh;
struct Depsgraph;
struct Mesh;
struct Object;
+struct ReportList;
struct Scene;
/* crazyspace.c */
@@ -43,7 +45,7 @@ void BKE_crazyspace_set_quats_editmesh(struct BMEditMesh *em,
float (*origcos)[3],
float (*mappedcos)[3],
float (*quats)[4],
- const bool use_select);
+ bool use_select);
void BKE_crazyspace_set_quats_mesh(struct Mesh *me,
float (*origcos)[3],
float (*mappedcos)[3],
@@ -69,6 +71,31 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
float (**deformmats)[3][3],
float (**deformcos)[3]);
+/* -------------------------------------------------------------------- */
+/** \name Crazy-Space API
+ * \{ */
+
+void BKE_crazyspace_api_eval(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *object,
+ struct ReportList *reports);
+
+void BKE_crazyspace_api_displacement_to_deformed(struct Object *object,
+ struct ReportList *reports,
+ int vertex_index,
+ float displacement[3],
+ float r_displacement_deformed[3]);
+
+void BKE_crazyspace_api_displacement_to_original(struct Object *object,
+ struct ReportList *reports,
+ int vertex_index,
+ float displacement_deformed[3],
+ float r_displacement[3]);
+
+void BKE_crazyspace_api_eval_clear(struct Object *object);
+
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h
index 329046ad494..64fbb00b143 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.h
+++ b/source/blender/blenkernel/BKE_cryptomatte.h
@@ -59,7 +59,7 @@ 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,
+ float encoded_hash,
char *r_name,
int name_len);
diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh
index 08536ecccbd..aa82166aa70 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.hh
+++ b/source/blender/blenkernel/BKE_cryptomatte.hh
@@ -70,7 +70,7 @@ struct CryptomatteHash {
uint32_t hash;
CryptomatteHash(uint32_t hash);
- CryptomatteHash(const char *name, const int name_len);
+ CryptomatteHash(const char *name, int name_len);
static CryptomatteHash from_hex_encoded(blender::StringRef hex_encoded);
std::string hex_encoded() const;
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 713ee8cac01..25d49544330 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -90,7 +90,7 @@ typedef struct CVKeyIndex {
* Frees edit-curve entirely.
*/
void BKE_curve_editfont_free(struct Curve *cu);
-void BKE_curve_init(struct Curve *cu, const short curve_type);
+void BKE_curve_init(struct Curve *cu, short curve_type);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
short BKE_curve_type_get(const struct Curve *cu);
void BKE_curve_type_test(struct Object *ob);
@@ -106,23 +106,17 @@ void BKE_curve_texspace_ensure(struct Curve *cu);
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]);
-void BKE_curve_transform_ex(struct Curve *cu,
- const float mat[4][4],
- const bool do_keys,
- const bool do_props,
- const float unit_scale);
-void BKE_curve_transform(struct Curve *cu,
- const float mat[4][4],
- const bool do_keys,
- const bool do_props);
-void BKE_curve_translate(struct Curve *cu, const float offset[3], const bool do_keys);
+void BKE_curve_transform_ex(
+ struct Curve *cu, const float mat[4][4], bool do_keys, bool do_props, float unit_scale);
+void BKE_curve_transform(struct Curve *cu, const float mat[4][4], bool do_keys, bool do_props);
+void BKE_curve_translate(struct Curve *cu, const float offset[3], bool do_keys);
void BKE_curve_material_index_remove(struct Curve *cu, int index);
bool BKE_curve_material_index_used(const struct Curve *cu, int index);
void BKE_curve_material_index_clear(struct Curve *cu);
bool BKE_curve_material_index_validate(struct Curve *cu);
void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsigned int remap_len);
-void BKE_curve_smooth_flag_set(struct Curve *cu, const bool use_smooth);
+void BKE_curve_smooth_flag_set(struct Curve *cu, bool use_smooth);
/**
* \return edit-nurbs or normal nurbs list.
@@ -155,11 +149,11 @@ void BKE_curve_nurbs_vert_coords_get(const struct ListBase *lb,
void BKE_curve_nurbs_vert_coords_apply_with_mat4(struct ListBase *lb,
const float (*vert_coords)[3],
const float mat[4][4],
- const bool constrain_2d);
+ bool constrain_2d);
void BKE_curve_nurbs_vert_coords_apply(struct ListBase *lb,
const float (*vert_coords)[3],
- const bool constrain_2d);
+ bool constrain_2d);
float (*BKE_curve_nurbs_key_vert_coords_alloc(const struct ListBase *lb,
float *key,
@@ -202,7 +196,7 @@ void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], cons
/* ** Nurbs ** */
-bool BKE_nurbList_index_get_co(struct ListBase *editnurb, const int index, float r_co[3]);
+bool BKE_nurbList_index_get_co(struct ListBase *editnurb, int index, float r_co[3]);
int BKE_nurbList_verts_count(const struct ListBase *nurb);
int BKE_nurbList_verts_count_without_handles(const struct ListBase *nurb);
@@ -218,10 +212,8 @@ void BKE_nurbList_duplicate(struct ListBase *lb1, const struct ListBase *lb2);
* - 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,
- const uint8_t flag);
+void BKE_nurbList_handles_set(struct ListBase *editnurb, char code);
+void BKE_nurbList_handles_recalculate(struct ListBase *editnurb, bool calc_length, uint8_t flag);
void BKE_nurbList_handles_autocalc(ListBase *editnurb, uint8_t flag);
void BKE_nurbList_flag_set(ListBase *editnurb, uint8_t flag, bool set);
@@ -266,10 +258,10 @@ void BKE_nurb_makeCurve(const struct Nurb *nu,
/**
* 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);
+unsigned int BKE_curve_calc_coords_axis_len(unsigned int bezt_array_len,
+ unsigned int resolu,
+ bool is_cyclic,
+ bool use_cyclic_duplicate_endpoint);
/**
* Calculate an array for the entire curve (cyclic or non-cyclic).
* \note Call for each axis.
@@ -277,13 +269,13 @@ unsigned int BKE_curve_calc_coords_axis_len(const unsigned int bezt_array_len,
* \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,
- const bool is_cyclic,
- const bool use_cyclic_duplicate_endpoint,
+ unsigned int bezt_array_len,
+ unsigned int resolu,
+ bool is_cyclic,
+ bool use_cyclic_duplicate_endpoint,
/* array params */
- const unsigned int axis,
- const unsigned int stride,
+ unsigned int axis,
+ unsigned int stride,
float *r_points);
void BKE_nurb_knot_calc_u(struct Nurb *nu);
@@ -301,10 +293,7 @@ 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);
+bool BKE_nurb_type_convert(struct Nurb *nu, short type, bool use_handles, const char **r_err_msg);
/**
* Be sure to call #BKE_nurb_knot_calc_u / #BKE_nurb_knot_calc_v after this.
@@ -333,8 +322,8 @@ void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, struct BPoint *bp, float r_plan
void BKE_nurb_handle_calc(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
- const bool is_fcurve,
- const char smoothing);
+ bool is_fcurve,
+ char smoothing);
/**
* Variant of #BKE_nurb_handle_calc() that allows calculating based on a different select flag.
*
@@ -345,9 +334,9 @@ void BKE_nurb_handle_calc(struct BezTriple *bezt,
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);
+ eBezTriple_Flag__Alias handle_sel_flag,
+ bool is_fcurve,
+ char smoothing);
/**
* Similar to #BKE_nurb_handle_calc but for curves and figures out the previous and next for us.
*/
@@ -371,10 +360,10 @@ void BKE_nurb_handles_autocalc(struct Nurb *nu, uint8_t flag);
* 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,
- const bool use_around_local);
-void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles, const bool use_around_local);
+ eBezTriple_Flag__Alias sel_flag,
+ bool use_handle,
+ bool use_around_local);
+void BKE_nurb_handles_test(struct Nurb *nu, bool use_handles, bool use_around_local);
/* **** Depsgraph evaluation **** */
@@ -398,18 +387,18 @@ extern void (*BKE_curve_batch_cache_free_cb)(struct Curve *cu);
* \{ */
unsigned int BKE_curve_decimate_bezt_array(struct BezTriple *bezt_array,
- const unsigned int bezt_array_len,
- const unsigned int resolu,
- const bool is_cyclic,
- const char flag_test,
- const char flag_set,
- const float error_sq_max,
- const unsigned int error_target_len);
+ unsigned int bezt_array_len,
+ unsigned int resolu,
+ bool is_cyclic,
+ char flag_test,
+ char flag_set,
+ float error_sq_max,
+ unsigned int error_target_len);
void BKE_curve_decimate_nurb(struct Nurb *nu,
- const unsigned int resolu,
- const float error_sq_max,
- const unsigned int error_target_len);
+ unsigned int resolu,
+ float error_sq_max,
+ unsigned int error_target_len);
/** \} */
@@ -420,19 +409,19 @@ void BKE_curve_decimate_nurb(struct Nurb *nu,
void BKE_curve_deform_coords(const struct Object *ob_curve,
const struct Object *ob_target,
float (*vert_coords)[3],
- const int vert_coords_len,
+ int vert_coords_len,
const struct MDeformVert *dvert,
- const int defgrp_index,
- const short flag,
- const short defaxis);
+ int defgrp_index,
+ short flag,
+ short defaxis);
void BKE_curve_deform_coords_with_editmesh(const struct Object *ob_curve,
const struct Object *ob_target,
float (*vert_coords)[3],
- const int vert_coords_len,
- const int defgrp_index,
- const short flag,
- const short defaxis,
+ int vert_coords_len,
+ int defgrp_index,
+ short flag,
+ short defaxis,
struct BMEditMesh *em_target);
/**
@@ -445,7 +434,7 @@ void BKE_curve_deform_co(const struct Object *ob_curve,
const struct Object *ob_target,
const float orco[3],
float vec[3],
- const int no_rot_axis,
+ int no_rot_axis,
float r_mat[3][3]);
/** \} */
diff --git a/source/blender/blenkernel/BKE_curve_to_mesh.hh b/source/blender/blenkernel/BKE_curve_to_mesh.hh
index cf5c8b87ede..10649e8703f 100644
--- a/source/blender/blenkernel/BKE_curve_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_curve_to_mesh.hh
@@ -16,8 +16,8 @@
#pragma once
-struct Mesh;
struct CurveEval;
+struct Mesh;
/** \file
* \ingroup bke
diff --git a/source/blender/blenkernel/BKE_curveprofile.h b/source/blender/blenkernel/BKE_curveprofile.h
index ee8bf99a216..aa79f29760d 100644
--- a/source/blender/blenkernel/BKE_curveprofile.h
+++ b/source/blender/blenkernel/BKE_curveprofile.h
@@ -62,8 +62,8 @@ struct CurveProfile *BKE_curveprofile_copy(const struct CurveProfile *profile);
* \return Whether the handle moved from its start position.
*/
bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
- const bool handle_1,
- const bool snap,
+ bool handle_1,
+ bool snap,
const float delta[2]);
/**
@@ -76,7 +76,7 @@ bool BKE_curveprofile_move_handle(struct CurveProfilePoint *point,
*/
bool BKE_curveprofile_move_point(struct CurveProfile *profile,
struct CurveProfilePoint *point,
- const bool snap,
+ bool snap,
const float delta[2]);
/**
@@ -92,7 +92,7 @@ bool BKE_curveprofile_remove_point(struct CurveProfile *profile, struct CurvePro
*
* \note Requires #BKE_curveprofile_update call after.
*/
-void BKE_curveprofile_remove_by_flag(struct CurveProfile *profile, const short flag);
+void BKE_curveprofile_remove_by_flag(struct CurveProfile *profile, short flag);
/**
* Adds a new point at the specified location. The choice for which points to place the new vertex
@@ -151,7 +151,7 @@ enum {
* \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);
+void BKE_curveprofile_update(struct CurveProfile *profile, int update_flags);
/**
* Does a single evaluation along the profile's path.
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 68d29235469..00eae2e8e6e 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -84,7 +84,7 @@ void customData_mask_layers__print(const struct CustomData_MeshMasks *mask);
typedef void (*cd_interp)(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest);
typedef void (*cd_copy)(const void *source, void *dest, int count);
-typedef bool (*cd_validate)(void *item, const uint totitems, const bool do_fixes);
+typedef bool (*cd_validate)(void *item, uint totitems, bool do_fixes);
/**
* Update mask_dst with layers defined in mask_src (equivalent to a bit-wise OR).
@@ -131,7 +131,7 @@ void CustomData_data_copy_value(int type, const void *source, void *dest);
* 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);
+ int type, const void *source, void *dest, int mixmode, float mixfactor);
/**
* Compares if data1 is equal to data2. type is a valid CustomData type
@@ -187,7 +187,7 @@ bool CustomData_bmesh_merge(const struct CustomData *source,
CustomDataMask mask,
eCDAllocType alloctype,
struct BMesh *bm,
- const char htype);
+ char htype);
/**
* NULL's all members and resets the #CustomData.typemap.
@@ -268,22 +268,17 @@ int CustomData_number_of_layers_typemask(const struct CustomData *data, CustomDa
* 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);
+void *CustomData_duplicate_referenced_layer(struct CustomData *data, int type, int totelem);
void *CustomData_duplicate_referenced_layer_n(struct CustomData *data,
- const int type,
- const int n,
- const int totelem);
+ int type,
+ int n,
+ int totelem);
void *CustomData_duplicate_referenced_layer_named(struct CustomData *data,
- const int type,
+ int type,
const char *name,
- const int totelem);
+ int totelem);
void *CustomData_duplicate_referenced_layer_anonymous(
- CustomData *data,
- const int type,
- const struct AnonymousAttributeID *anonymous_id,
- const int totelem);
+ CustomData *data, int type, const struct AnonymousAttributeID *anonymous_id, int totelem);
bool CustomData_is_referenced_layer(struct CustomData *data, int type);
/**
@@ -328,7 +323,7 @@ void CustomData_bmesh_copy_data_exclude_by_type(const struct CustomData *source,
struct CustomData *dest,
void *src_block,
void **dest_block,
- const CustomDataMask mask_exclude);
+ CustomDataMask mask_exclude);
/**
* Copies data of a single layer of a given type.
@@ -394,7 +389,7 @@ 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);
+void CustomData_swap(struct CustomData *data, int index_a, int index_b);
/**
* Gets a pointer to the data element at index from the first layer of type.
@@ -501,7 +496,7 @@ void CustomData_bmesh_free_block_data(struct CustomData *data, void *block);
*/
void CustomData_bmesh_free_block_data_exclude_by_type(struct CustomData *data,
void *block,
- const CustomDataMask mask_exclude);
+ CustomDataMask mask_exclude);
/**
* Copy custom data to/from layers as in mesh/derived-mesh, to edit-mesh
@@ -544,7 +539,7 @@ 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);
+int CustomData_layertype_layers_max(int type);
/**
* Make sure the name of layer at index is unique.
@@ -577,7 +572,7 @@ void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct Cust
*/
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);
+void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, char htype);
#ifndef NDEBUG
/**
@@ -595,9 +590,7 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool f
*
* \return True if some errors were found.
*/
-bool CustomData_layer_validate(struct CustomDataLayer *layer,
- const uint totitems,
- const bool do_fixes);
+bool CustomData_layer_validate(struct CustomDataLayer *layer, uint totitems, bool do_fixes);
void CustomData_layers__print(struct CustomData *data);
/* External file storage */
@@ -627,8 +620,8 @@ typedef void (*cd_datatransfer_interp)(const struct CustomDataTransferLayerMap *
void *dest,
const void **sources,
const float *weights,
- const int count,
- const float mix_factor);
+ int count,
+ float mix_factor);
/**
* Fake CD_LAYERS (those are actually 'real' data stored directly into elements' structs,
@@ -754,6 +747,14 @@ void CustomData_blend_write(struct BlendWriter *writer,
struct ID *id);
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
+#ifndef NDEBUG
+struct DynStr;
+/** Use to inspect mesh data when debugging. */
+void CustomData_debug_info_from_layers(const struct CustomData *data,
+ const char *indent,
+ struct DynStr *dynstr);
+#endif /* NDEBUG */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h
index a4218ec564b..42cf2256e8c 100644
--- a/source/blender/blenkernel/BKE_data_transfer.h
+++ b/source/blender/blenkernel/BKE_data_transfer.h
@@ -63,19 +63,19 @@ enum {
DT_TYPE_POLY_ALL = DT_TYPE_UV | DT_TYPE_SHARP_FACE | DT_TYPE_FREESTYLE_FACE,
};
-void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types,
+void BKE_object_data_transfer_dttypes_to_cdmask(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 BKE_object_data_transfer_get_dttypes_capacity(int dtdata_types,
bool *r_advanced_mixing,
bool *r_threshold);
-int BKE_object_data_transfer_get_dttypes_item_types(const int dtdata_types);
+int BKE_object_data_transfer_get_dttypes_item_types(int dtdata_types);
-int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type);
-int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type);
+int BKE_object_data_transfer_dttype_to_cdtype(int dtdata_type);
+int BKE_object_data_transfer_dttype_to_srcdst_index(int dtdata_type);
#define DT_DATATYPE_IS_VERT(_dt) \
ELEM(_dt, DT_TYPE_MDEFORMVERT, DT_TYPE_SHAPEKEY, DT_TYPE_SKIN, DT_TYPE_BWEIGHT_VERT)
@@ -136,8 +136,8 @@ void BKE_object_data_transfer_layout(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst,
- const int data_types,
- const bool use_delete,
+ int data_types,
+ bool use_delete,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX],
const int tolayers_select[DT_MULTILAYER_INDEX_MAX]);
@@ -145,46 +145,46 @@ bool BKE_object_data_transfer_mesh(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst,
- const int data_types,
- const bool use_create,
- const int map_vert_mode,
- const int map_edge_mode,
- const int map_loop_mode,
- const int map_poly_mode,
+ int data_types,
+ bool use_create,
+ int map_vert_mode,
+ int map_edge_mode,
+ int map_loop_mode,
+ int map_poly_mode,
struct SpaceTransform *space_transform,
- const bool auto_transform,
- const float max_distance,
- const float ray_radius,
- const float islands_handling_precision,
+ bool auto_transform,
+ float max_distance,
+ float ray_radius,
+ float islands_handling_precision,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX],
const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
- const int mix_mode,
- const float mix_factor,
+ int mix_mode,
+ float mix_factor,
const char *vgroup_name,
- const bool invert_vgroup,
+ bool invert_vgroup,
struct ReportList *reports);
bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_src,
struct Object *ob_dst,
struct Mesh *me_dst,
- const int data_types,
+ int data_types,
bool use_create,
- const int map_vert_mode,
- const int map_edge_mode,
- const int map_loop_mode,
- const int map_poly_mode,
+ int map_vert_mode,
+ int map_edge_mode,
+ int map_loop_mode,
+ int map_poly_mode,
struct SpaceTransform *space_transform,
- const bool auto_transform,
- const float max_distance,
- const float ray_radius,
- const float islands_handling_precision,
+ bool auto_transform,
+ float max_distance,
+ float ray_radius,
+ float islands_handling_precision,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX],
const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
- const int mix_mode,
- const float mix_factor,
+ int mix_mode,
+ float mix_factor,
const char *vgroup_name,
- const bool invert_vgroup,
+ bool invert_vgroup,
struct ReportList *reports);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index 9870d43b5c2..ca0ca03f099 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -51,7 +51,7 @@ 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);
+void BKE_object_defgroup_active_index_set(struct Object *ob, 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);
@@ -68,33 +68,31 @@ struct bDeformGroup *BKE_object_defgroup_find_name(const struct Object *ob, cons
/**
* \note caller must free.
*/
-int *BKE_object_defgroup_flip_map(const struct Object *ob,
- int *flip_map_len,
- const bool use_default);
+int *BKE_object_defgroup_flip_map(const struct Object *ob, int *flip_map_len, 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,
+ bool use_default,
int defgroup);
-int BKE_object_defgroup_flip_index(const struct Object *ob, int index, const bool use_default);
+int BKE_object_defgroup_flip_index(const struct Object *ob, int index, bool use_default);
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);
+struct MDeformWeight *BKE_defvert_find_index(const struct MDeformVert *dv, 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);
+struct MDeformWeight *BKE_defvert_ensure_index(struct MDeformVert *dv, 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);
+void BKE_defvert_add_index_notest(struct MDeformVert *dv, int defgroup, float weight);
/**
* Removes the given vertex from the vertex group.
*
@@ -110,13 +108,13 @@ int BKE_defvert_find_shared(const struct MDeformVert *dvert_a, const struct MDef
/**
* \return true if has no weights.
*/
-bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_tot);
+bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, int defgroup_tot);
void BKE_defvert_array_free_elems(struct MDeformVert *dvert, int totvert);
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);
+float BKE_defvert_find_weight(const struct MDeformVert *dvert, 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.
@@ -124,9 +122,7 @@ float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgrou
*
* 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);
+float BKE_defvert_array_find_weight_safe(const struct MDeformVert *dvert, int index, int defgroup);
/**
* \return The total weight in all groups marked in the selection mask.
@@ -180,7 +176,7 @@ void BKE_defvert_copy(struct MDeformVert *dvert_dst, const struct MDeformVert *d
void BKE_defvert_copy_subset(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool *vgroup_subset,
- const int vgroup_tot);
+ int vgroup_tot);
/**
* Overwrite weights filtered by vgroup_subset and with mirroring specified by the flip map
* - do nothing if neither are set.
@@ -189,101 +185,96 @@ void BKE_defvert_copy_subset(struct MDeformVert *dvert_dst,
void BKE_defvert_mirror_subset(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool *vgroup_subset,
- const int vgroup_tot,
+ int vgroup_tot,
const int *flip_map,
- const int flip_map_len);
+ 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,
+ int defgroup_dst,
const struct MDeformVert *dvert_src,
- const int defgroup_src);
+ 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);
+ 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);
+ int flip_map_len,
+ 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_remap(struct MDeformVert *dvert, const int *map, int map_len);
+void BKE_defvert_flip(struct MDeformVert *dvert, const int *flip_map, int flip_map_len);
+void BKE_defvert_flip_merged(struct MDeformVert *dvert, const int *flip_map, 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);
+ 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);
+ int vgroup_tot,
+ 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,
+ int vgroup_tot,
const bool *lock_flags,
- const int defbase_tot);
+ int defbase_tot);
/* 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);
+void BKE_defvert_extract_vgroup_to_vertweights(
+ struct MDeformVert *dvert, int defgroup, int num_verts, float *r_weights, 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,
+ int defgroup,
+ int num_verts,
struct MEdge *edges,
- const int num_edges,
+ int num_edges,
float *r_weights,
- const bool invert_vgroup);
+ bool invert_vgroup);
void BKE_defvert_extract_vgroup_to_loopweights(struct MDeformVert *dvert,
- const int defgroup,
- const int num_verts,
+ int defgroup,
+ int num_verts,
struct MLoop *loops,
- const int num_loops,
+ int num_loops,
float *r_weights,
- const bool invert_vgroup);
+ bool invert_vgroup);
void BKE_defvert_extract_vgroup_to_polyweights(struct MDeformVert *dvert,
- const int defgroup,
- const int num_verts,
+ int defgroup,
+ int num_verts,
struct MLoop *loops,
- const int num_loops,
+ int num_loops,
struct MPoly *polys,
- const int num_polys,
+ int num_polys,
float *r_weights,
- const bool invert_vgroup);
+ bool invert_vgroup);
-void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight);
+void BKE_defvert_weight_to_rgb(float r_rgb[3], float weight);
void BKE_defvert_blend_write(struct BlendWriter *writer, int count, struct MDeformVert *dvlist);
void BKE_defvert_blend_read(struct BlendDataReader *reader,
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index db1217465d7..6467ad36989 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -86,7 +86,7 @@ void BKE_displist_free(struct ListBase *lb);
void BKE_displist_make_curveTypes(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct Object *ob,
- const bool for_render);
+ bool for_render);
void BKE_displist_make_mball(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph,
@@ -94,7 +94,7 @@ void BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph,
struct Object *ob,
struct ListBase *source_nurb,
struct ListBase *target_nurb,
- const bool for_render);
+ bool for_render);
bool BKE_displist_surfindex_get(
const struct DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4);
@@ -107,7 +107,7 @@ bool BKE_displist_surfindex_get(
void BKE_displist_fill(const struct ListBase *dispbase,
struct ListBase *to,
const float normal_proj[3],
- const bool flip_normal);
+ bool flip_normal);
float BKE_displist_calc_taper(struct Depsgraph *depsgraph,
const struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h
index 5eff84b8c9e..303a83d921f 100644
--- a/source/blender/blenkernel/BKE_duplilist.h
+++ b/source/blender/blenkernel/BKE_duplilist.h
@@ -27,11 +27,11 @@ extern "C" {
#endif
struct Depsgraph;
+struct ID;
struct ListBase;
struct Object;
struct ParticleSystem;
struct Scene;
-struct ID;
/* ---------------------------------------------------- */
/* Dupli-Geometry */
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 32cc5961e4a..1da7ae3da8a 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -19,7 +19,7 @@
/** \file
* \ingroup bke
*
- * The \link edmesh EDBM module\endlink is for editmode bmesh stuff.
+ * The \link edmesh EDBM module \endlink is for editmode bmesh stuff.
* In contrast, this module is for code shared with blenkernel that's
* only concerned with low level operations on the #BMEditMesh structure.
*/
@@ -62,14 +62,6 @@ typedef struct BMEditMesh {
struct BMLoop *(*looptris)[3];
int tottri;
- struct Mesh *mesh_eval_final, *mesh_eval_cage;
-
- /** Cached cage bounding box of `mesh_eval_cage` for selection. */
- struct BoundBox *bb_cage;
-
- /** Evaluated mesh data-mask. */
- CustomData_MeshMasks lastDataMask;
-
/** Selection mode (#SCE_SELECT_VERTEX, #SCE_SELECT_EDGE & #SCE_SELECT_FACE). */
short selectmode;
/** The active material (assigned to newly created faces). */
@@ -121,7 +113,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em);
* 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.
*/
@@ -145,7 +136,7 @@ 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);
+struct BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *em);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h
index fc274b4ffd1..b4368ff363b 100644
--- a/source/blender/blenkernel/BKE_editmesh_bvh.h
+++ b/source/blender/blenkernel/BKE_editmesh_bvh.h
@@ -42,13 +42,13 @@ typedef bool (*BMBVHTree_FaceFilter)(struct BMFace *f, void *userdata);
BMBVHTree *BKE_bmbvh_new_from_editmesh(struct BMEditMesh *em,
int flag,
const float (*cos_cage)[3],
- const bool cos_cage_free);
+ bool cos_cage_free);
BMBVHTree *BKE_bmbvh_new_ex(struct BMesh *bm,
struct BMLoop *(*looptris)[3],
int looptris_tot,
int flag,
const float (*cos_cage)[3],
- const bool cos_cage_free,
+ bool cos_cage_free,
bool (*test_fn)(struct BMFace *, void *user_data),
void *user_data);
BMBVHTree *BKE_bmbvh_new(struct BMesh *bm,
@@ -56,14 +56,14 @@ BMBVHTree *BKE_bmbvh_new(struct BMesh *bm,
int looptris_tot,
int flag,
const float (*cos_cage)[3],
- const bool cos_cage_free);
+ bool cos_cage_free);
void BKE_bmbvh_free(BMBVHTree *tree);
struct BVHTree *BKE_bmbvh_tree_get(BMBVHTree *tree);
struct BMFace *BKE_bmbvh_ray_cast(BMBVHTree *tree,
const float co[3],
const float dir[3],
- const float radius,
+ float radius,
float *r_dist,
float r_hitout[3],
float r_cagehit[3]);
@@ -71,7 +71,7 @@ struct BMFace *BKE_bmbvh_ray_cast(BMBVHTree *tree,
struct BMFace *BKE_bmbvh_ray_cast_filter(BMBVHTree *tree,
const float co[3],
const float dir[3],
- const float radius,
+ float radius,
float *r_dist,
float r_hitout[3],
float r_cagehit[3],
@@ -81,12 +81,8 @@ struct BMFace *BKE_bmbvh_ray_cast_filter(BMBVHTree *tree,
/**
* 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);
-struct BMFace *BKE_bmbvh_find_face_closest(BMBVHTree *tree,
- const float co[3],
- const float dist_max);
+struct BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *tree, const float co[3], float dist_max);
+struct BMFace *BKE_bmbvh_find_face_closest(BMBVHTree *tree, const float co[3], float dist_max);
/**
* Overlap indices reference the looptri's.
diff --git a/source/blender/blenkernel/BKE_editmesh_tangent.h b/source/blender/blenkernel/BKE_editmesh_tangent.h
index b76db11348e..3b0569b869a 100644
--- a/source/blender/blenkernel/BKE_editmesh_tangent.h
+++ b/source/blender/blenkernel/BKE_editmesh_tangent.h
@@ -39,7 +39,7 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
const float (*loop_normals)[3],
const float (*vert_orco)[3],
CustomData *dm_loopdata_out,
- const uint dm_loopdata_out_len,
+ uint dm_loopdata_out_len,
short *tangent_mask_curr_p);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 1537d14ab01..121ec7f316b 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -143,7 +143,7 @@ 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);
+const FModifierTypeInfo *get_fmodifier_typeinfo(int type);
/* ---------------------- */
@@ -266,7 +266,7 @@ void BKE_fcurve_foreach_id(struct FCurve *fcu, struct LibraryForeachIDData *data
* 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);
+struct FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], int array_index);
/**
* Quick way to loop over all f-curves of a given 'path'.
@@ -322,8 +322,8 @@ struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
* 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[],
- const float frame,
- const int arraylen,
+ float frame,
+ int arraylen,
bool *r_replace);
/* fcurve_cache.c */
@@ -336,7 +336,7 @@ 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);
+ int array_index);
/**
* Fill in an array of F-Curve, leave NULL when not found.
*
@@ -351,7 +351,7 @@ int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache,
* 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);
+ struct FCurve *fcu, float *min, float *max, bool do_sel_only, bool do_min_length);
/**
* Calculate the extents of F-Curve's data.
@@ -361,8 +361,8 @@ bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
float *xmax,
float *ymin,
float *ymax,
- const bool do_sel_only,
- const bool include_handles);
+ bool do_sel_only,
+ bool include_handles);
/**
* Return an array of keyed frames, rounded to `interval`.
@@ -373,11 +373,11 @@ bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
* 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,
+ int fcurve_array_len,
+ float interval,
int *r_frames_len);
float *BKE_fcurves_calc_keyed_frames(struct FCurve **fcurve_array,
- const int fcurve_array_len,
+ int fcurve_array_len,
int *r_frames_len);
/**
@@ -472,7 +472,7 @@ void calchandles_fcurve_ex(struct FCurve *fcu, eBezTriple_Flag handle_sel_flag);
* \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);
+void testhandles_fcurve(struct FCurve *fcu, eBezTriple_Flag sel_flag, 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.
@@ -546,7 +546,7 @@ void fcurve_store_samples(
/**
* Convert baked/sampled f-curves into bezt/regular f-curves.
*/
-void fcurve_samples_to_keyframes(struct FCurve *fcu, const int start, const int end);
+void fcurve_samples_to_keyframes(struct FCurve *fcu, int start, 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 af4c970241f..20667c4dfba 100644
--- a/source/blender/blenkernel/BKE_fcurve_driver.h
+++ b/source/blender/blenkernel/BKE_fcurve_driver.h
@@ -100,10 +100,18 @@ void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dva
*/
void driver_change_variable_type(struct DriverVar *dvar, int type);
/**
- * Validate driver name (after being renamed).
+ * Validate driver variable name (after being renamed).
+ *
*/
void driver_variable_name_validate(struct DriverVar *dvar);
/**
+ * Ensure the driver variable's name is unique.
+ *
+ * Assumes the driver variable has already been assigned to the driver, so that
+ * the `prev/next` pointers can be used to find the other variables.
+ */
+void driver_variable_unique_name(struct DriverVar *dvar);
+/**
* Add a new driver variable.
*/
struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
diff --git a/source/blender/blenkernel/BKE_fluid.h b/source/blender/blenkernel/BKE_fluid.h
index 7bafcf00ce8..88df8e52dca 100644
--- a/source/blender/blenkernel/BKE_fluid.h
+++ b/source/blender/blenkernel/BKE_fluid.h
@@ -49,7 +49,7 @@ void BKE_fluid_modifier_reset(struct FluidModifierData *fmd);
void BKE_fluid_modifier_create_type_data(struct FluidModifierData *fmd);
void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd,
struct FluidModifierData *tfmd,
- const int flag);
+ int flag);
bool BKE_fluid_reallocate_fluid(struct FluidDomainSettings *fds, int res[3], int free_old);
void BKE_fluid_reallocate_copy_fluid(struct FluidDomainSettings *fds,
@@ -76,8 +76,8 @@ void BKE_fluid_particle_system_create(struct Main *bmain,
const char *pset_name,
const char *parts_name,
const char *psys_name,
- const int psys_type);
-void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type);
+ int psys_type);
+void BKE_fluid_particle_system_destroy(struct Object *ob, int particle_type);
void BKE_fluid_cache_startframe_set(struct FluidDomainSettings *settings, int value);
void BKE_fluid_cache_endframe_set(struct FluidDomainSettings *settings, int value);
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index ee3517f5b43..3a4301aad6d 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -38,10 +38,10 @@ typedef struct FreestyleSettings FreestyleSettings;
/* FreestyleConfig */
void BKE_freestyle_config_init(struct FreestyleConfig *config);
-void BKE_freestyle_config_free(struct FreestyleConfig *config, const bool do_id_user);
+void BKE_freestyle_config_free(struct FreestyleConfig *config, bool do_id_user);
void BKE_freestyle_config_copy(struct FreestyleConfig *new_config,
const struct FreestyleConfig *config,
- const int flag);
+ int flag);
/* FreestyleConfig.modules */
struct FreestyleModuleConfig *BKE_freestyle_module_add(struct FreestyleConfig *config);
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 79f29e0954e..f92f33b2776 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -23,11 +23,11 @@
#include <atomic>
#include <iostream>
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
#include "BLI_function_ref.hh"
#include "BLI_hash.hh"
#include "BLI_map.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_set.hh"
#include "BLI_user_counter.hh"
#include "BLI_vector_set.hh"
@@ -93,41 +93,64 @@ class GeometryComponent {
GeometryComponentType type() const;
- /* Return true when any attribute with this name exists, including built in attributes. */
+ /**
+ * Return true when any attribute with this name exists, including built in attributes.
+ */
bool attribute_exists(const blender::bke::AttributeIDRef &attribute_id) const;
- /* Return the data type and domain of an attribute with the given name if it exists. */
+ /**
+ * Return the data type and domain of an attribute with the given name if it exists.
+ */
std::optional<AttributeMetaData> attribute_get_meta_data(
const blender::bke::AttributeIDRef &attribute_id) const;
- /* Returns true when the geometry component supports this attribute domain. */
- bool attribute_domain_supported(const AttributeDomain domain) const;
- /* Can only be used with supported domain types. */
- virtual int attribute_domain_size(const AttributeDomain domain) const;
+ /**
+ * Return true when the geometry component supports this attribute domain.
+ * \note Conceptually this function is static, the result is always the same for different
+ * instances of the same geometry component type.
+ */
+ bool attribute_domain_supported(AttributeDomain domain) const;
+ /**
+ * Return the length of a specific domain, or 0 if the domain is not supported.
+ */
+ virtual int attribute_domain_size(AttributeDomain domain) const;
+ /**
+ * Return true if the attribute name corresponds to a built-in attribute with a hardcoded domain
+ * and data type.
+ */
bool attribute_is_builtin(const blender::StringRef attribute_name) const;
bool attribute_is_builtin(const blender::bke::AttributeIDRef &attribute_id) const;
- /* Get read-only access to the highest priority attribute with the given name.
- * Returns null if the attribute does not exist. */
+ /**
+ * Get read-only access to an attribute with the given name or id, on the highest priority domain
+ * if there is a name collision.
+ * \return null if the attribute does not exist.
+ */
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
const blender::bke::AttributeIDRef &attribute_id) const;
- /* Get read and write access to the highest priority attribute with the given name.
- * Returns null if the attribute does not exist. */
+ /**
+ * Get read and write access to an attribute with the given name or id, on the highest priority
+ * domain if there is a name collision.
+ * \note #WriteAttributeLookup.tag_modified_fn must be called after modifying data.
+ * \return null if the attribute does not exist
+ */
blender::bke::WriteAttributeLookup attribute_try_get_for_write(
const blender::bke::AttributeIDRef &attribute_id);
- /* Get a read-only attribute for the domain based on the given attribute. This can be used to
+ /**
+ * Get a read-only attribute for the domain based on the given attribute. This can be used to
* interpolate from one domain to another.
- * Returns null if the interpolation is not implemented. */
+ * \return null if the interpolation is not implemented.
+ */
blender::fn::GVArray attribute_try_adapt_domain(const blender::fn::GVArray &varray,
const AttributeDomain from_domain,
const AttributeDomain to_domain) const
{
return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain);
}
-
+ /* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
blender::VArray<T> attribute_try_adapt_domain(const blender::VArray<T> &varray,
const AttributeDomain from_domain,
@@ -137,17 +160,19 @@ class GeometryComponent {
.template typed<T>();
}
- /* Returns true when the attribute has been deleted. */
+ /** Returns true when the attribute has been deleted. */
bool attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id);
- /* Returns true when the attribute has been created. */
+ /** Returns true when the attribute has been created. */
bool attribute_try_create(const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
+ AttributeDomain domain,
const CustomDataType data_type,
const AttributeInit &initializer);
- /* Try to create the builtin attribute with the given name. No data type or domain has to be
- * provided, because those are fixed for builtin attributes. */
+ /**
+ * Try to create the builtin attribute with the given name. No data type or domain has to be
+ * provided, because those are fixed for builtin attributes.
+ */
bool attribute_try_create_builtin(const blender::StringRef attribute_name,
const AttributeInit &initializer);
@@ -160,34 +185,41 @@ class GeometryComponent {
virtual bool is_empty() const;
- /* Get a virtual array to read the data of an attribute on the given domain and data type.
- * Returns null when the attribute does not exist or cannot be converted to the requested domain
- * and data type. */
+ /**
+ * Get a virtual array that refers to the data of an attribute, interpolated to the given domain
+ * and converted to the data type. Returns null when the attribute does not exist or cannot be
+ * interpolated or converted.
+ */
blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
+ AttributeDomain domain,
const CustomDataType data_type) const;
- /* Get a virtual array to read the data of an attribute on the given domain. The data type is
- * left unchanged. Returns null when the attribute does not exist or cannot be adapted to the
- * requested domain. */
+ /**
+ * Get a virtual array that refers to the data of an attribute, interpolated to the given domain.
+ * The data type is left unchanged. Returns null when the attribute does not exist or cannot be
+ * interpolated.
+ */
blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain) const;
+ AttributeDomain domain) const;
- /* Get a virtual array to read data of an attribute with the given data type. The domain is
- * left unchanged. Returns null when the attribute does not exist or cannot be converted to the
- * requested data type. */
+ /**
+ * Get a virtual array that refers to the data of an attribute converted to the given data type.
+ * The attribute's domain is left unchanged. Returns null when the attribute does not exist or
+ * cannot be converted.
+ */
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
const blender::bke::AttributeIDRef &attribute_id, const CustomDataType data_type) const;
- /* Get a virtual array to read the data of an attribute. If that is not possible, the returned
- * virtual array will contain a default value. This never returns null. */
+ /**
+ * Get a virtual array that refers to the data of an attribute, interpolated to the given domain
+ * and converted to the data type. If that is not possible, the returned virtual array will
+ * contain a default value. This never returns null.
+ */
blender::fn::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
+ AttributeDomain domain,
const CustomDataType data_type,
const void *default_value = nullptr) const;
-
- /* Should be used instead of the method above when the requested data type is known at compile
- * time for better type safety. */
+ /* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
blender::VArray<T> attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
const AttributeDomain domain,
@@ -211,19 +243,10 @@ class GeometryComponent {
*/
blender::bke::OutputAttribute attribute_try_get_for_output(
const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
+ AttributeDomain domain,
const CustomDataType data_type,
const void *default_value = nullptr);
-
- /* Same as attribute_try_get_for_output, but should be used when the original values in the
- * attributes are not read, i.e. the attribute is used only for output. Since values are not read
- * from this attribute, no default value is necessary. */
- blender::bke::OutputAttribute attribute_try_get_for_output_only(
- const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type);
-
- /* Statically typed method corresponding to the equally named generic one. */
+ /* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output(
const blender::bke::AttributeIDRef &attribute_id,
@@ -235,7 +258,17 @@ class GeometryComponent {
return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value);
}
- /* Statically typed method corresponding to the equally named generic one. */
+ /**
+ * Same as #attribute_try_get_for_output, but should be used when the original values in the
+ * attributes are not read, i.e. the attribute is used only for output. The can be faster because
+ * it can avoid interpolation and conversion of existing values. Since values are not read from
+ * this attribute, no default value is necessary.
+ */
+ blender::bke::OutputAttribute attribute_try_get_for_output_only(
+ const blender::bke::AttributeIDRef &attribute_id,
+ AttributeDomain domain,
+ const CustomDataType data_type);
+ /* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only(
const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain)
@@ -248,10 +281,9 @@ class GeometryComponent {
private:
virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const;
- virtual blender::fn::GVArray attribute_try_adapt_domain_impl(
- const blender::fn::GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const;
+ virtual blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray,
+ AttributeDomain from_domain,
+ AttributeDomain to_domain) const;
};
template<typename T>
@@ -339,7 +371,7 @@ struct GeometrySet {
*/
blender::Vector<const GeometryComponent *> get_components_for_read() const;
- void compute_boundbox_without_instances(blender::float3 *r_min, blender::float3 *r_max) const;
+ bool compute_boundbox_without_instances(blender::float3 *r_min, blender::float3 *r_max) const;
friend std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set);
@@ -537,7 +569,7 @@ class MeshComponent : public GeometryComponent {
*/
Mesh *get_for_write();
- int attribute_domain_size(const AttributeDomain domain) const final;
+ int attribute_domain_size(AttributeDomain domain) const final;
bool is_empty() const final;
@@ -549,10 +581,9 @@ class MeshComponent : public GeometryComponent {
private:
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
- blender::fn::GVArray attribute_try_adapt_domain_impl(
- const blender::fn::GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const final;
+ blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray,
+ AttributeDomain from_domain,
+ AttributeDomain to_domain) const final;
};
/**
@@ -601,7 +632,7 @@ class PointCloudComponent : public GeometryComponent {
*/
PointCloud *get_for_write();
- int attribute_domain_size(const AttributeDomain domain) const final;
+ int attribute_domain_size(AttributeDomain domain) const final;
bool is_empty() const final;
@@ -651,7 +682,7 @@ class CurveComponent : public GeometryComponent {
const CurveEval *get_for_read() const;
CurveEval *get_for_write();
- int attribute_domain_size(const AttributeDomain domain) const final;
+ int attribute_domain_size(AttributeDomain domain) const final;
bool is_empty() const final;
@@ -669,10 +700,9 @@ class CurveComponent : public GeometryComponent {
private:
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
- blender::fn::GVArray attribute_try_adapt_domain_impl(
- const blender::fn::GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const final;
+ blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray,
+ AttributeDomain from_domain,
+ AttributeDomain to_domain) const final;
};
/**
@@ -879,7 +909,7 @@ class InstancesComponent : public GeometryComponent {
* 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);
+ GeometrySet &geometry_set_from_reference(int reference_index);
blender::Span<int> instance_reference_handles() const;
blender::MutableSpan<int> instance_reference_handles();
@@ -889,12 +919,18 @@ class InstancesComponent : public GeometryComponent {
int instances_amount() const;
int references_amount() const;
+ /**
+ * Remove the indices that are not contained in the mask input, and remove unused instance
+ * references afterwards.
+ */
+ void remove_instances(const blender::IndexMask mask);
+
blender::Span<int> almost_unique_ids() const;
blender::bke::CustomDataAttributes &attributes();
const blender::bke::CustomDataAttributes &attributes() const;
- int attribute_domain_size(const AttributeDomain domain) const final;
+ int attribute_domain_size(AttributeDomain domain) const final;
void foreach_referenced_geometry(
blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
@@ -988,7 +1024,7 @@ class GeometryFieldInput : public fn::FieldInput {
ResourceScope &scope) const override;
virtual GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ AttributeDomain domain,
IndexMask mask) const = 0;
};
@@ -1016,7 +1052,7 @@ class AttributeFieldInput : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ AttributeDomain domain,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -1033,6 +1069,30 @@ class IDAttributeFieldInput : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
+ AttributeDomain domain,
+ IndexMask mask) const override;
+
+ std::string socket_inspection_name() const override;
+
+ uint64_t hash() const override;
+ bool is_equal_to(const fn::FieldNode &other) const override;
+};
+
+VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain);
+
+VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
+ const Mesh &mesh,
+ const IndexMask mask,
+ const AttributeDomain domain);
+
+class NormalFieldInput : public GeometryFieldInput {
+ public:
+ NormalFieldInput() : GeometryFieldInput(CPPType::get<float3>())
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
const AttributeDomain domain,
IndexMask mask) const override;
@@ -1072,7 +1132,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ AttributeDomain domain,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 184ebb8e934..0c17636be03 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -50,9 +50,6 @@ typedef struct Global {
/** Last used location for library link/append. */
char lib[1024];
- /** When set: `G_MAIN->filepath` contains valid relative base path. */
- bool relbase_valid;
-
/**
* Strings of recently opened files to show in the file menu.
* A list of #RecentFile read from #BLENDER_HISTORY_FILE.
@@ -107,6 +104,7 @@ typedef struct Global {
* * 1234: Disable new dyntopo code fixing skinny faces generation (04/2015).
* * 3001: Enable additional Fluid modifier (Mantaflow) options (02/2020).
* * 4000: Line Art state output and debugging logs (03/2021).
+ * * 4001: Mesh topology information in the spreadsheet (01/2022).
* * 16384 and above: Reserved for python (add-ons) usage.
*/
short debug_value;
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index a483d482bd5..885d0c2fd90 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -151,8 +151,8 @@ struct bGPDframe *BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
*/
struct bGPDlayer *BKE_gpencil_layer_addnew(struct bGPdata *gpd,
const char *name,
- const bool setactive,
- const bool add_to_header);
+ bool setactive,
+ bool add_to_header);
/**
* Add a new grease pencil data-block.
* \param bmain: Main pointer
@@ -166,16 +166,15 @@ struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[]);
* \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);
+struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src, 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);
+ bool dup_frames,
+ bool dup_strokes);
/**
* Make a copy of a given gpencil layer settings.
*/
@@ -199,8 +198,8 @@ struct bGPDcurve *BKE_gpencil_stroke_curve_duplicate(struct bGPDcurve *gpc_src);
* \return Pointer to new stroke.
*/
struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src,
- const bool dup_points,
- const bool dup_curve);
+ bool dup_points,
+ bool dup_curve);
/**
* Make a copy of a given gpencil data-block.
@@ -252,9 +251,9 @@ void BKE_gpencil_material_remap(struct bGPdata *gpd,
* \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,
+ float hue_threshold,
+ float sat_threshold,
+ float val_threshold,
struct GHash *r_mat_table);
/**
* Merge similar materials
@@ -266,9 +265,9 @@ bool BKE_gpencil_merge_materials_table_get(struct Object *ob,
* \return True if done
*/
bool BKE_gpencil_merge_materials(struct Object *ob,
- const float hue_threshold,
- const float sat_threshold,
- const float val_threshold,
+ float hue_threshold,
+ float sat_threshold,
+ float val_threshold,
int *r_removed);
/* statistics functions */
@@ -296,7 +295,7 @@ struct bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thic
* \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);
+ struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness, bool insert_at_head);
/**
* Add a stroke and copy the temporary drawing color value
@@ -314,7 +313,7 @@ struct bGPDstroke *BKE_gpencil_stroke_add_existing_style(struct bGPDframe *gpf,
int totpoints,
short thickness);
-struct bGPDcurve *BKE_gpencil_stroke_editcurve_new(const int tot_curve_points);
+struct bGPDcurve *BKE_gpencil_stroke_editcurve_new(int tot_curve_points);
/* Stroke and Fill - Alpha Visibility Threshold */
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
@@ -398,7 +397,7 @@ void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
* \param gpd: Grease pencil data-block
* \param unlock: Unlock flag
*/
-void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, const bool unlock);
+void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, bool unlock);
/**
* Add grease pencil mask layer.
@@ -641,11 +640,8 @@ void BKE_gpencil_palette_ensure(struct Main *bmain, struct Scene *scene);
* \param mask: Mask
* \return True if done
*/
-bool BKE_gpencil_from_image(struct SpaceImage *sima,
- struct bGPdata *gpd,
- struct bGPDframe *gpf,
- const float size,
- const bool mask);
+bool BKE_gpencil_from_image(
+ struct SpaceImage *sima, struct bGPdata *gpd, struct bGPDframe *gpf, float size, bool mask);
/* Iterators */
/**
diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h
index 044e2ff2336..5c5f96c17f1 100644
--- a/source/blender/blenkernel/BKE_gpencil_curve.h
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -50,17 +50,17 @@ void BKE_gpencil_convert_curve(struct Main *bmain,
struct Scene *scene,
struct Object *ob_gp,
struct Object *ob_cu,
- const bool use_collections,
- const float scale_thickness,
- const float sample);
+ bool use_collections,
+ float scale_thickness,
+ 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);
+ float error_threshold,
+ float corner_angle,
+ float stroke_radius);
/**
* Updates the edit-curve for a stroke. Frees the old curve if one exists and generates a new one.
*/
@@ -85,13 +85,13 @@ 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);
+ uint resolution,
+ 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);
+void BKE_gpencil_editcurve_subdivide(struct bGPDstroke *gps, int cuts);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h
index 4b9671c7881..24b820b06cc 100644
--- a/source/blender/blenkernel/BKE_gpencil_geom.h
+++ b/source/blender/blenkernel/BKE_gpencil_geom.h
@@ -57,7 +57,7 @@ bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_
* \return True if it was possible to calculate
*/
bool BKE_gpencil_stroke_minmax(const struct bGPDstroke *gps,
- const bool use_select,
+ bool use_select,
float r_min[3],
float r_max[3]);
@@ -136,8 +136,8 @@ bool BKE_gpencil_stroke_trim(struct bGPdata *gpd, struct bGPDstroke *gps);
void BKE_gpencil_stroke_merge_distance(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
- const float threshold,
- const bool use_unselected);
+ float threshold,
+ bool use_unselected);
/**
* Get points of stroke always flat to view not affected
@@ -167,7 +167,7 @@ void BKE_gpencil_stroke_2d_flat_ref(const struct bGPDspoint *ref_points,
const struct bGPDspoint *points,
int totpoints,
float (*points2d)[2],
- const float scale,
+ float scale,
int *r_direction);
/**
* Triangulate stroke to generate data for filling areas.
@@ -227,8 +227,8 @@ void BKE_gpencil_point_coords_apply_with_mat4(struct bGPdata *gpd,
*/
bool BKE_gpencil_stroke_sample(struct bGPdata *gpd,
struct bGPDstroke *gps,
- const float dist,
- const bool select);
+ float dist,
+ bool select);
/**
* Apply smooth position to stroke point.
* \param gps: Stroke to smooth
@@ -236,10 +236,7 @@ bool BKE_gpencil_stroke_sample(struct bGPdata *gpd,
* \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);
+bool BKE_gpencil_stroke_smooth_point(struct bGPDstroke *gps, int i, float inf, bool smooth_caps);
/**
* Apply smooth strength to stroke point.
* \param gps: Stroke to smooth
@@ -276,7 +273,7 @@ bool BKE_gpencil_stroke_close(struct bGPDstroke *gps);
void BKE_gpencil_dissolve_points(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
- const short tag);
+ short tag);
/**
* Backbone stretch similar to Freestyle.
@@ -288,23 +285,21 @@ void BKE_gpencil_dissolve_points(struct bGPdata *gpd,
* \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,
- const short mode,
- const bool follow_curvature,
- const int extra_point_count,
- const float segment_influence,
- const float max_angle,
- const bool invert_curvature);
+ float dist,
+ float overshoot_fac,
+ short mode,
+ bool follow_curvature,
+ int extra_point_count,
+ float segment_influence,
+ float max_angle,
+ 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);
+bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps, int index_from, int index_to);
/**
* Split the given stroke into several new strokes, partitioning
* it based on whether the stroke points have a particular flag
@@ -315,9 +310,9 @@ struct bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd,
struct bGPDstroke *gps,
struct bGPDstroke *next_stroke,
int tag_flags,
- const bool select,
- const bool flat_cap,
- const int limit);
+ bool select,
+ bool flat_cap,
+ int limit);
void BKE_gpencil_curve_delete_tagged_points(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
@@ -341,7 +336,7 @@ void BKE_gpencil_stroke_flip(struct bGPDstroke *gps);
bool BKE_gpencil_stroke_split(struct bGPdata *gpd,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
- const int before_index,
+ int before_index,
struct bGPDstroke **remaining_gps);
/**
* Shrink the stroke by length.
@@ -349,7 +344,7 @@ bool BKE_gpencil_stroke_split(struct bGPdata *gpd,
* \param dist: delta length
* \param mode: 1->Start, 2->End
*/
-bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist, const short mode);
+bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, float dist, short mode);
/**
* Calculate grease pencil stroke length.
@@ -360,8 +355,8 @@ bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist, const s
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,
+ int start_index,
+ int end_index,
bool use_3d);
/**
@@ -375,9 +370,9 @@ void BKE_gpencil_stroke_set_random_color(struct bGPDstroke *gps);
*/
void BKE_gpencil_stroke_join(struct bGPDstroke *gps_a,
struct bGPDstroke *gps_b,
- const bool leave_gaps,
- const bool fit_thickness,
- const bool smooth);
+ bool leave_gaps,
+ bool fit_thickness,
+ bool smooth);
/**
* Copy the stroke of the frame to all frames selected (except current).
*/
@@ -385,7 +380,7 @@ void BKE_gpencil_stroke_copy_to_keyframes(struct bGPdata *gpd,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
- const bool tail);
+ bool tail);
/**
* Convert a mesh object to grease pencil stroke.
@@ -408,14 +403,14 @@ bool BKE_gpencil_convert_mesh(struct Main *bmain,
struct Scene *scene,
struct Object *ob_gp,
struct Object *ob_mesh,
- const float angle,
- const int thickness,
- const float offset,
+ float angle,
+ int thickness,
+ float offset,
const float matrix[4][4],
- const int frame_offset,
- const bool use_seams,
- const bool use_faces,
- const bool use_vgroups);
+ int frame_offset,
+ bool use_seams,
+ bool use_faces,
+ bool use_vgroups);
/**
* Subdivide the grease pencil stroke so the number of points is target_number.
@@ -428,8 +423,8 @@ bool BKE_gpencil_convert_mesh(struct Main *bmain,
*/
void BKE_gpencil_stroke_uniform_subdivide(struct bGPdata *gpd,
struct bGPDstroke *gps,
- const uint32_t target_number,
- const bool select);
+ uint32_t target_number,
+ bool select);
/**
* Stroke to view space
@@ -458,7 +453,7 @@ struct bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *r
struct bGPdata *gpd,
const struct bGPDlayer *gpl,
struct bGPDstroke *gps,
- const int subdivisions,
+ int subdivisions,
const float diff_mat[4][4]);
/**
* Get average pressure.
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index 5fc0abf6a2c..6df13df1c01 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -207,7 +207,7 @@ typedef struct GpencilModifierTypeInfo {
*/
void (*updateDepsgraph)(struct GpencilModifierData *md,
const struct ModifierUpdateDepsgraphContext *ctx,
- const int mode);
+ int mode);
/**
* Should return true if the modifier needs to be recalculated on time
@@ -279,7 +279,7 @@ struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
* \param md: Modifier data.
* \param flag: Flags.
*/
-void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
+void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, int flag);
/**
* Free grease pencil modifier data
* \param md: Modifier data.
@@ -324,7 +324,7 @@ void BKE_gpencil_modifier_copydata(struct GpencilModifierData *md,
*/
void BKE_gpencil_modifier_copydata_ex(struct GpencilModifierData *md,
struct GpencilModifierData *target,
- const int flag);
+ int flag);
/**
* Set grease pencil modifier error.
* \param md: Modifier data.
@@ -403,11 +403,19 @@ GpencilLineartLimitInfo BKE_gpencil_get_lineart_modifier_limits(const struct Obj
void BKE_gpencil_set_lineart_modifier_limits(struct GpencilModifierData *md,
const struct GpencilLineartLimitInfo *info,
- const bool is_first_lineart);
+ bool is_first_lineart);
bool BKE_gpencil_is_first_lineart_in_stack(const struct Object *ob,
const struct GpencilModifierData *md);
+/**
+ * Init grease pencil cache deform data.
+ * \param ob: Grease pencil object
+ */
void BKE_gpencil_cache_data_init(struct Depsgraph *depsgraph, struct Object *ob);
+/**
+ * Clear grease pencil cache deform data.
+ * \param ob: Grease pencil object
+ */
void BKE_gpencil_cache_data_clear(struct Object *ob);
/**
@@ -449,8 +457,8 @@ int BKE_gpencil_time_modifier_cfra(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bGPDlayer *gpl,
- const int cfra,
- const bool is_render);
+ int cfra,
+ bool is_render);
void BKE_gpencil_modifier_blend_write(struct BlendWriter *writer, struct ListBase *modbase);
void BKE_gpencil_modifier_blend_read_data(struct BlendDataReader *reader, struct ListBase *lb);
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index c96a37e0d09..a65cdcd23af 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -123,13 +123,13 @@ struct ImBuf *BKE_icon_imbuf_get_buffer(int icon_id) ATTR_WARN_UNUSED_RESULT;
/**
* Retrieve icon for id.
*/
-struct Icon *BKE_icon_get(const int icon_id);
+struct Icon *BKE_icon_get(int icon_id);
/**
* 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);
+void BKE_icon_set(int icon_id, struct Icon *icon);
/**
* Remove icon and free data if library object becomes invalid.
@@ -139,13 +139,13 @@ 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);
+bool BKE_icon_delete(int icon_id);
+bool BKE_icon_delete_unmanaged(int icon_id);
/**
* Report changes - icon needs to be recalculated.
*/
-void BKE_icon_changed(const int icon_id);
+void BKE_icon_changed(int icon_id);
/**
* Free all icons.
@@ -220,16 +220,16 @@ 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);
+void BKE_previewimg_ensure(struct PreviewImage *prv, 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);
+struct ImBuf *BKE_previewimg_to_imbuf(struct PreviewImage *prv, int size);
-void BKE_previewimg_finish(struct PreviewImage *prv, const int size);
-bool BKE_previewimg_is_finished(const struct PreviewImage *prv, const int size);
+void BKE_previewimg_finish(struct PreviewImage *prv, int size);
+bool BKE_previewimg_is_finished(const struct PreviewImage *prv, int size);
struct PreviewImage *BKE_previewimg_cached_get(const char *name);
@@ -244,7 +244,7 @@ struct PreviewImage *BKE_previewimg_cached_ensure(const char *name);
*/
struct PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name,
const char *path,
- const int source,
+ int source,
bool force_update);
void BKE_previewimg_cached_release(const char *name);
@@ -259,8 +259,8 @@ struct Icon_Geom *BKE_icon_geom_from_memory(uchar *data, size_t data_len);
struct Icon_Geom *BKE_icon_geom_from_file(const char *filename);
struct ImBuf *BKE_icon_geom_rasterize(const struct Icon_Geom *geom,
- const unsigned int size_x,
- const unsigned int size_y);
+ unsigned int size_x,
+ unsigned int size_y);
void BKE_icon_geom_invert_lightness(struct Icon_Geom *geom);
int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type);
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 1fb3636e9fd..b0b981e49f0 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -62,7 +62,7 @@ typedef union IDPropertyTemplate {
*/
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();
+ int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Shallow copies item.
@@ -102,7 +102,7 @@ void IDP_FreeString(struct IDProperty *prop) ATTR_NONNULL();
typedef void (*IDPWalkFunc)(void *userData, struct IDProperty *idp);
-void IDP_AssignID(struct IDProperty *prop, struct ID *id, const int flag);
+void IDP_AssignID(struct IDProperty *prop, struct ID *id, int flag);
/*-------- Group Functions -------*/
@@ -113,9 +113,8 @@ void IDP_AssignID(struct IDProperty *prop, struct ID *id, const int flag);
* \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();
+void IDP_SyncGroupTypes(struct IDProperty *dest, const struct IDProperty *src, bool do_arraylen)
+ ATTR_NONNULL();
/**
* Replaces all properties with the same name in a destination group from a source group.
*/
@@ -132,7 +131,7 @@ void IDP_ReplaceInGroup_ex(struct IDProperty *group,
* 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)
+void IDP_MergeGroup(struct IDProperty *dest, const struct IDProperty *src, bool do_overwrite)
ATTR_NONNULL();
/**
* If a property is missing in \a dest, add it.
@@ -140,8 +139,8 @@ void IDP_MergeGroup(struct IDProperty *dest, const struct IDProperty *src, const
*/
void IDP_MergeGroup_ex(struct IDProperty *dest,
const struct IDProperty *src,
- const bool do_overwrite,
- const int flag) ATTR_NONNULL();
+ bool do_overwrite,
+ 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.
@@ -180,8 +179,7 @@ struct IDProperty *IDP_GetPropertyFromGroup(const struct IDProperty *prop,
*/
struct IDProperty *IDP_GetPropertyTypeFromGroup(const struct IDProperty *prop,
const char *name,
- const char type) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+ char type) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/*-------- Main Functions --------*/
/**
@@ -190,13 +188,12 @@ struct IDProperty *IDP_GetPropertyTypeFromGroup(const struct IDProperty *prop,
* \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
+struct IDProperty *IDP_GetProperties(struct ID *id, bool create_if_needed) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
struct IDProperty *IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
struct IDProperty *IDP_CopyProperty_ex(const struct IDProperty *prop,
- const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Copy content from source #IDProperty into destination one,
* freeing destination property's content first.
@@ -208,7 +205,7 @@ void IDP_CopyPropertyContent(struct IDProperty *dst, struct IDProperty *src) ATT
*/
bool IDP_EqualsProperties_ex(struct IDProperty *prop1,
struct IDProperty *prop2,
- const bool is_strict) ATTR_WARN_UNUSED_RESULT;
+ bool is_strict) ATTR_WARN_UNUSED_RESULT;
bool IDP_EqualsProperties(struct IDProperty *prop1,
struct IDProperty *prop2) ATTR_WARN_UNUSED_RESULT;
@@ -240,7 +237,7 @@ bool IDP_EqualsProperties(struct IDProperty *prop1,
* IDP_AddToGroup or MEM_freeN the property, doing anything else might result in
* a memory leak.
*/
-struct IDProperty *IDP_New(const char type,
+struct IDProperty *IDP_New(char type,
const IDPropertyTemplate *val,
const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -248,9 +245,9 @@ struct IDProperty *IDP_New(const char type,
* \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_ex(struct IDProperty *prop, bool do_id_user);
void IDP_FreePropertyContent(struct IDProperty *prop);
-void IDP_FreeProperty_ex(struct IDProperty *prop, const bool do_id_user);
+void IDP_FreeProperty_ex(struct IDProperty *prop, bool do_id_user);
void IDP_FreeProperty(struct IDProperty *prop);
void IDP_ClearProperty(struct IDProperty *prop);
@@ -319,7 +316,7 @@ typedef void (*IDPForeachPropertyCallback)(struct IDProperty *id_property, void
* IDP_TYPE_FILTER_ enum in DNA_ID.h.
*/
void IDP_foreach_property(struct IDProperty *id_property_root,
- const int type_filter,
+ int type_filter,
IDPForeachPropertyCallback callback,
void *user_data);
diff --git a/source/blender/blenkernel/BKE_idprop.hh b/source/blender/blenkernel/BKE_idprop.hh
new file mode 100644
index 00000000000..782fa9c7404
--- /dev/null
+++ b/source/blender/blenkernel/BKE_idprop.hh
@@ -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.
+ */
+
+#pragma once
+
+#include "BKE_idprop.h"
+
+#include "BLI_serialize.hh"
+#include "BLI_span.hh"
+
+namespace blender::bke::idprop {
+
+/**
+ * \brief Convert the given `properties` to `Value` objects for serialization.
+ *
+ * `IDP_ID` and `IDP_IDPARRAY` are not supported and will be ignored.
+ *
+ * UI data such as max/min will not be serialized.
+ */
+std::unique_ptr<io::serialize::ArrayValue> convert_to_serialize_values(
+ const IDProperty *properties);
+
+/**
+ * \brief Convert the given `value` to an `IDProperty`.
+ */
+IDProperty *convert_from_serialize_value(const blender::io::serialize::Value &value);
+
+class IDPropertyDeleter {
+ public:
+ void operator()(IDProperty *id_prop)
+ {
+ IDP_FreeProperty(id_prop);
+ }
+};
+
+/** \brief Allocate a new IDProperty of type IDP_INT, set its name and value. */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, int32_t value);
+
+/** \brief Allocate a new IDProperty of type IDP_FLOAT, set its name and value. */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, float value);
+
+/** \brief Allocate a new IDProperty of type IDP_DOUBLE, set its name and value. */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, double value);
+
+/** \brief Allocate a new IDProperty of type IDP_STRING, set its name and value. */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name,
+ const StringRefNull value);
+
+/**
+ * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_INT.
+ *
+ * \param values: The values will be copied into the IDProperty.
+ */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name,
+ Span<int32_t> values);
+
+/**
+ * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_FLOAT.
+ *
+ * \param values: The values will be copied into the IDProperty.
+ */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, Span<float> values);
+
+/**
+ * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_DOUBLE.
+ *
+ * \param values: The values will be copied into the IDProperty.
+ */
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name,
+ Span<double> values);
+
+/**
+ * \brief Allocate a new IDProperty of type IDP_GROUP.
+ *
+ * \param prop_name: The name of the newly created property.
+ */
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create_group(StringRefNull prop_name);
+
+} // namespace blender::bke::idprop
diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index 8cd5d2a2361..df50f773a46 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -31,11 +31,11 @@
extern "C" {
#endif
+struct BPathForeachPathData;
struct BlendDataReader;
struct BlendExpander;
struct BlendLibReader;
struct BlendWriter;
-struct BPathForeachPathData;
struct ID;
struct LibraryForeachIDData;
struct Main;
@@ -78,12 +78,12 @@ typedef void (*IDTypeInitDataFunction)(struct ID *id);
typedef void (*IDTypeCopyDataFunction)(struct Main *bmain,
struct ID *id_dst,
const struct ID *id_src,
- const int flag);
+ int flag);
typedef void (*IDTypeFreeDataFunction)(struct ID *id);
/** \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 (*IDTypeMakeLocalFunction)(struct Main *bmain, struct ID *id, int flags);
typedef void (*IDTypeForeachIDFunction)(struct ID *id, struct LibraryForeachIDData *data);
@@ -292,7 +292,7 @@ extern IDTypeInfo IDType_ID_LINK_PLACEHOLDER;
void BKE_idtype_init(void);
/* General helpers. */
-const struct IDTypeInfo *BKE_idtype_get_info_from_idcode(const short id_code);
+const struct IDTypeInfo *BKE_idtype_get_info_from_idcode(short id_code);
const struct IDTypeInfo *BKE_idtype_get_info_from_id(const struct ID *id);
/**
@@ -301,21 +301,21 @@ const struct IDTypeInfo *BKE_idtype_get_info_from_id(const struct ID *id);
* \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 char *BKE_idtype_idcode_to_name(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);
+const char *BKE_idtype_idcode_to_name_plural(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);
+const char *BKE_idtype_idcode_to_translation_context(short idcode);
/**
* Return if the ID code is a valid ID code.
@@ -323,7 +323,7 @@ const char *BKE_idtype_idcode_to_translation_context(const short idcode);
* \param idcode: The code to check.
* \return Boolean, 0 when invalid.
*/
-bool BKE_idtype_idcode_is_valid(const short idcode);
+bool BKE_idtype_idcode_is_valid(short idcode);
/**
* Check if an ID type is linkable.
@@ -331,21 +331,21 @@ bool BKE_idtype_idcode_is_valid(const short idcode);
* \param idcode: The IDType code to check.
* \return Boolean, false when non linkable, true otherwise.
*/
-bool BKE_idtype_idcode_is_linkable(const short idcode);
+bool BKE_idtype_idcode_is_linkable(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);
+bool BKE_idtype_idcode_is_only_appendable(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);
+bool BKE_idtype_idcode_append_is_reusable(short idcode);
/* Macro currently, since any linkable IDtype should be localizable. */
#define BKE_idtype_idcode_is_localizable BKE_idtype_idcode_is_linkable
@@ -360,20 +360,20 @@ 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);
+uint64_t BKE_idtype_idcode_to_idfilter(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);
+short BKE_idtype_idcode_from_idfilter(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);
+int BKE_idtype_idcode_to_index(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);
+short BKE_idtype_idcode_from_index(int index);
/**
* Return an ID code and steps the index forward 1.
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 0d1ebbf0dc9..d3afd655d8c 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -38,6 +38,7 @@ struct ImageFormatData;
struct ImagePool;
struct ImageTile;
struct ImbFormatOptions;
+struct ListBase;
struct Main;
struct Object;
struct RenderResult;
@@ -114,35 +115,35 @@ int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, const struct ImageForm
int BKE_imbuf_write_as(struct ImBuf *ibuf,
const char *name,
struct ImageFormatData *imf,
- const bool save_copy);
+ bool save_copy);
void BKE_image_path_from_imformat(char *string,
const char *base,
const char *relbase,
int frame,
const struct ImageFormatData *im_format,
- const bool use_ext,
- const bool use_frames,
+ bool use_ext,
+ bool use_frames,
const char *suffix);
void BKE_image_path_from_imtype(char *string,
const char *base,
const char *relbase,
int frame,
- const char imtype,
- const bool use_ext,
- const bool use_frames,
+ char imtype,
+ bool use_ext,
+ bool use_frames,
const char *suffix);
int BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
-int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype);
-char BKE_image_ftype_to_imtype(const int ftype, const struct ImbFormatOptions *options);
-int BKE_image_imtype_to_ftype(const char imtype, struct ImbFormatOptions *r_options);
+int BKE_image_path_ensure_ext_from_imtype(char *string, char imtype);
+char BKE_image_ftype_to_imtype(int ftype, const struct ImbFormatOptions *options);
+int BKE_image_imtype_to_ftype(char imtype, struct ImbFormatOptions *r_options);
-bool BKE_imtype_is_movie(const char imtype);
-bool BKE_imtype_supports_zbuf(const char imtype);
-bool BKE_imtype_supports_compress(const char imtype);
-bool BKE_imtype_supports_quality(const char imtype);
-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);
+bool BKE_imtype_is_movie(char imtype);
+bool BKE_imtype_supports_zbuf(char imtype);
+bool BKE_imtype_supports_compress(char imtype);
+bool BKE_imtype_supports_quality(char imtype);
+bool BKE_imtype_requires_linear_float(char imtype);
+char BKE_imtype_valid_channels(char imtype, bool write_file);
+char BKE_imtype_valid_depths(char imtype);
/**
* String is from command line `--render-format` argument,
@@ -242,9 +243,9 @@ struct Image *BKE_image_add_generated(struct Main *bmain,
int floatbuf,
short gen_type,
const float color[4],
- const bool stereo3d,
- const bool is_data,
- const bool tiled);
+ bool stereo3d,
+ bool is_data,
+ bool tiled);
/**
* 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.
@@ -286,6 +287,10 @@ void BKE_image_ensure_viewer_views(const struct RenderData *rd,
void BKE_image_user_frame_calc(struct Image *ima, struct ImageUser *iuser, int cfra);
int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, bool *r_is_in_range);
void BKE_image_user_file_path(struct ImageUser *iuser, struct Image *ima, char *path);
+void BKE_image_user_file_path_ex(struct ImageUser *iuser,
+ struct Image *ima,
+ char *path,
+ bool resolve_udim);
void BKE_image_editors_update_frame(const struct Main *bmain, int cfra);
/**
@@ -331,7 +336,7 @@ void BKE_image_backup_render(struct Scene *scene, struct Image *ima, bool free_c
bool BKE_image_save_openexr_multiview(struct Image *ima,
struct ImBuf *ibuf,
const char *filepath,
- const int flags);
+ int flags);
/**
* Goes over all textures that use images.
@@ -364,7 +369,7 @@ void BKE_image_packfiles(struct ReportList *reports, struct Image *ima, const ch
void BKE_image_packfiles_from_mem(struct ReportList *reports,
struct Image *ima,
char *data,
- const size_t data_len);
+ size_t data_len);
/**
* Prints memory statistics for images.
@@ -399,6 +404,18 @@ void BKE_image_get_tile_label(struct Image *ima,
char *label,
int len_label);
+/**
+ * Checks whether the given filepath refers to a UDIM tiled texture.
+ * If yes, the range from the lowest to the highest tile is returned.
+ *
+ * `filepath` may be modified to ensure a UDIM token is present.
+ * `tiles` may be filled even if the result ultimately is false!
+ */
+bool BKE_image_get_tile_info(char *filepath,
+ struct ListBase *tiles,
+ int *tile_start,
+ int *tile_range);
+
struct ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label);
bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile);
void BKE_image_reassign_tile(struct Image *ima, struct ImageTile *tile, int new_tile_number);
@@ -413,6 +430,41 @@ bool BKE_image_fill_tile(struct Image *ima,
int planes,
bool is_float);
+typedef enum {
+ UDIM_TILE_FORMAT_NONE = 0,
+ UDIM_TILE_FORMAT_UDIM = 1,
+ UDIM_TILE_FORMAT_UVTILE = 2
+} eUDIM_TILE_FORMAT;
+
+/**
+ * Ensures that `filename` contains a UDIM token if we find a supported format pattern.
+ * \note This must only be the name component (without slashes).
+ */
+void BKE_image_ensure_tile_token(char *filename);
+
+/**
+ * When provided with an absolute virtual filepath, check to see if at least
+ * one concrete file exists.
+ * Note: This function requires directory traversal and may be inefficient in time-critical,
+ * or iterative, code paths.
+ */
+bool BKE_image_tile_filepath_exists(const char *filepath);
+
+/**
+ * Retrieves the UDIM token format and returns the pattern from the provided `filepath`.
+ * The returned pattern is typically passed to either `BKE_image_get_tile_number_from_filepath` or
+ * `BKE_image_set_filepath_from_tile_number`.
+ */
+char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format);
+bool BKE_image_get_tile_number_from_filepath(const char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int *r_tile_number);
+void BKE_image_set_filepath_from_tile_number(char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int tile_number);
+
struct ImageTile *BKE_image_get_tile(struct Image *ima, int tile_number);
struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, const struct ImageUser *iuser);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index de069d6236f..07e816558df 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -68,16 +68,16 @@ 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_from_shape(const struct Key *key, 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_from_shape(const struct Key *key, int shape_index);
size_t BKE_keyblock_element_calc_size(const struct Key *key);
-bool BKE_key_idtype_support(const short id_type);
+bool BKE_key_idtype_support(short id_type);
struct Key **BKE_key_from_id_p(struct ID *id);
struct Key *BKE_key_from_id(struct ID *id);
@@ -98,7 +98,7 @@ struct KeyBlock *BKE_keyblock_add(struct Key *key, const char *name);
* \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);
+struct KeyBlock *BKE_keyblock_add_ctime(struct Key *key, const char *name, bool do_force);
/**
* Get the appropriate #KeyBlock given an index.
*/
@@ -113,7 +113,7 @@ struct KeyBlock *BKE_keyblock_find_name(struct Key *key, const char name[]);
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.
+ * \note the user needs to free the returned string once they're finished with it.
*/
char *BKE_keyblock_curval_rnapath_get(struct Key *key, struct KeyBlock *kb);
@@ -179,7 +179,7 @@ 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);
+bool BKE_keyblock_is_basis(struct Key *key, int index);
/* -------------------------------------------------------------------- */
/** \name Key-Block Data Access
@@ -188,16 +188,14 @@ bool BKE_keyblock_is_basis(struct Key *key, const int index);
/**
* \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_from_shape(const struct Key *key, float (*arr)[3], 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,
+ int shape_index,
const float (*coords)[3],
const float mat[4][4]);
/**
@@ -206,13 +204,13 @@ void BKE_keyblock_data_set_with_mat4(struct Key *key,
*/
void BKE_keyblock_curve_data_set_with_mat4(struct Key *key,
const struct ListBase *nurb,
- const int shape_index,
+ 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);
+void BKE_keyblock_data_set(struct Key *key, int shape_index, const void *data);
/** \} */
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index bf03e99bbc3..35260aa3852 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -69,15 +69,11 @@ void BKE_lattice_transform(struct Lattice *lt, const float mat[4][4], bool do_ke
bool BKE_lattice_is_any_selected(const struct Lattice *lt);
-int BKE_lattice_index_from_uvw(struct Lattice *lt, const int u, const int v, const int w);
-void BKE_lattice_index_to_uvw(struct Lattice *lt, const int index, int *r_u, int *r_v, int *r_w);
-int BKE_lattice_index_flip(
- struct Lattice *lt, const int index, const bool flip_u, const bool flip_v, const bool flip_w);
-void BKE_lattice_bitmap_from_flag(struct Lattice *lt,
- unsigned int *bitmap,
- const uint8_t flag,
- const bool clear,
- const bool respecthide);
+int BKE_lattice_index_from_uvw(struct Lattice *lt, int u, int v, int w);
+void BKE_lattice_index_to_uvw(struct Lattice *lt, int index, int *r_u, int *r_v, int *r_w);
+int BKE_lattice_index_flip(struct Lattice *lt, int index, bool flip_u, bool flip_v, bool flip_w);
+void BKE_lattice_bitmap_from_flag(
+ struct Lattice *lt, unsigned int *bitmap, uint8_t flag, bool clear, bool respecthide);
/* **** Depsgraph evaluation **** */
@@ -110,27 +106,27 @@ void BKE_lattice_deform_data_destroy(struct LatticeDeformData *lattice_deform_da
void BKE_lattice_deform_coords(const struct Object *ob_lattice,
const struct Object *ob_target,
float (*vert_coords)[3],
- const int vert_coords_len,
- const short flag,
+ int vert_coords_len,
+ short flag,
const char *defgrp_name,
float fac);
void BKE_lattice_deform_coords_with_mesh(const struct Object *ob_lattice,
const struct Object *ob_target,
float (*vert_coords)[3],
- const int vert_coords_len,
- const short flag,
+ int vert_coords_len,
+ short flag,
const char *defgrp_name,
- const float fac,
+ float fac,
const struct Mesh *me_target);
void BKE_lattice_deform_coords_with_editmesh(const struct Object *ob_lattice,
const struct Object *ob_target,
float (*vert_coords)[3],
- const int vert_coords_len,
- const short flag,
+ int vert_coords_len,
+ short flag,
const char *defgrp_name,
- const float fac,
+ float fac,
struct BMEditMesh *em_target);
/** \} */
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index b2fa464aedc..accdfe1ca25 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -71,7 +71,7 @@ struct ViewLayer *BKE_view_layer_find(const struct Scene *scene, const char *lay
struct ViewLayer *BKE_view_layer_add(struct Scene *scene,
const char *name,
struct ViewLayer *view_layer_source,
- const int type);
+ int type);
/* DEPRECATED */
/**
@@ -85,12 +85,12 @@ 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);
+void BKE_view_layer_free_ex(struct ViewLayer *view_layer, 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);
+void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, int tag);
/**
* Fallback for when a Scene has no camera to use.
@@ -119,7 +119,7 @@ void BKE_view_layer_copy_data(struct Scene *scene_dst,
const struct Scene *scene_src,
struct ViewLayer *view_layer_dst,
const struct ViewLayer *view_layer_src,
- const int flag);
+ int flag);
void BKE_view_layer_rename(struct Main *bmain,
struct Scene *scene,
@@ -148,8 +148,7 @@ 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);
+struct LayerCollection *BKE_layer_collection_from_index(struct ViewLayer *view_layer, int index);
/**
* \return -1 if not found.
*/
@@ -158,6 +157,14 @@ int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct La
void BKE_layer_collection_resync_forbid(void);
void BKE_layer_collection_resync_allow(void);
+/**
+ * Helper to fix older pre-2.80 blend-files.
+ *
+ * Ensures the given `view_layer` as a valid first-level layer collection, i.e. a single one
+ * matching the scene's master collection. This is a requirement for `BKE_layer_collection_sync`.
+ */
+void BKE_layer_collection_doversion_2_80(const struct Scene *scene, struct ViewLayer *view_layer);
+
void BKE_main_collection_sync(const struct Main *bmain);
void BKE_scene_collection_sync(const struct Scene *scene);
/**
@@ -242,9 +249,9 @@ void BKE_layer_collection_isolate_local(struct ViewLayer *view_layer,
*/
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);
+ bool visible,
+ bool hierarchy);
+void BKE_layer_collection_set_flag(struct LayerCollection *lc, int flag, bool value);
/* Evaluation. */
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 34339c4ff9f..ebd35cad965 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -77,7 +77,7 @@ void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT;
* 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)
+void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, int flag)
ATTR_WARN_UNUSED_RESULT;
/**
* Initialize an ID of given type, such that it has valid 'empty' data.
@@ -114,14 +114,14 @@ void BKE_lib_libblock_session_uuid_renew(struct ID *id);
*
* \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);
+void *BKE_id_new(struct Main *bmain, 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);
+void *BKE_id_new_nomain(short type, const char *name);
/**
* New ID creation/copying options.
@@ -202,7 +202,7 @@ enum {
void BKE_libblock_copy_ex(struct Main *bmain,
const struct ID *id,
struct ID **r_newid,
- const int orig_flag);
+ int orig_flag);
/**
* Used everywhere in blenkernel.
*/
@@ -220,7 +220,7 @@ void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) AT
void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL();
struct ID *BKE_libblock_find_name(struct Main *bmain,
- const short type,
+ short type,
const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
struct ID *BKE_libblock_find_session_uuid(struct Main *bmain, short type, uint32_t session_uuid);
/**
@@ -267,8 +267,8 @@ enum {
LIB_ID_FREE_NO_UI_USER = 1 << 9,
};
-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();
+void BKE_libblock_free_datablock(struct ID *id, int flag) ATTR_NONNULL();
+void BKE_libblock_free_data(struct ID *id, bool do_id_user) ATTR_NONNULL();
/**
* In most cases #BKE_id_free_ex handles this, when lower level functions are called directly
@@ -295,7 +295,7 @@ void BKE_libblock_free_data_py(struct ID *id);
* \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);
+void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, bool use_flag_from_idtag);
/**
* Complete ID freeing, should be usable in most cases (even for out-of-Main IDs).
*
@@ -383,9 +383,19 @@ enum {
};
/**
+ * Helper to decide whether given `id` can be directly made local, or needs to be copied.
+ * `r_force_local` and `r_force_copy` cannot be true together. But both can be false, in case no
+ * action should be performed.
+ *
+ * \note low-level helper to de-duplicate logic between `BKE_lib_id_make_local_generic` and the
+ * specific corner-cases implementations needed for objects and brushes.
+ */
+void BKE_lib_id_make_local_generic_action_define(
+ struct Main *bmain, struct ID *id, int flags, bool *r_force_local, bool *r_force_copy);
+/**
* 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);
+void BKE_lib_id_make_local_generic(struct Main *bmain, struct ID *id, int flags);
/**
* Calls the appropriate make_local method for the block, unless test is set.
*
@@ -395,7 +405,7 @@ void BKE_lib_id_make_local_generic(struct Main *bmain, struct ID *id, const int
* 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);
+bool BKE_lib_id_make_local(struct Main *bmain, struct ID *id, int flags);
/**
* \note Does *not* set #ID.newid pointer.
*/
@@ -431,18 +441,15 @@ struct ID *BKE_id_copy(struct Main *bmain, const struct ID *id);
* (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);
+struct ID *BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, 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);
+ uint duplicate_flags,
+ int copy_flags);
/**
* Does a mere memory swap over the whole IDs data (including type-specific memory).
@@ -474,7 +481,7 @@ void id_sort_by_name(struct ListBase *lb, struct ID *id, struct ID *id_sorting_h
* 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);
+void BKE_lib_id_expand_local(struct Main *bmain, struct ID *id, int flags);
/**
* Ensures given ID has a unique name in given listbase.
@@ -489,48 +496,45 @@ void BKE_lib_id_expand_local(struct Main *bmain, struct ID *id, const int flags)
bool BKE_id_new_name_validate(struct ListBase *lb,
struct ID *id,
const char *name,
- const bool do_linked_data) ATTR_NONNULL(1, 2);
+ 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);
+void BKE_lib_id_clear_library_data(struct Main *bmain, struct ID *id, int flags);
/**
* 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);
+void BKE_main_id_tag_idcode(struct Main *mainvar, short type, int tag, 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);
+void BKE_main_id_tag_listbase(struct ListBase *lb, int tag, 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);
+void BKE_main_id_tag_all(struct Main *mainvar, int tag, 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);
+void BKE_main_id_flag_listbase(struct ListBase *lb, int flag, 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);
+void BKE_main_id_flag_all(struct Main *bmain, int flag, 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_id_refcount_recompute(struct Main *bmain, bool do_linked_only);
void BKE_main_lib_objects_recalc_all(struct Main *bmain);
@@ -567,7 +571,7 @@ void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const struct ID *id, char
*/
void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI],
const struct ID *id,
- const bool add_lib_hint,
+ bool add_lib_hint,
char separator_char,
int *r_prefix_len);
@@ -591,8 +595,8 @@ char *BKE_id_to_unique_string_key(const struct ID *id);
void BKE_library_make_local(struct Main *bmain,
const struct Library *lib,
struct GHash *old_to_new_ids,
- const bool untagged_only,
- const bool set_fake);
+ bool untagged_only,
+ bool set_fake);
void BKE_id_tag_set_atomic(struct ID *id, int tag);
void BKE_id_tag_clear_atomic(struct ID *id, int tag);
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index 1c30db7a714..30e75259967 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -65,17 +65,15 @@ struct IDOverrideLibrary *BKE_lib_override_library_init(struct ID *local_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);
+void BKE_lib_override_library_copy(struct ID *dst_id, const struct ID *src_id, 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);
+void BKE_lib_override_library_clear(struct IDOverrideLibrary *override, bool do_id_user);
/**
* Free given \a override.
*/
-void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user);
+void BKE_lib_override_library_free(struct IDOverrideLibrary **override, bool do_id_user);
/**
* Check if given ID has some override rules that actually indicate the user edited it.
@@ -84,10 +82,13 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id);
/**
* Create an overridden local copy of linked reference.
+ *
+ * \note This function is very basic, low-level. It does not consider any hierarchical dependency,
+ * and also prevents any automatic re-sync of this local override.
*/
struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
struct ID *reference_id,
- const bool do_tagged_remap);
+ bool do_tagged_remap);
/**
* Create overridden local copies of all tagged data-blocks in given Main.
*
@@ -109,7 +110,7 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
*/
bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
const struct Library *reference_library,
- const bool do_no_main);
+ bool do_no_main);
/**
* Advanced 'smart' function to create fully functional overrides.
*
@@ -163,9 +164,9 @@ void BKE_lib_override_library_main_proxy_convert(struct Main *bmain,
* 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).
+ * \param id_root: The root liboverride ID to resync from.
* \return true if override was successfully resynced.
*/
bool BKE_lib_override_library_resync(struct Main *bmain,
@@ -173,8 +174,7 @@ bool BKE_lib_override_library_resync(struct Main *bmain,
struct ViewLayer *view_layer,
struct ID *id_root,
struct Collection *override_resync_residual_storage,
- const bool do_hierarchy_enforce,
- const bool do_post_process,
+ bool do_hierarchy_enforce,
struct BlendFileReadReport *reports);
/**
* Detect and handle required resync of overrides data, when relations between reference linked IDs
@@ -250,21 +250,21 @@ struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_ope
struct IDOverrideLibraryProperty *override_property,
const char *subitem_refname,
const char *subitem_locname,
- const int subitem_refindex,
- const int subitem_locindex,
- const bool strict,
+ int subitem_refindex,
+ int subitem_locindex,
+ 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,
+ short operation,
const char *subitem_refname,
const char *subitem_locname,
- const int subitem_refindex,
- const int subitem_locindex,
- const bool strict,
+ int subitem_refindex,
+ int subitem_locindex,
+ bool strict,
bool *r_strict,
bool *r_created);
/**
@@ -306,7 +306,8 @@ void BKE_lib_override_library_main_validate(struct Main *bmain, struct ReportLis
* 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. */
+ * \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.
@@ -317,7 +318,8 @@ bool BKE_lib_override_library_status_check_local(struct Main *bmain, struct ID *
* 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. */
+ * \return true if status is OK, false otherwise.
+ */
bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct ID *local);
/**
@@ -338,7 +340,7 @@ bool BKE_lib_override_library_operations_create(struct Main *bmain, struct ID *l
/**
* 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);
+bool BKE_lib_override_library_main_operations_create(struct Main *bmain, bool force_auto);
/**
* Reset all overrides in given \a id_root, while preserving ID relations.
@@ -353,18 +355,18 @@ void BKE_lib_override_library_id_hierarchy_reset(struct Main *bmain, struct ID *
* 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);
+ short tag,
+ 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);
+ short tag,
+ 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);
+void BKE_lib_override_library_main_tag(struct Main *bmain, short tag, bool do_set);
/**
* Remove all tagged-as-unused properties and operations from that ID override data.
diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h
index 91f72cc0762..d853cb16b13 100644
--- a/source/blender/blenkernel/BKE_lib_query.h
+++ b/source/blender/blenkernel/BKE_lib_query.h
@@ -153,8 +153,8 @@ void BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data,
int cb_flag);
int BKE_lib_query_foreachid_process_flags_get(struct LibraryForeachIDData *data);
int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeachIDData *data,
- const int cb_flag,
- const bool do_replace);
+ int cb_flag,
+ bool do_replace);
#define BKE_LIB_FOREACHID_PROCESS_ID(_data, _id, _cb_flag) \
{ \
@@ -202,7 +202,7 @@ void BKE_library_foreach_ID_link(
/**
* 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);
+void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, int cb_flag);
/**
* Return the number of times given \a id_user uses/references \a id_used.
@@ -222,7 +222,7 @@ int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_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);
+bool BKE_library_id_can_use_idtype(struct ID *id_owner, short id_type_used);
/**
* Check whether given ID is used locally (i.e. by another non-linked ID).
@@ -257,10 +257,10 @@ void BKE_library_ID_test_usages(struct Main *bmain,
* #INDEX_ID_NULL item.
*/
void BKE_lib_query_unused_ids_tag(struct Main *bmain,
- const int tag,
- const bool do_local_ids,
- const bool do_linked_ids,
- const bool do_tag_recursive,
+ int tag,
+ bool do_local_ids,
+ bool do_linked_ids,
+ bool do_tag_recursive,
int *r_num_tagged);
/**
@@ -272,7 +272,7 @@ void BKE_lib_query_unused_ids_tag(struct Main *bmain,
* \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);
+void BKE_library_unused_linked_data_set_tag(struct Main *bmain, 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
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index 9c8caa0266b..cc970342fbb 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -38,6 +38,9 @@
extern "C" {
#endif
+struct ID;
+struct IDRemapper;
+
/* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */
/* Also IDRemap->flag. */
@@ -98,17 +101,28 @@ enum {
};
/**
+ * Replace all references in given Main using the given \a mappings
+ *
+ * \note Is preferred over BKE_libblock_remap_locked due to performance.
+ */
+void BKE_libblock_remap_multiple_locked(struct Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags);
+
+void BKE_libblock_remap_multiple(struct Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags);
+
+/**
* 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,
- const short remap_flags) ATTR_NONNULL(1, 2);
-void BKE_libblock_remap(struct Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
+void BKE_libblock_remap_locked(struct Main *bmain, void *old_idv, void *new_idv, short remap_flags)
+ ATTR_NONNULL(1, 2);
+void BKE_libblock_remap(struct Main *bmain, void *old_idv, void *new_idv, short remap_flags)
ATTR_NONNULL(1, 2);
/**
@@ -120,8 +134,8 @@ void BKE_libblock_remap(struct Main *bmain, void *old_idv, void *new_idv, const
*/
void BKE_libblock_unlink(struct Main *bmain,
void *idv,
- const bool do_flag_never_null,
- const bool do_skip_indirect) ATTR_NONNULL();
+ bool do_flag_never_null,
+ bool do_skip_indirect) ATTR_NONNULL();
/**
* Similar to libblock_remap, but only affects IDs used by given \a idv ID.
@@ -133,7 +147,7 @@ void BKE_libblock_relink_ex(struct Main *bmain,
void *idv,
void *old_idv,
void *new_idv,
- const short remap_flags) ATTR_NONNULL(1, 2);
+ short remap_flags) ATTR_NONNULL(1, 2);
/**
* Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
@@ -144,16 +158,65 @@ void BKE_libblock_relink_ex(struct Main *bmain,
* 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)
+void BKE_libblock_relink_to_newid(struct Main *bmain, struct ID *id, int remap_flag)
ATTR_NONNULL();
typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
-typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *);
+typedef void (*BKE_library_remap_editor_id_reference_cb)(const struct IDRemapper *mappings);
void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
void BKE_library_callback_remap_editor_id_reference_set(
BKE_library_remap_editor_id_reference_cb func);
+/* IDRemapper */
+struct IDRemapper;
+typedef enum IDRemapperApplyResult {
+ /** No remapping rules available for the source. */
+ ID_REMAP_RESULT_SOURCE_UNAVAILABLE,
+ /** Source isn't mappable (e.g. NULL). */
+ ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE,
+ /** Source has been remapped to a new pointer. */
+ ID_REMAP_RESULT_SOURCE_REMAPPED,
+ /** Source has been set to NULL. */
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED,
+} IDRemapperApplyResult;
+
+typedef enum IDRemapperApplyOptions {
+ ID_REMAP_APPLY_UPDATE_REFCOUNT = (1 << 0),
+ ID_REMAP_APPLY_ENSURE_REAL = (1 << 1),
+
+ ID_REMAP_APPLY_DEFAULT = 0,
+} IDRemapperApplyOptions;
+
+typedef void (*IDRemapperIterFunction)(struct ID *old_id, struct ID *new_id, void *user_data);
+
+/**
+ * Create a new ID Remapper.
+ *
+ * An ID remapper stores multiple remapping rules.
+ */
+struct IDRemapper *BKE_id_remapper_create(void);
+
+void BKE_id_remapper_clear(struct IDRemapper *id_remapper);
+bool BKE_id_remapper_is_empty(const struct IDRemapper *id_remapper);
+/** Free the given ID Remapper. */
+void BKE_id_remapper_free(struct IDRemapper *id_remapper);
+/** Add a new remapping. */
+void BKE_id_remapper_add(struct IDRemapper *id_remapper, struct ID *old_id, struct ID *new_id);
+
+/**
+ * Apply a remapping.
+ *
+ * Update the id pointer stored in the given r_id_ptr if a remapping rule exists.
+ */
+IDRemapperApplyResult BKE_id_remapper_apply(const struct IDRemapper *id_remapper,
+ struct ID **r_id_ptr,
+ IDRemapperApplyOptions options);
+bool BKE_id_remapper_has_mapping_for(const struct IDRemapper *id_remapper, uint64_t type_filter);
+void BKE_id_remapper_iter(const struct IDRemapper *id_remapper,
+ IDRemapperIterFunction func,
+ void *user_data);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_lightprobe.h b/source/blender/blenkernel/BKE_lightprobe.h
index 764914ee315..59c5d32c03e 100644
--- a/source/blender/blenkernel/BKE_lightprobe.h
+++ b/source/blender/blenkernel/BKE_lightprobe.h
@@ -31,7 +31,7 @@ extern "C" {
struct LightProbe;
struct Main;
-void BKE_lightprobe_type_set(struct LightProbe *probe, const short lightprobe_type);
+void BKE_lightprobe_type_set(struct LightProbe *probe, short lightprobe_type);
void *BKE_lightprobe_add(struct Main *bmain, const char *name);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index eb17ff78688..94a5fde5468 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -60,16 +60,16 @@ LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *lines
LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle,
const LineStyleModifier *m,
- const int flag);
+ int flag);
LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle,
const LineStyleModifier *m,
- const int flag);
+ int flag);
LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle,
const LineStyleModifier *m,
- const int flag);
+ int flag);
LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle,
const LineStyleModifier *m,
- const int flag);
+ int flag);
int BKE_linestyle_color_modifier_remove(FreestyleLineStyle *linestyle,
LineStyleModifier *modifier);
@@ -101,7 +101,7 @@ void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, List
char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle,
struct ColorBand *color_ramp);
-bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes);
+bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, bool use_shading_nodes);
void BKE_linestyle_default_shader(const struct bContext *C, FreestyleLineStyle *linestyle);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 953c29f797a..4c6eb31db4b 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -116,6 +116,7 @@ enum {
typedef struct Main {
struct Main *next, *prev;
+ /** 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;
@@ -211,12 +212,10 @@ 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_create(struct Main *bmain, 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);
+void BKE_main_relations_tag_set(struct Main *bmain, eMainIDRelationsEntryTags tag, bool value);
/**
* Create a #GSet storing all IDs present in given \a bmain, by their pointers.
@@ -407,6 +406,13 @@ int set_listbasepointers(struct Main *main, struct ListBase *lb[]);
((main)->versionfile < (ver) || \
((main)->versionfile == (ver) && (main)->subversionfile < (subver)))
+/**
+ * The size of thumbnails (optionally) stored in the `.blend` files header.
+ *
+ * NOTE(@campbellbarton): This is kept small as it's stored uncompressed in the `.blend` file,
+ * where a larger size would increase the size of every `.blend` file unreasonably.
+ * If we wanted to increase the size, we'd want to use compression (JPEG or similar).
+ */
#define BLEN_THUMB_SIZE 128
#define BLEN_THUMB_MEMSIZE(_x, _y) \
diff --git a/source/blender/blenkernel/BKE_main_idmap.h b/source/blender/blenkernel/BKE_main_idmap.h
index 13ddcaa93ba..16b0c710357 100644
--- a/source/blender/blenkernel/BKE_main_idmap.h
+++ b/source/blender/blenkernel/BKE_main_idmap.h
@@ -56,9 +56,9 @@ enum {
* \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,
+ bool create_valid_ids_set,
struct Main *old_bmain,
- const int idmap_types) ATTR_WARN_UNUSED_RESULT
+ int idmap_types) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map) ATTR_NONNULL();
@@ -78,8 +78,7 @@ struct ID *BKE_main_idmap_lookup_id(struct IDNameLib_Map *id_map,
ATTR_NONNULL(1, 2);
struct ID *BKE_main_idmap_lookup_uuid(struct IDNameLib_Map *id_map,
- const uint session_uuid) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL(1);
+ uint session_uuid) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 2a2b080217c..e17f7eb4e85 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -115,7 +115,7 @@ float BKE_mask_spline_project_co(struct MaskSpline *spline,
struct MaskSplinePoint *point,
float start_u,
const float co[2],
- const eMaskSign sign);
+ eMaskSign sign);
/** \} */
@@ -144,18 +144,16 @@ void BKE_mask_point_normal(struct MaskSpline *spline,
float n[2]);
float BKE_mask_point_weight_scalar(struct MaskSpline *spline,
struct MaskSplinePoint *point,
- const float u);
-float BKE_mask_point_weight(struct MaskSpline *spline,
- struct MaskSplinePoint *point,
- const float u);
+ float u);
+float BKE_mask_point_weight(struct MaskSpline *spline, struct MaskSplinePoint *point, float u);
struct MaskSplinePointUW *BKE_mask_point_sort_uw(struct MaskSplinePoint *point,
struct MaskSplinePointUW *uw);
void BKE_mask_point_add_uw(struct MaskSplinePoint *point, float u, float w);
-void BKE_mask_point_select_set(struct MaskSplinePoint *point, const bool do_select);
+void BKE_mask_point_select_set(struct MaskSplinePoint *point, bool do_select);
void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point,
- const eMaskWhichHandle which_handle,
- const bool do_select);
+ eMaskWhichHandle which_handle,
+ bool do_select);
/** \} */
@@ -193,12 +191,12 @@ void BKE_mask_coord_to_image(struct Image *image,
/** \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);
+void BKE_mask_evaluate(struct Mask *mask, float ctime, bool do_newframe);
+void BKE_mask_layer_evaluate(struct MaskLayer *masklay, float ctime, bool do_newframe);
void BKE_mask_parent_init(struct MaskParent *parent);
void BKE_mask_calc_handle_adjacent_interp(struct MaskSpline *spline,
struct MaskSplinePoint *point,
- const float u);
+ float u);
/**
* Calculates the tangent of a point by its previous and next
* (ignoring handles - as if its a poly line).
@@ -214,7 +212,7 @@ void BKE_mask_calc_handle_point(struct MaskSpline *spline, struct MaskSplinePoin
*/
void BKE_mask_calc_handle_point_auto(struct MaskSpline *spline,
struct MaskSplinePoint *point,
- const bool do_recalc_length);
+ bool do_recalc_length);
void BKE_mask_get_handle_point_adjacent(struct MaskSpline *spline,
struct MaskSplinePoint *point,
struct MaskSplinePoint **r_point_prev,
@@ -247,22 +245,21 @@ void BKE_mask_layer_shape_to_mask(struct MaskLayer *masklay, struct MaskLayerSha
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);
+ float fac);
+struct MaskLayerShape *BKE_mask_layer_shape_find_frame(struct MaskLayer *masklay, 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,
+ 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);
+struct MaskLayerShape *BKE_mask_layer_shape_alloc(struct MaskLayer *masklay, int frame);
void BKE_mask_layer_shape_free(struct MaskLayerShape *masklay_shape);
-struct MaskLayerShape *BKE_mask_layer_shape_verify_frame(struct MaskLayer *masklay,
- const int frame);
+struct MaskLayerShape *BKE_mask_layer_shape_verify_frame(struct MaskLayer *masklay, int frame);
struct MaskLayerShape *BKE_mask_layer_shape_duplicate(struct MaskLayerShape *masklay_shape);
void BKE_mask_layer_shape_unlink(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape);
void BKE_mask_layer_shape_sort(struct MaskLayer *masklay);
@@ -354,15 +351,14 @@ void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mas
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,
- const unsigned int resol);
+int BKE_mask_spline_differentiate_calc_total(const struct MaskSpline *spline, unsigned int resol);
float (*BKE_mask_spline_differentiate_with_resolution(struct MaskSpline *spline,
- const unsigned int resol,
+ unsigned int resol,
unsigned int *r_tot_diff_point))[2];
void BKE_mask_spline_feather_collapse_inner_loops(struct MaskSpline *spline,
float (*feather_points)[2],
- const unsigned int tot_feather_point);
+ unsigned int tot_feather_point);
float (*BKE_mask_spline_differentiate(
struct MaskSpline *spline, int width, int height, unsigned int *r_tot_diff_point))[2];
/**
@@ -371,8 +367,8 @@ float (*BKE_mask_spline_differentiate(
*/
float (*BKE_mask_spline_feather_differentiated_points_with_resolution(
struct MaskSpline *spline,
- const unsigned int resol,
- const bool do_feather_isect,
+ unsigned int resol,
+ bool do_feather_isect,
unsigned int *r_tot_feather_point))[2];
/* *** mask point functions which involve evaluation *** */
@@ -393,8 +389,8 @@ float *BKE_mask_point_segment_feather_diff(struct MaskSpline *spline,
int height,
unsigned int *tot_feather_point);
-void BKE_mask_layer_evaluate_animation(struct MaskLayer *masklay, const float ctime);
-void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, const float ctime);
+void BKE_mask_layer_evaluate_animation(struct MaskLayer *masklay, float ctime);
+void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, float ctime);
void BKE_mask_eval_animation(struct Depsgraph *depsgraph, struct Mask *mask);
void BKE_mask_eval_update(struct Depsgraph *depsgraph, struct Mask *mask);
@@ -414,19 +410,19 @@ MaskRasterHandle *BKE_maskrasterize_handle_new(void);
void BKE_maskrasterize_handle_free(MaskRasterHandle *mr_handle);
void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
struct Mask *mask,
- const int width,
- const int height,
- const bool do_aspect_correct,
- const bool do_mask_aa,
- const bool do_feather);
+ int width,
+ int height,
+ bool do_aspect_correct,
+ bool do_mask_aa,
+ 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,
+ unsigned int width,
+ unsigned int height,
float *buffer);
/** \} */
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 5f9007c79b0..11746f445e4 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -51,7 +51,7 @@ void BKE_object_materials_test(struct Main *bmain, struct Object *ob, struct ID
void BKE_objects_materials_test_all(struct Main *bmain, struct ID *id);
void BKE_object_material_resize(struct Main *bmain,
struct Object *ob,
- const short totcol,
+ short totcol,
bool do_id_user);
void BKE_object_material_remap(struct Object *ob, const unsigned int *remap);
/**
@@ -110,7 +110,7 @@ void BKE_object_material_array_assign(struct Main *bmain,
struct Object *ob,
struct Material ***matar,
int totcol,
- const bool to_object_only);
+ bool to_object_only);
short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma);
bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
@@ -172,7 +172,7 @@ void BKE_id_material_eval_ensure_default_slot(struct ID *id);
* \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]);
+void ramp_blend(int type, float r_col[3], float fac, const float col[3]);
/** \} */
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 895fe5a28f9..fb72b361a0a 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -82,18 +82,15 @@ float *BKE_mball_make_orco(struct Object *ob, struct ListBase *dispbase);
* 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,
- float min[3],
- float max[3],
- const float obmat[4][4],
- const short flag);
+bool BKE_mball_minmax_ex(
+ const struct MetaBall *mb, float min[3], float max[3], const float obmat[4][4], 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_transform(struct MetaBall *mb, const float mat[4][4], bool do_props);
void BKE_mball_translate(struct MetaBall *mb, const float offset[3]);
/**
@@ -101,7 +98,7 @@ void BKE_mball_translate(struct MetaBall *mb, const float offset[3]);
*
* \note don't do context manipulation here (rna uses).
*/
-struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type);
+struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, int type);
/* *** select funcs *** */
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index c39583d234a..e1c706a82dc 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -23,6 +23,7 @@
*/
#include "BKE_mesh_types.h"
+#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
struct BLI_Stack;
@@ -74,7 +75,7 @@ struct BMesh *BKE_mesh_to_bmesh_ex(const struct Mesh *me,
const struct BMeshFromMeshParams *convert_params);
struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me,
struct Object *ob,
- const bool add_key_index,
+ bool add_key_index,
const struct BMeshCreateParams *params);
struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm,
@@ -118,6 +119,9 @@ void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh,
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);
+
+void BKE_mesh_free_editmesh(struct Mesh *mesh);
+
/**
* A version of #BKE_mesh_copy_parameters that is intended for evaluated output
* (the modifier stack for example).
@@ -130,7 +134,7 @@ void BKE_mesh_copy_parameters_for_eval(struct Mesh *me_dst, const struct Mesh *m
* 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_update_customdata_pointers(struct Mesh *me, bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
struct Mesh *BKE_mesh_new_nomain(
@@ -189,7 +193,7 @@ void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *
void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me);
void BKE_mesh_to_curve_nurblist(const struct Mesh *me,
struct ListBase *nurblist,
- const int edge_users_test);
+ int edge_users_test);
void BKE_mesh_to_curve(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -208,7 +212,7 @@ void BKE_mesh_material_index_remove(struct Mesh *me, short index);
bool BKE_mesh_material_index_used(struct Mesh *me, short index);
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);
+void BKE_mesh_smooth_flag_set(struct Mesh *me, bool use_smooth);
/**
* Needed after converting a mesh with subsurf optimal display to mesh.
@@ -254,8 +258,8 @@ void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
*/
struct Mesh *BKE_mesh_new_from_object(struct Depsgraph *depsgraph,
struct Object *object,
- const bool preserve_all_data_layers,
- const bool preserve_origindex);
+ bool preserve_all_data_layers,
+ bool preserve_origindex);
/**
* This is a version of BKE_mesh_new_from_object() which stores mesh in the given main database.
@@ -276,8 +280,8 @@ struct Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob_eval,
struct ModifierData *md_eval,
- const bool use_virtual_modifiers,
- const bool build_shapekey_layers);
+ bool use_virtual_modifiers,
+ bool build_shapekey_layers);
/**
* Copies a nomain-Mesh into an existing Mesh.
@@ -294,7 +298,7 @@ void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, st
/* 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);
+void BKE_mesh_translate(struct Mesh *me, const float offset[3], bool do_keys);
void BKE_mesh_tessface_ensure(struct Mesh *mesh);
void BKE_mesh_tessface_clear(struct Mesh *mesh);
@@ -322,7 +326,6 @@ void BKE_mesh_vert_coords_apply_with_mat4(struct Mesh *mesh,
const float (*vert_coords)[3],
const float mat[4][4]);
void BKE_mesh_vert_coords_apply(struct Mesh *mesh, const float (*vert_coords)[3]);
-void BKE_mesh_vert_normals_apply(struct Mesh *mesh, const short (*vert_normals)[3]);
/* *** mesh_tessellate.c *** */
@@ -344,7 +347,7 @@ int BKE_mesh_tessface_calc_ex(struct CustomData *fdata,
int totface,
int totloop,
int totpoly,
- const bool do_face_nor_copy);
+ bool do_face_nor_copy);
void BKE_mesh_tessface_calc(struct Mesh *mesh);
/**
@@ -374,7 +377,83 @@ void BKE_mesh_recalc_looptri_with_normals(const struct MLoop *mloop,
/* *** mesh_normals.cc *** */
+/**
+ * Returns the normals for each vertex, which is defined as the weighted average of the normals
+ * from a vertices surrounding faces, or the normalized position of vertices connected to no faces.
+ * \warning May still return null if the mesh is empty.
+ */
+const float (*BKE_mesh_vertex_normals_ensure(const struct Mesh *mesh))[3];
+
+/**
+ * Return the normal direction of every polygon, which is defined by the winding direction of its
+ * corners.
+ * \warning May still return null if the mesh is empty or has no polygons.
+ */
+const float (*BKE_mesh_poly_normals_ensure(const struct Mesh *mesh))[3];
+
+/**
+ * Tag mesh vertex and face normals to be recalculated when/if they are needed later.
+ *
+ * \note Dirty tagged normals are the default state of a new mesh, so tagging them
+ * dirty explicitly is not always necessary if the mesh is created locally.
+ */
void BKE_mesh_normals_tag_dirty(struct Mesh *mesh);
+
+/**
+ * Check that a mesh with non-dirty normals has vertex and face custom data layers.
+ * If these asserts fail, it means some area cleared the dirty flag but didn't copy or add the
+ * normal layers, or removed normals but didn't set the dirty flag.
+ */
+void BKE_mesh_assert_normals_dirty_or_calculated(const struct Mesh *mesh);
+
+/**
+ * Retrieve write access to the vertex normal layer, ensuring that it exists and that it is not
+ * shared. The provided vertex normals should be the same as if they were calculated automatically.
+ *
+ * \note In order to clear the dirty flag, this function should be followed by a call to
+ * #BKE_mesh_vertex_normals_clear_dirty. This is separate so that normals are still tagged dirty
+ * while they are being assigned.
+ */
+float (*BKE_mesh_vertex_normals_for_write(struct Mesh *mesh))[3];
+
+/**
+ * Retrieve write access to the poly normal layer, ensuring that it exists and that it is not
+ * shared. The provided poly normals should be the same as if they were calculated automatically.
+ *
+ * \note In order to clear the dirty flag, this function should be followed by a call to
+ * #BKE_mesh_poly_normals_clear_dirty. This is separate so that normals are still tagged dirty
+ * while they are being assigned.
+ */
+float (*BKE_mesh_poly_normals_for_write(struct Mesh *mesh))[3];
+
+/**
+ * Mark the mesh's vertex normals non-dirty, for when they are calculated or assigned manually.
+ */
+void BKE_mesh_vertex_normals_clear_dirty(struct Mesh *mesh);
+
+/**
+ * Mark the mesh's poly normals non-dirty, for when they are calculated or assigned manually.
+ */
+void BKE_mesh_poly_normals_clear_dirty(struct Mesh *mesh);
+
+/**
+ * Return true if the mesh vertex normals either are not stored or are dirty.
+ * This can be used to help decide whether to transfer them when copying a mesh.
+ */
+bool BKE_mesh_vertex_normals_are_dirty(const struct Mesh *mesh);
+
+/**
+ * Return true if the mesh polygon normals either are not stored or are dirty.
+ * This can be used to help decide whether to transfer them when copying a mesh.
+ */
+bool BKE_mesh_poly_normals_are_dirty(const struct Mesh *mesh);
+
+/**
+ * Calculate face normals directly into a result array.
+ *
+ * \note Usually #BKE_mesh_poly_normals_ensure is the preferred way to access face normals,
+ * since they may already be calculated and cached on the mesh.
+ */
void BKE_mesh_calc_normals_poly(const struct MVert *mvert,
int mvert_len,
const struct MLoop *mloop,
@@ -382,20 +461,16 @@ void BKE_mesh_calc_normals_poly(const struct MVert *mvert,
const struct MPoly *mpoly,
int mpoly_len,
float (*r_poly_normals)[3]);
-void BKE_mesh_calc_normals_poly_and_vertex(struct MVert *mvert,
- int mvert_len,
- const struct MLoop *mloop,
- int mloop_len,
- const struct MPoly *mpolys,
- 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.
+
+/**
+ * Calculate vertex and face normals, storing the result in custom data layers on the mesh.
+ *
+ * \note It is usually preferable to calculate normals lazily with
+ * #BKE_mesh_vertex_normals_ensure, but some areas (perhaps unnecessarily)
+ * can also calculate them eagerly.
*/
void BKE_mesh_calc_normals(struct Mesh *me);
-void BKE_mesh_ensure_normals(struct Mesh *me);
+
/**
* Called after calculating all modifiers.
*/
@@ -410,7 +485,7 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const struct MLoop *mloops,
const struct MPoly *mpolys,
const int *loop_to_poly,
const int *e2lfan_curr,
- const uint mv_pivot_index,
+ uint mv_pivot_index,
const struct MLoop **r_mlfan_curr,
int *r_mlfan_curr_index,
int *r_mlfan_vert_index,
@@ -423,15 +498,15 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const struct MLoop *mloops,
* to keep same shading as with auto-smooth!
*/
void BKE_edges_sharp_from_angle_set(const struct MVert *mverts,
- const int numVerts,
+ int numVerts,
struct MEdge *medges,
- const int numEdges,
+ int numEdges,
struct MLoop *mloops,
- const int numLoops,
+ int numLoops,
struct MPoly *mpolys,
const float (*polynors)[3],
- const int numPolys,
- const float split_angle);
+ int numPolys,
+ float split_angle);
/**
* References a contiguous loop-fan with normal offset vars.
@@ -484,9 +559,7 @@ enum {
};
/* Low-level custom normals functions. */
-void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr,
- const int numLoops,
- const char data_type);
+void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, int numLoops, char data_type);
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr);
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr);
@@ -528,9 +601,9 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
*/
void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr,
MLoopNorSpace *lnor_space,
- const int ml_index,
+ int ml_index,
void *bm_loop,
- const bool is_single);
+ bool is_single);
void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space,
const short clnor_data[2],
float r_custom_lnor[3]);
@@ -546,42 +619,45 @@ void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space,
* (splitting edges).
*/
void BKE_mesh_normals_loop_split(const struct MVert *mverts,
- const int numVerts,
+ const float (*vert_normals)[3],
+ int numVerts,
struct MEdge *medges,
- const int numEdges,
+ int numEdges,
struct MLoop *mloops,
float (*r_loopnors)[3],
- const int numLoops,
+ int numLoops,
struct MPoly *mpolys,
const float (*polynors)[3],
- const int numPolys,
- const bool use_split_normals,
- const float split_angle,
+ int numPolys,
+ bool use_split_normals,
+ float split_angle,
MLoopNorSpaceArray *r_lnors_spacearr,
short (*clnors_data)[2],
int *r_loop_to_poly);
void BKE_mesh_normals_loop_custom_set(const struct MVert *mverts,
- const int numVerts,
+ const float (*vert_normals)[3],
+ int numVerts,
struct MEdge *medges,
- const int numEdges,
+ int numEdges,
struct MLoop *mloops,
float (*r_custom_loopnors)[3],
- const int numLoops,
+ int numLoops,
struct MPoly *mpolys,
const float (*polynors)[3],
- const int numPolys,
+ int numPolys,
short (*r_clnors_data)[2]);
void BKE_mesh_normals_loop_custom_from_vertices_set(const struct MVert *mverts,
+ const float (*vert_normals)[3],
float (*r_custom_vertnors)[3],
- const int numVerts,
+ int numVerts,
struct MEdge *medges,
- const int numEdges,
+ int numEdges,
struct MLoop *mloops,
- const int numLoops,
+ int numLoops,
struct MPoly *mpolys,
const float (*polynors)[3],
- const int numPolys,
+ int numPolys,
short (*r_clnors_data)[2]);
/**
@@ -590,9 +666,9 @@ void BKE_mesh_normals_loop_custom_from_vertices_set(const struct MVert *mverts,
* \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,
+void BKE_mesh_normals_loop_to_vertex(int numVerts,
const struct MLoop *mloops,
- const int numLoops,
+ int numLoops,
const float (*clnors)[3],
float (*r_vert_clnors)[3]);
@@ -682,9 +758,9 @@ bool BKE_mesh_center_of_volume(const struct Mesh *me, float r_cent[3]);
* \param r_center: Center of mass.
*/
void BKE_mesh_calc_volume(const struct MVert *mverts,
- const int mverts_num,
+ int mverts_num,
const struct MLoopTri *mlooptri,
- const int looptri_num,
+ int looptri_num,
const struct MLoop *mloop,
float *r_volume,
float r_center[3]);
@@ -724,7 +800,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(struct ID *id,
* 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);
+void BKE_mesh_mdisp_flip(struct MDisps *md, bool use_loop_mdisp_flip);
/**
* Flip (invert winding of) the given \a mpoly, i.e. reverse order of its loops
@@ -739,7 +815,7 @@ void BKE_mesh_polygon_flip_ex(struct MPoly *mpoly,
struct CustomData *ldata,
float (*lnors)[3],
struct MDisps *mdisp,
- const bool use_loop_mdisp_flip);
+ 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).
@@ -792,8 +868,8 @@ enum {
*/
struct Mesh *BKE_mesh_merge_verts(struct Mesh *mesh,
const int *vtargetmap,
- const int tot_vtargetmap,
- const int merge_mode);
+ int tot_vtargetmap,
+ int merge_mode);
/* Flush flags. */
@@ -803,35 +879,35 @@ struct Mesh *BKE_mesh_merge_verts(struct Mesh *mesh,
void BKE_mesh_flush_hidden_from_verts_ex(const struct MVert *mvert,
const struct MLoop *mloop,
struct MEdge *medge,
- const int totedge,
+ int totedge,
struct MPoly *mpoly,
- const int totpoly);
+ int totpoly);
void BKE_mesh_flush_hidden_from_verts(struct Mesh *me);
void BKE_mesh_flush_hidden_from_polys_ex(struct MVert *mvert,
const struct MLoop *mloop,
struct MEdge *medge,
- const int totedge,
+ int totedge,
const struct MPoly *mpoly,
- const int totpoly);
+ 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,
+ int totvert,
const struct MLoop *mloop,
struct MEdge *medge,
- const int totedge,
+ int totedge,
const struct MPoly *mpoly,
- const int totpoly);
+ int totpoly);
void BKE_mesh_flush_select_from_polys(struct Mesh *me);
void BKE_mesh_flush_select_from_verts_ex(const struct MVert *mvert,
- const int totvert,
+ int totvert,
const struct MLoop *mloop,
struct MEdge *medge,
- const int totedge,
+ int totedge,
struct MPoly *mpoly,
- const int totpoly);
+ int totpoly);
void BKE_mesh_flush_select_from_verts(struct Mesh *me);
/* spatial evaluation */
@@ -847,9 +923,9 @@ void BKE_mesh_flush_select_from_verts(struct Mesh *me);
* \param vert_cos_new: resulting coords.
*/
void BKE_mesh_calc_relative_deform(const struct MPoly *mpoly,
- const int totpoly,
+ int totpoly,
const struct MLoop *mloop,
- const int totvert,
+ int totvert,
const float (*vert_cos_src)[3],
const float (*vert_cos_dst)[3],
@@ -864,18 +940,15 @@ void BKE_mesh_calc_relative_deform(const struct MPoly *mpoly,
*
* \returns true if a change is made.
*/
-bool BKE_mesh_validate(struct Mesh *me, const bool do_verbose, const bool cddata_check_mask);
+bool BKE_mesh_validate(struct Mesh *me, bool do_verbose, bool cddata_check_mask);
/**
* Checks if a Mesh is valid without any modification. This is always verbose.
- *
- * \see #DM_is_valid to call on derived meshes
- *
- * \returns is_valid.
+ * \returns True if the mesh is valid.
*/
bool BKE_mesh_is_valid(struct Mesh *me);
/**
* Check all material indices of polygons are valid, invalid ones are set to 0.
- * \returns is_valid.
+ * \returns True if the material indices are valid.
*/
bool BKE_mesh_validate_material_indices(struct Mesh *me);
@@ -906,24 +979,24 @@ bool BKE_mesh_validate_arrays(struct Mesh *me,
struct MPoly *mpolys,
unsigned int totpoly,
struct MDeformVert *dverts, /* assume totvert length */
- const bool do_verbose,
- const bool do_fixes,
+ bool do_verbose,
+ bool do_fixes,
bool *r_change);
/**
* \returns is_valid.
*/
bool BKE_mesh_validate_all_customdata(struct CustomData *vdata,
- const uint totvert,
+ uint totvert,
struct CustomData *edata,
- const uint totedge,
+ uint totedge,
struct CustomData *ldata,
- const uint totloop,
+ uint totloop,
struct CustomData *pdata,
- const uint totpoly,
- const bool check_meshmask,
- const bool do_verbose,
- const bool do_fixes,
+ uint totpoly,
+ bool check_meshmask,
+ bool do_verbose,
+ bool do_fixes,
bool *r_change);
void BKE_mesh_strip_loose_faces(struct Mesh *me);
@@ -941,12 +1014,12 @@ 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_legacy(struct Mesh *me, 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);
+void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool select_new_edges);
/**
* Calculate/create edges from tessface data
*
@@ -956,7 +1029,7 @@ void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
/* In DerivedMesh.cc */
void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval,
- const CustomData_MeshMasks *cd_mask_finalize);
+ const struct CustomData_MeshMasks *cd_mask_finalize);
/* **** Depsgraph evaluation **** */
@@ -969,6 +1042,13 @@ void BKE_mesh_batch_cache_free(struct Mesh *me);
extern void (*BKE_mesh_batch_cache_dirty_tag_cb)(struct Mesh *me, eMeshBatchDirtyMode mode);
extern void (*BKE_mesh_batch_cache_free_cb)(struct Mesh *me);
+/* mesh_debug.c */
+#ifndef NDEBUG
+char *BKE_mesh_debug_info(const struct Mesh *me)
+ ATTR_NONNULL(1) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+void BKE_mesh_debug_print(const struct Mesh *me) ATTR_NONNULL(1);
+#endif
+
/* Inlines */
/* NOTE(@sybren): Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h,
diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
index a7a7529f217..5a743999803 100644
--- a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
+++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
@@ -46,8 +46,8 @@ Mesh *direct_mesh_boolean(blender::Span<const Mesh *> meshes,
blender::Span<const float4x4 *> obmats,
const float4x4 &target_transform,
blender::Span<blender::Array<short>> material_remaps,
- const bool use_self,
- const bool hole_tolerant,
- const int boolean_mode);
+ bool use_self,
+ bool hole_tolerant,
+ int boolean_mode);
} // namespace blender::meshintersect
diff --git a/source/blender/blenkernel/BKE_mesh_fair.h b/source/blender/blenkernel/BKE_mesh_fair.h
index 2d5c85d4129..c4c1af054f0 100644
--- a/source/blender/blenkernel/BKE_mesh_fair.h
+++ b/source/blender/blenkernel/BKE_mesh_fair.h
@@ -42,14 +42,14 @@ typedef enum eMeshFairingDepth {
* the vertex should be modified by fairing. */
void BKE_bmesh_prefair_and_fair_vertices(struct BMesh *bm,
bool *affect_vertices,
- const eMeshFairingDepth depth);
+ eMeshFairingDepth depth);
/* This function can optionally use the MVert coordinates of deform_mverts to read and write the
* fairing result. When NULL, the function will use mesh->mverts directly. */
void BKE_mesh_prefair_and_fair_vertices(struct Mesh *mesh,
struct MVert *deform_mverts,
bool *affect_vertices,
- const eMeshFairingDepth depth);
+ eMeshFairingDepth depth);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mesh_iterators.h b/source/blender/blenkernel/BKE_mesh_iterators.h
index 83f0228dc76..b28465fc41e 100644
--- a/source/blender/blenkernel/BKE_mesh_iterators.h
+++ b/source/blender/blenkernel/BKE_mesh_iterators.h
@@ -31,14 +31,11 @@ typedef enum MeshForeachFlag {
MESH_FOREACH_USE_NORMAL = (1 << 0),
} MeshForeachFlag;
-void BKE_mesh_foreach_mapped_vert(struct Mesh *mesh,
- void (*func)(void *userData,
- int index,
- const float co[3],
- const float no_f[3],
- const short no_s[3]),
- void *userData,
- MeshForeachFlag flag);
+void BKE_mesh_foreach_mapped_vert(
+ struct Mesh *mesh,
+ void (*func)(void *userData, int index, const float co[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag);
/**
* Copied from #cdDM_foreachMappedEdge.
* \param tot_edges: Number of original edges. Used to avoid calling the callback with invalid
@@ -68,9 +65,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
void *userData,
MeshForeachFlag flag);
-void BKE_mesh_foreach_mapped_vert_coords_get(struct Mesh *me_eval,
- float (*r_cos)[3],
- const int totcos);
+void BKE_mesh_foreach_mapped_vert_coords_get(struct Mesh *me_eval, float (*r_cos)[3], int totcos);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index acc1628de1d..48669278e23 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -100,8 +100,8 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const struct MPoly *mpoly,
unsigned int totpoly,
unsigned int totvert,
const float limit[2],
- const bool selected,
- const bool use_winding);
+ bool selected,
+ bool use_winding);
UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v);
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap);
@@ -137,11 +137,11 @@ void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MVert *mvert,
- const int totvert,
+ int totvert,
const struct MLoopTri *mlooptri,
- const int totlooptri,
+ int totlooptri,
const struct MLoop *mloop,
- const int totloop);
+ 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.
@@ -163,11 +163,11 @@ void BKE_mesh_vert_edge_vert_map_create(
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MEdge *medge,
- const int totedge,
+ int totedge,
const struct MPoly *mpoly,
- const int totpoly,
+ int totpoly,
const struct MLoop *mloop,
- const int totloop);
+ int totloop);
/**
* Generates a map where the key is the edge and the value
* is a list of polygons that use that edge.
@@ -176,11 +176,11 @@ void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
int **r_mem,
const struct MEdge *medge,
- const int totedge,
+ int totedge,
const struct MPoly *mpoly,
- const int totpoly,
+ int totpoly,
const struct MLoop *mloop,
- const int totloop);
+ 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).
@@ -195,11 +195,8 @@ void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
* `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);
+void BKE_mesh_origindex_map_create(
+ MeshElemMap **r_map, int **r_mem, int totsource, const int *final_origindex, int totfinal);
/**
* A version of #BKE_mesh_origindex_map_create that takes a looptri array.
* Making a poly -> looptri map.
@@ -207,9 +204,9 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
int **r_mem,
const struct MPoly *mpoly,
- const int mpoly_num,
+ int mpoly_num,
const struct MLoopTri *looptri,
- const int looptri_num);
+ int looptri_num);
/* islands */
@@ -239,28 +236,28 @@ typedef struct MeshIslandStore {
} MeshIslandStore;
void BKE_mesh_loop_islands_init(MeshIslandStore *island_store,
- const short item_type,
- const int items_num,
- const short island_type,
- const short innercut_type);
+ short item_type,
+ int items_num,
+ short island_type,
+ short innercut_type);
void BKE_mesh_loop_islands_clear(MeshIslandStore *island_store);
void BKE_mesh_loop_islands_free(MeshIslandStore *island_store);
void BKE_mesh_loop_islands_add(MeshIslandStore *island_store,
- const int item_num,
+ int item_num,
const int *items_indices,
- const int num_island_items,
+ int num_island_items,
int *island_item_indices,
- const int num_innercut_items,
+ int num_innercut_items,
int *innercut_item_indices);
typedef bool (*MeshRemapIslandsCalc)(struct MVert *verts,
- const int totvert,
+ int totvert,
struct MEdge *edges,
- const int totedge,
+ int totedge,
struct MPoly *polys,
- const int totpoly,
+ int totpoly,
struct MLoop *loops,
- const int totloop,
+ int totloop,
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.
@@ -271,13 +268,13 @@ typedef bool (*MeshRemapIslandsCalc)(struct MVert *verts,
* not some UV layers coordinates.
*/
bool BKE_mesh_calc_islands_loop_poly_edgeseam(struct MVert *verts,
- const int totvert,
+ int totvert,
struct MEdge *edges,
- const int totedge,
+ int totedge,
struct MPoly *polys,
- const int totpoly,
+ int totpoly,
struct MLoop *loops,
- const int totloop,
+ int totloop,
MeshIslandStore *r_island_store);
/**
@@ -294,13 +291,13 @@ bool BKE_mesh_calc_islands_loop_poly_edgeseam(struct MVert *verts,
* those loops are supposed to be really quick to do.
*/
bool BKE_mesh_calc_islands_loop_poly_uvmap(struct MVert *verts,
- const int totvert,
+ int totvert,
struct MEdge *edges,
- const int totedge,
+ int totedge,
struct MPoly *polys,
- const int totpoly,
+ int totpoly,
struct MLoop *loops,
- const int totloop,
+ int totloop,
const struct MLoopUV *luvs,
MeshIslandStore *r_island_store);
@@ -313,13 +310,13 @@ bool BKE_mesh_calc_islands_loop_poly_uvmap(struct MVert *verts,
* Note it's callers's responsibility to MEM_freeN returned array.
*/
int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge,
- const int totedge,
+ int totedge,
const struct MPoly *mpoly,
- const int totpoly,
+ int totpoly,
const struct MLoop *mloop,
- const int totloop,
+ int totloop,
int *r_totgroup,
- const bool use_bitflags);
+ bool use_bitflags);
/* use on looptri vertex values */
#define BKE_MESH_TESSTRI_VINDEX_ORDER(_tri, _v) \
diff --git a/source/blender/blenkernel/BKE_mesh_mirror.h b/source/blender/blenkernel/BKE_mesh_mirror.h
index abb8e4d3e44..c77974d6cc1 100644
--- a/source/blender/blenkernel/BKE_mesh_mirror.h
+++ b/source/blender/blenkernel/BKE_mesh_mirror.h
@@ -40,19 +40,18 @@ struct Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(struct MirrorMo
void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
struct Mesh *mesh,
- const int axis,
- const float dist);
+ int axis,
+ float dist);
/**
* \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);
+struct Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(struct MirrorModifierData *mmd,
+ struct Object *ob,
+ const struct Mesh *mesh,
+ int axis,
+ 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 c33b3800aa4..ab07cb0df4e 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -50,10 +50,10 @@ typedef struct MeshPairRemap {
} MeshPairRemap;
/* Helpers! */
-void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num);
+void BKE_mesh_remap_init(MeshPairRemap *map, int items_num);
void BKE_mesh_remap_free(MeshPairRemap *map);
-void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, const int index);
+void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, int index);
/* TODO:
* Add other 'from/to' mapping sources, like e.g. using an UVMap, etc.
@@ -155,10 +155,10 @@ enum {
};
void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
- const int vert_mode,
- const int edge_mode,
- const int loop_mode,
- const int poly_mode,
+ int vert_mode,
+ int edge_mode,
+ int loop_mode,
+ int poly_mode,
struct CustomData_MeshMasks *cddata_mask);
/**
@@ -173,73 +173,70 @@ void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
*/
float BKE_mesh_remap_calc_difference_from_mesh(const struct SpaceTransform *space_transform,
const struct MVert *verts_dst,
- const int numverts_dst,
+ 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,
+ int numverts_dst,
struct Mesh *me_src,
struct SpaceTransform *r_space_transform);
-void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
+void BKE_mesh_remap_calc_verts_from_mesh(int mode,
const struct SpaceTransform *space_transform,
- const float max_dist,
- const float ray_radius,
+ float max_dist,
+ float ray_radius,
const struct MVert *verts_dst,
- const int numverts_dst,
- const bool dirty_nors_dst,
+ int numverts_dst,
+ bool dirty_nors_dst,
struct Mesh *me_src,
MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
+void BKE_mesh_remap_calc_edges_from_mesh(int mode,
const struct SpaceTransform *space_transform,
- const float max_dist,
- const float ray_radius,
+ float max_dist,
+ float ray_radius,
const struct MVert *verts_dst,
- const int numverts_dst,
+ int numverts_dst,
const struct MEdge *edges_dst,
- const int numedges_dst,
- const bool dirty_nors_dst,
+ int numedges_dst,
+ bool dirty_nors_dst,
struct Mesh *me_src,
MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
+void BKE_mesh_remap_calc_loops_from_mesh(int mode,
const struct SpaceTransform *space_transform,
- const float max_dist,
- const float ray_radius,
+ float max_dist,
+ float ray_radius,
+ struct Mesh *mesh_dst,
struct MVert *verts_dst,
- const int numverts_dst,
+ int numverts_dst,
struct MEdge *edges_dst,
- const int numedges_dst,
+ int numedges_dst,
struct MLoop *loops_dst,
- const int numloops_dst,
+ int numloops_dst,
struct MPoly *polys_dst,
- const int numpolys_dst,
+ int numpolys_dst,
struct CustomData *ldata_dst,
- struct CustomData *pdata_dst,
- const bool use_split_nors_dst,
- const float split_angle_dst,
- const bool dirty_nors_dst,
+ bool use_split_nors_dst,
+ float split_angle_dst,
+ bool dirty_nors_dst,
struct Mesh *me_src,
MeshRemapIslandsCalc gen_islands_src,
- const float islands_precision_src,
+ float islands_precision_src,
struct MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_polys_from_mesh(const int mode,
+void BKE_mesh_remap_calc_polys_from_mesh(int mode,
const struct SpaceTransform *space_transform,
- const float max_dist,
- const float ray_radius,
+ float max_dist,
+ float ray_radius,
+ struct Mesh *mesh_dst,
struct MVert *verts_dst,
- const int numverts_dst,
struct MLoop *loops_dst,
- const int numloops_dst,
struct MPoly *polys_dst,
- const int numpolys_dst,
- struct CustomData *pdata_dst,
- const bool dirty_nors_dst,
+ int numpolys_dst,
struct Mesh *me_src,
struct MeshPairRemap *r_map);
diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h
index 764241e7f92..ad86f6d8f25 100644
--- a/source/blender/blenkernel/BKE_mesh_runtime.h
+++ b/source/blender/blenkernel/BKE_mesh_runtime.h
@@ -56,7 +56,7 @@ void BKE_mesh_runtime_free_data(struct Mesh *mesh);
* 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);
+void BKE_mesh_runtime_reset_on_copy(struct Mesh *mesh, int flag);
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh);
void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh);
/**
@@ -102,12 +102,6 @@ struct Mesh *mesh_create_eval_final(struct Depsgraph *depsgraph,
struct Object *ob,
const struct CustomData_MeshMasks *dataMask);
-struct Mesh *mesh_create_eval_final_index_render(struct Depsgraph *depsgraph,
- struct Scene *scene,
- struct Object *ob,
- const struct CustomData_MeshMasks *dataMask,
- int index);
-
struct Mesh *mesh_create_eval_no_deform(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
@@ -122,10 +116,6 @@ void BKE_mesh_runtime_eval_to_meshkey(struct Mesh *me_deformed,
struct KeyBlock *kb);
#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_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh
index 17f8e766724..738b768d906 100644
--- a/source/blender/blenkernel/BKE_mesh_sample.hh
+++ b/source/blender/blenkernel/BKE_mesh_sample.hh
@@ -22,7 +22,7 @@
#include "FN_generic_virtual_array.hh"
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "BKE_attribute.h"
@@ -89,8 +89,8 @@ class MeshAttributeInterpolator {
const Span<int> looptri_indices);
void sample_data(const GVArray &src,
- const AttributeDomain domain,
- const eAttributeMapMode mode,
+ AttributeDomain domain,
+ eAttributeMapMode mode,
const GMutableSpan dst);
void sample_attribute(const ReadAttributeLookup &src_attribute,
diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h
index 39d4072085c..320c4e7f36a 100644
--- a/source/blender/blenkernel/BKE_mesh_tangent.h
+++ b/source/blender/blenkernel/BKE_mesh_tangent.h
@@ -32,14 +32,14 @@ struct ReportList;
* 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,
+ int numVerts,
const struct MLoop *mloops,
float (*r_looptangent)[4],
float (*loopnors)[3],
const struct MLoopUV *loopuv,
- const int numLoops,
+ int numLoops,
const struct MPoly *mpolys,
- const int numPolys,
+ int numPolys,
struct ReportList *reports);
/**
* Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
@@ -57,21 +57,22 @@ void BKE_mesh_calc_loop_tangent_single(struct Mesh *mesh,
*/
void BKE_mesh_calc_loop_tangent_ex(const struct MVert *mvert,
const struct MPoly *mpoly,
- const uint mpoly_len,
+ uint mpoly_len,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
- const uint looptri_len,
+ uint looptri_len,
struct CustomData *loopdata,
bool calc_active_tangent,
const char (*tangent_names)[64],
int tangent_names_len,
+ const float (*vert_normals)[3],
const float (*poly_normals)[3],
const float (*loop_normals)[3],
const float (*vert_orco)[3],
/* result */
struct CustomData *loopdata_out,
- const uint loopdata_out_len,
+ uint loopdata_out_len,
short *tangent_mask_curr_p);
void BKE_mesh_calc_loop_tangents(struct Mesh *me_eval,
diff --git a/source/blender/blenkernel/BKE_mesh_wrapper.h b/source/blender/blenkernel/BKE_mesh_wrapper.h
index 2fe264fd0f7..12e8fd71503 100644
--- a/source/blender/blenkernel/BKE_mesh_wrapper.h
+++ b/source/blender/blenkernel/BKE_mesh_wrapper.h
@@ -22,6 +22,7 @@
struct BMEditMesh;
struct CustomData_MeshMasks;
struct Mesh;
+struct Object;
#ifdef __cplusplus
extern "C" {
@@ -51,6 +52,8 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const struct Mesh *me,
int vert_coords_len,
const float mat[4][4]);
+struct Mesh *BKE_mesh_wrapper_ensure_subdivision(const struct Object *ob, struct Mesh *me);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 278189633a6..80889813b34 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -184,7 +184,7 @@ typedef struct ModifierTypeInfo {
*
* \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
*/
- void (*copyData)(const struct ModifierData *md, struct ModifierData *target, const int flag);
+ void (*copyData)(const struct ModifierData *md, struct ModifierData *target, int flag);
/********************* Deform modifier functions *********************/
@@ -322,7 +322,7 @@ typedef struct ModifierTypeInfo {
*
* The dag_eval_mode should be of type eEvaluationMode.
*/
- bool (*dependsOnTime)(struct Scene *scene, struct ModifierData *md, const int dag_eval_mode);
+ bool (*dependsOnTime)(struct Scene *scene, struct ModifierData *md, int dag_eval_mode);
/**
* True when a deform modifier uses normals, the requiredDataMask
@@ -415,7 +415,7 @@ void BKE_modifier_panel_expand(struct ModifierData *md);
*/
struct ModifierData *BKE_modifier_new(int type);
-void BKE_modifier_free_ex(struct ModifierData *md, const int flag);
+void BKE_modifier_free_ex(struct ModifierData *md, int flag);
void BKE_modifier_free(struct ModifierData *md);
/**
* Use instead of `BLI_remlink` when the object's active modifier should change.
@@ -432,11 +432,9 @@ bool BKE_modifier_unique_name(struct ListBase *modifiers, struct ModifierData *m
*/
void BKE_modifier_copydata_generic(const struct ModifierData *md,
struct ModifierData *md_dst,
- const int flag);
+ int flag);
void BKE_modifier_copydata(struct ModifierData *md, struct ModifierData *target);
-void BKE_modifier_copydata_ex(struct ModifierData *md,
- struct ModifierData *target,
- const int flag);
+void BKE_modifier_copydata_ex(struct ModifierData *md, struct ModifierData *target, int flag);
bool BKE_modifier_depends_ontime(struct Scene *scene, struct ModifierData *md, int dag_eval_mode);
bool BKE_modifier_supports_mapping(struct ModifierData *md);
bool BKE_modifier_supports_cage(struct Scene *scene, struct ModifierData *md);
@@ -604,7 +602,7 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
* (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);
+ bool get_cage_mesh);
void BKE_modifier_check_uuids_unique_and_report(const struct Object *object);
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index c83022c4658..504771fa733 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -167,7 +167,7 @@ void multiresModifier_ensure_external_read(struct Mesh *mesh,
/**** interpolation stuff ****/
/* Adapted from `sculptmode.c` */
-void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v);
+void old_mdisps_bilinear(float out[3], float (*disps)[3], int st, float u, float v);
/**
* Find per-corner coordinate with given per-face UV coord.
*/
@@ -175,9 +175,9 @@ int mdisp_rot_face_to_crn(struct MVert *mvert,
struct MPoly *mpoly,
struct MLoop *mloop,
const struct MLoopTri *lt,
- const int face_side,
- const float u,
- const float v,
+ int face_side,
+ float u,
+ float v,
float *x,
float *y);
@@ -187,7 +187,7 @@ bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd,
const float (*vert_coords)[3],
- const int num_vert_coords);
+ int num_vert_coords);
/**
* Returns truth on success, false otherwise.
*
@@ -202,7 +202,7 @@ bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph,
struct Object *ob,
struct MultiresModifierData *mmd,
struct ModifierData *deform_md);
-bool multiresModifier_reshapeFromCCG(const int tot_level,
+bool multiresModifier_reshapeFromCCG(int tot_level,
struct Mesh *coarse_mesh,
struct SubdivCCG *subdiv_ccg);
@@ -216,7 +216,7 @@ typedef enum eMultiresSubdivideModeType {
void multiresModifier_subdivide(struct Object *object,
struct MultiresModifierData *mmd,
- const eMultiresSubdivideModeType mode);
+ eMultiresSubdivideModeType mode);
void multires_subdivide_create_tangent_displacement_linear_grids(struct Object *object,
struct MultiresModifierData *mmd);
@@ -226,8 +226,8 @@ void multires_subdivide_create_tangent_displacement_linear_grids(struct Object *
*/
void multiresModifier_subdivide_to_level(struct Object *object,
struct MultiresModifierData *mmd,
- const int top_level,
- const eMultiresSubdivideModeType mode);
+ int top_level,
+ eMultiresSubdivideModeType mode);
/* Subdivision integration, defined in multires_subdiv.c */
@@ -242,9 +242,9 @@ void BKE_multires_subdiv_mesh_settings_init(struct SubdivToMeshSettings *mesh_se
const struct Scene *scene,
const struct Object *object,
const struct MultiresModifierData *mmd,
- const bool use_render_params,
- const bool ignore_simplify,
- const bool ignore_control_edges);
+ bool use_render_params,
+ bool ignore_simplify,
+ bool ignore_control_edges);
/* General helpers. */
@@ -257,7 +257,7 @@ void BKE_multires_subdiv_mesh_settings_init(struct SubdivToMeshSettings *mesh_se
BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3],
const float dPdu[3],
const float dPdv[3],
- const int corner);
+ int corner);
/* Versioning. */
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index b297851ad90..61431547bfb 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -71,8 +71,8 @@ void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user);
*/
struct NlaStrip *BKE_nlastrip_copy(struct Main *bmain,
struct NlaStrip *strip,
- const bool use_same_action,
- const int flag);
+ bool use_same_action,
+ int flag);
/**
* Copy a single NLA Track.
* \param flag: Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_...
@@ -80,14 +80,14 @@ struct NlaStrip *BKE_nlastrip_copy(struct Main *bmain,
*/
struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain,
struct NlaTrack *nlt,
- const bool use_same_actions,
- const int flag);
+ bool use_same_actions,
+ 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);
+void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, const ListBase *src, int flag);
/**
* Copy NLA tracks from #adt_source to #adt_dest, and update the active track/strip pointers to
@@ -115,7 +115,7 @@ struct NlaStrip *BKE_nlastrip_new(struct bAction *act);
*/
struct NlaStrip *BKE_nlastack_add_strip(struct AnimData *adt,
struct bAction *act,
- const bool is_liboverride);
+ bool is_liboverride);
/**
* Add a NLA Strip referencing the given speaker's sound.
*/
@@ -217,9 +217,7 @@ 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);
+bool BKE_nlatrack_add_strip(struct NlaTrack *nlt, struct NlaStrip *strip, bool is_liboverride);
/**
* Get the extents of the given NLA-Track including gaps between strips,
@@ -309,7 +307,7 @@ 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);
+bool BKE_nla_action_stash(struct AnimData *adt, bool is_liboverride);
/* ............ */
@@ -321,7 +319,7 @@ bool BKE_nla_action_stash(struct AnimData *adt, const bool is_liboverride);
*
* TODO: maybe we should have checks for this too.
*/
-void BKE_nla_action_pushdown(struct AnimData *adt, const bool is_liboverride);
+void BKE_nla_action_pushdown(struct AnimData *adt, bool is_liboverride);
/**
* Find the active strip + track combination, and set them up as the tweaking track,
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 2038842ee59..16d8ba2e6dd 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -34,6 +34,11 @@
#include "RNA_types.h"
#ifdef __cplusplus
+# include "BLI_map.hh"
+# include "BLI_string_ref.hh"
+#endif
+
+#ifdef __cplusplus
extern "C" {
#endif
@@ -114,6 +119,7 @@ namespace nodes {
class NodeMultiFunctionBuilder;
class GeoNodeExecParams;
class NodeDeclarationBuilder;
+class GatherLinkSearchOpParams;
} // namespace nodes
namespace fn {
class CPPType;
@@ -129,10 +135,15 @@ using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, voi
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;
@@ -284,7 +295,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
@@ -325,6 +336,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;
@@ -339,22 +357,11 @@ typedef struct bNodeType {
#define NODE_CLASS_OP_VECTOR 4
#define NODE_CLASS_OP_FILTER 5
#define NODE_CLASS_GROUP 6
-// #define NODE_CLASS_FILE 7
#define NODE_CLASS_CONVERTER 8
#define NODE_CLASS_MATTE 9
#define NODE_CLASS_DISTORT 10
-// #define NODE_CLASS_OP_DYNAMIC 11 /* deprecated */
#define NODE_CLASS_PATTERN 12
#define NODE_CLASS_TEXTURE 13
-// #define NODE_CLASS_EXECUTION 14
-// #define NODE_CLASS_GETDATA 15
-// #define NODE_CLASS_SETDATA 16
-// #define NODE_CLASS_MATH 17
-// #define NODE_CLASS_MATH_VECTOR 18
-// #define NODE_CLASS_MATH_ROTATION 19
-// #define NODE_CLASS_PARTICLES 25
-// #define NODE_CLASS_TRANSFORM 30
-// #define NODE_CLASS_COMBINE 31
#define NODE_CLASS_SCRIPT 32
#define NODE_CLASS_INTERFACE 33
#define NODE_CLASS_SHADER 40
@@ -396,13 +403,12 @@ typedef struct bNodeTreeType {
/* calls allowing threaded composite */
void (*localize)(struct bNodeTree *localtree, struct bNodeTree *ntree);
- void (*local_sync)(struct bNodeTree *localtree, struct bNodeTree *ntree);
void (*local_merge)(struct Main *bmain, struct bNodeTree *localtree, struct bNodeTree *ntree);
/* Tree update. Overrides `nodetype->updatetreefunc` ! */
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);
@@ -464,7 +470,7 @@ void ntreeFreeTree(struct bNodeTree *ntree);
void ntreeFreeEmbeddedTree(struct bNodeTree *ntree);
struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree,
struct Main *bmain,
- const bool do_id_user);
+ bool do_id_user);
struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree);
/**
@@ -482,18 +488,14 @@ struct bNodeTree *ntreeFromID(struct ID *id);
void ntreeFreeLocalNode(struct bNodeTree *ntree, struct bNode *node);
void ntreeFreeLocalTree(struct bNodeTree *ntree);
struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type);
-bool ntreeHasType(const struct bNodeTree *ntree, int type);
bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
-void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree);
void ntreeUpdateAllNew(struct Main *main);
-/**
- * \param tree_update_flag: #eNodeTreeUpdate enum.
- */
-void ntreeUpdateAllUsers(struct Main *main, struct ID *id, int tree_update_flag);
+void ntreeUpdateAllUsers(struct Main *main, struct ID *id);
void ntreeGetDependencyList(struct bNodeTree *ntree,
struct bNode ***r_deplist,
int *r_deplist_len);
+void ntreeUpdateNodeLevels(struct bNodeTree *ntree);
/**
* XXX: old trees handle output flags automatically based on special output
@@ -504,21 +506,12 @@ void ntreeSetOutput(struct bNodeTree *ntree);
void ntreeFreeCache(struct bNodeTree *ntree);
-bool ntreeNodeExists(const struct bNodeTree *ntree, const struct bNode *testnode);
-bool ntreeOutputExists(const struct bNode *node, const struct bNodeSocket *testsock);
-void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable);
+void ntreeNodeFlagSet(const bNodeTree *ntree, int flag, 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.
@@ -629,13 +622,6 @@ struct bNodeSocket *nodeAddSocket(struct bNodeTree *ntree,
const char *idname,
const char *identifier,
const char *name);
-struct bNodeSocket *nodeInsertSocket(struct bNodeTree *ntree,
- struct bNode *node,
- eNodeSocketInOut in_out,
- const char *idname,
- struct bNodeSocket *next_sock,
- const char *identifier,
- const char *name);
struct bNodeSocket *nodeAddStaticSocket(struct bNodeTree *ntree,
struct bNode *node,
eNodeSocketInOut in_out,
@@ -643,14 +629,6 @@ struct bNodeSocket *nodeAddStaticSocket(struct bNodeTree *ntree,
int subtype,
const char *identifier,
const char *name);
-struct bNodeSocket *nodeInsertStaticSocket(struct bNodeTree *ntree,
- struct bNode *node,
- eNodeSocketInOut in_out,
- int type,
- int subtype,
- struct bNodeSocket *next_sock,
- const char *identifier,
- const char *name);
void nodeRemoveSocket(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock);
void nodeRemoveSocketEx(struct bNodeTree *ntree,
struct bNode *node,
@@ -683,31 +661,26 @@ void nodeRemoveNode(struct Main *bmain,
struct bNode *node,
bool do_id_user);
-/**
- * \param ntree: is the target tree.
- *
- * \note keep socket list order identical, for copying links.
- * \note `unique_name` needs to be true. It's only disabled for speed when doing GPUnodetrees.
- */
-struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree,
- const struct bNode *node_src,
- const int flag,
- const bool unique_name);
+#ifdef __cplusplus
+
+namespace blender::bke {
/**
- * Same as #BKE_node_copy_ex but stores pointers to a new node and its sockets in the source node.
- *
- * NOTE: DANGER ZONE!
- *
- * TODO(sergey): Maybe it's better to make BKE_node_copy_ex() return a mapping from old node and
- * sockets to new one.
+ * \note keeps socket list order identical, for copying links.
+ * \note `unique_name` should usually be true, unless the \a dst_tree is temporary,
+ * or the names can already be assumed valid.
*/
-struct bNode *BKE_node_copy_store_new_pointers(struct bNodeTree *ntree,
- struct bNode *node_src,
- const int flag);
-struct bNodeTree *ntreeCopyTree_ex_new_pointers(const struct bNodeTree *ntree,
- struct Main *bmain,
- const bool do_id_user);
+bNode *node_copy_with_mapping(bNodeTree *dst_tree,
+ const bNode &node_src,
+ int flag,
+ bool unique_name,
+ Map<const bNodeSocket *, bNodeSocket *> &new_socket_map);
+
+bNode *node_copy(bNodeTree *dst_tree, const bNode &src_node, int flag, bool unique_name);
+
+} // namespace blender::bke
+
+#endif
/**
* Also used via RNA API, so we check for proper input output direction.
@@ -768,7 +741,7 @@ void nodeChainIter(const bNodeTree *ntree,
const bNode *node_start,
bool (*callback)(bNode *, bNode *, void *, const bool),
void *userdata,
- const bool reversed);
+ 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).
@@ -804,24 +777,13 @@ void nodeSetSelected(struct bNode *node, bool select);
*/
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);
-void nodeUpdate(struct bNodeTree *ntree, struct bNode *node);
-bool nodeUpdateID(struct bNodeTree *ntree, struct ID *id);
-void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
-
int nodeSocketIsHidden(const struct bNodeSocket *sock);
-void ntreeTagUsedSockets(struct bNodeTree *ntree);
void nodeSetSocketAvailability(struct bNodeTree *ntree,
struct bNodeSocket *sock,
bool is_available);
@@ -943,28 +905,15 @@ bNodePreview *BKE_node_preview_verify(
struct bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create);
bNodePreview *BKE_node_preview_copy(struct bNodePreview *preview);
void BKE_node_preview_free(struct bNodePreview *preview);
-void BKE_node_preview_init_tree(struct bNodeTree *ntree,
- int xsize,
- int ysize,
- bool create_previews);
-void BKE_node_preview_free_tree(struct bNodeTree *ntree);
+void BKE_node_preview_init_tree(struct bNodeTree *ntree, int xsize, int ysize);
void BKE_node_preview_remove_unused(struct bNodeTree *ntree);
void BKE_node_preview_clear(struct bNodePreview *preview);
void BKE_node_preview_clear_tree(struct bNodeTree *ntree);
-void BKE_node_preview_sync_tree(struct bNodeTree *to_ntree, struct bNodeTree *from_ntree);
void BKE_node_preview_merge_tree(struct bNodeTree *to_ntree,
struct bNodeTree *from_ntree,
bool remove_old);
-/**
- * Hack warning! this function is only used for shader previews,
- * and since it gets called multiple times per pixel for Z-transparency we only add the color once.
- * Preview gets cleared before it starts render though.
- */
-void BKE_node_preview_set_pixel(
- struct bNodePreview *preview, const float col[4], int x, int y, bool do_manage);
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -984,9 +933,11 @@ bool nodeGroupPoll(struct bNodeTree *nodetree,
/**
* Initialize a new node type struct with default values and callbacks.
*/
-void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
-void node_type_base_custom(
- struct bNodeType *ntype, const char *idname, const char *name, short nclass, short flag);
+void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
+void node_type_base_custom(struct bNodeType *ntype,
+ const char *idname,
+ const char *name,
+ short nclass);
void node_type_socket_templates(struct bNodeType *ntype,
struct bNodeSocketTemplate *inputs,
struct bNodeSocketTemplate *outputs);
@@ -1116,20 +1067,13 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
/** \name Node Tree
*/
-void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
- struct Scene *scene,
- const int layer_index);
+void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, int layer_index);
/* -------------------------------------------------------------------- */
/** \name Shader Nodes
* \{ */
/* NOTE: types are needed to restore callbacks, don't change values. */
-/* range 1 - 100 is reserved for common nodes */
-/* using toolbox, we add node groups by assuming the values below
- * don't exceed NODE_GROUP_MENU for now. */
-
-//#define SH_NODE_OUTPUT 1
//#define SH_NODE_MATERIAL 100
#define SH_NODE_RGB 101
@@ -1153,7 +1097,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_SEPRGB 120
#define SH_NODE_COMBRGB 121
#define SH_NODE_HUE_SAT 122
-#define NODE_DYNAMIC 123
#define SH_NODE_OUTPUT_MATERIAL 124
#define SH_NODE_OUTPUT_WORLD 125
@@ -1235,35 +1178,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_OUTPUT_AOV 707
#define SH_NODE_VECTOR_ROTATE 708
#define SH_NODE_CURVE_FLOAT 709
-
-/* custom defines options for Material node */
-// #define SH_NODE_MAT_DIFF 1
-// #define SH_NODE_MAT_SPEC 2
-// #define SH_NODE_MAT_NEG 4
-
-/* API */
-
-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,
- bool *has_volume_output);
+#define SH_NODE_POINT_INFO 710
/** \} */
@@ -1274,36 +1189,6 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
/* output socket defines */
#define RRES_OUT_IMAGE 0
#define RRES_OUT_ALPHA 1
-// #define RRES_OUT_Z 2
-// #define RRES_OUT_NORMAL 3
-// #define RRES_OUT_UV 4
-// #define RRES_OUT_VEC 5
-// #define RRES_OUT_RGBA 6
-#define RRES_OUT_DIFF 7
-// #define RRES_OUT_SPEC 8
-// #define RRES_OUT_SHADOW 9
-// #define RRES_OUT_AO 10
-// #define RRES_OUT_REFLECT 11
-// #define RRES_OUT_REFRACT 12
-// #define RRES_OUT_INDIRECT 13
-// #define RRES_OUT_INDEXOB 14
-// #define RRES_OUT_INDEXMA 15
-// #define RRES_OUT_MIST 16
-// #define RRES_OUT_EMIT 17
-// #define RRES_OUT_ENV 18
-// #define RRES_OUT_DIFF_DIRECT 19
-// #define RRES_OUT_DIFF_INDIRECT 20
-// #define RRES_OUT_DIFF_COLOR 21
-// #define RRES_OUT_GLOSSY_DIRECT 22
-// #define RRES_OUT_GLOSSY_INDIRECT 23
-// #define RRES_OUT_GLOSSY_COLOR 24
-// #define RRES_OUT_TRANSM_DIRECT 25
-// #define RRES_OUT_TRANSM_INDIRECT 26
-// #define RRES_OUT_TRANSM_COLOR 27
-// #define RRES_OUT_SUBSURFACE_DIRECT 28
-// #define RRES_OUT_SUBSURFACE_INDIRECT 29
-// #define RRES_OUT_SUBSURFACE_COLOR 30
-// #define RRES_OUT_DEBUG 31
/* NOTE: types are needed to restore callbacks, don't change values. */
#define CMP_NODE_VIEWER 201
@@ -1404,6 +1289,8 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
#define CMP_NODE_EXPOSURE 325
#define CMP_NODE_CRYPTOMATTE 326
#define CMP_NODE_POSTERIZE 327
+#define CMP_NODE_CONVERT_COLOR_SPACE 328
+#define CMP_NODE_SCENE_TIME 329
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -1442,81 +1329,6 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
#define CMP_DEFAULT_SMAA_CONTRAST_LIMIT 0.2f
#define CMP_DEFAULT_SMAA_CORNER_ROUNDING 0.25f
-/* API */
-void ntreeCompositExecTree(struct Scene *scene,
- struct bNodeTree *ntree,
- struct RenderData *rd,
- int rendering,
- int do_previews,
- 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,
- struct ViewLayer *view_layer,
- const char *name,
- eNodeSocketDatatype type);
-void ntreeCompositClearTags(struct bNodeTree *ntree);
-
-struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree,
- struct bNode *node,
- const char *name,
- struct ImageFormatData *im_format);
-int ntreeCompositOutputFileRemoveActiveSocket(struct bNodeTree *ntree, struct bNode *node);
-void ntreeCompositOutputFileSetPath(struct bNode *node,
- struct bNodeSocket *sock,
- const char *name);
-void ntreeCompositOutputFileSetLayer(struct bNode *node,
- struct bNodeSocket *sock,
- const char *name);
-/* needed in do_versions */
-void ntreeCompositOutputFileUniquePath(struct ListBase *list,
- struct bNodeSocket *sock,
- const char defname[],
- char delim);
-void ntreeCompositOutputFileUniqueLayer(struct ListBase *list,
- struct bNodeSocket *sock,
- const char defname[],
- char delim);
-
-void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
-void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
-
-void ntreeCompositCryptomatteSyncFromAdd(const Scene *scene, bNode *node);
-void ntreeCompositCryptomatteSyncFromRemove(bNode *node);
-bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node);
-int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node);
-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.
- */
-void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node);
-struct CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *node);
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1553,24 +1365,6 @@ struct TexResult;
#define TEX_NODE_PROC 500
#define TEX_NODE_PROC_MAX 600
-/* API */
-void ntreeTexCheckCyclics(struct bNodeTree *ntree);
-
-struct bNodeTreeExec *ntreeTexBeginExecTree(struct bNodeTree *ntree);
-void ntreeTexEndExecTree(struct bNodeTreeExec *exec);
-int ntreeTexExecTree(struct bNodeTree *ntree,
- struct TexResult *target,
- const float co[3],
- float dxt[3],
- float dyt[3],
- int osatex,
- const short thread,
- const struct Tex *tex,
- short which_output,
- int cfra,
- int preview,
- struct MTex *mtex);
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1722,6 +1516,14 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS 1143
#define GEO_NODE_INPUT_MESH_ISLAND 1144
#define GEO_NODE_INPUT_SCENE_TIME 1145
+#define GEO_NODE_ACCUMULATE_FIELD 1146
+#define GEO_NODE_INPUT_MESH_EDGE_ANGLE 1147
+#define GEO_NODE_FIELD_AT_INDEX 1148
+#define GEO_NODE_CURVE_PRIMITIVE_ARC 1149
+#define GEO_NODE_FLIP_FACES 1150
+#define GEO_NODE_SCALE_ELEMENTS 1151
+#define GEO_NODE_EXTRUDE_MESH 1152
+#define GEO_NODE_MERGE_BY_DISTANCE 1153
/** \} */
@@ -1752,15 +1554,6 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
void BKE_node_system_init(void);
void BKE_node_system_exit(void);
-/* -------------------------------------------------------------------- */
-/* evaluation support, */
-
-struct Depsgraph;
-
-void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph,
- struct bNodeTree *ntree_dst,
- const struct bNodeTree *ntree_src);
-
extern struct bNodeType NodeTypeUndefined;
extern struct bNodeSocketType NodeSocketTypeUndefined;
@@ -1768,6 +1561,18 @@ extern struct bNodeSocketType NodeSocketTypeUndefined;
}
#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) \
{ \
diff --git a/source/blender/blenkernel/BKE_node_tree_update.h b/source/blender/blenkernel/BKE_node_tree_update.h
new file mode 100644
index 00000000000..443ceafb073
--- /dev/null
+++ b/source/blender/blenkernel/BKE_node_tree_update.h
@@ -0,0 +1,110 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+struct ID;
+struct Main;
+struct bNode;
+struct bNodeLink;
+struct bNodeSocket;
+struct bNodeTree;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Tag tree as changed without providing any more information about what has changed exactly.
+ * The update process has to assume that everything may have changed.
+ *
+ * Using one of the methods below to tag the tree after changes is preferred when possible.
+ */
+void BKE_ntree_update_tag_all(struct bNodeTree *ntree);
+
+/**
+ * More specialized tag functions that may result in a more efficient update.
+ */
+
+void BKE_ntree_update_tag_node_property(struct bNodeTree *ntree, struct bNode *node);
+void BKE_ntree_update_tag_node_new(struct bNodeTree *ntree, struct bNode *node);
+void BKE_ntree_update_tag_node_removed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_node_mute(struct bNodeTree *ntree, struct bNode *node);
+void BKE_ntree_update_tag_node_internal_link(struct bNodeTree *ntree, struct bNode *node);
+
+void BKE_ntree_update_tag_socket_property(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_new(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_type(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_availability(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_removed(struct bNodeTree *ntree);
+
+void BKE_ntree_update_tag_link_changed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_link_removed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_link_added(struct bNodeTree *ntree, struct bNodeLink *link);
+void BKE_ntree_update_tag_link_mute(struct bNodeTree *ntree, struct bNodeLink *link);
+
+/** Used after file loading when run-time data on the tree has not been initialized yet. */
+void BKE_ntree_update_tag_missing_runtime_data(struct bNodeTree *ntree);
+/** Used when the interface sockets/values have changed. */
+void BKE_ntree_update_tag_interface(struct bNodeTree *ntree);
+/** Used when an id data block changed that might be used by nodes that need to be updated. */
+void BKE_ntree_update_tag_id_changed(struct Main *bmain, struct ID *id);
+
+typedef struct NodeTreeUpdateExtraParams {
+ /**
+ * Data passed into the callbacks.
+ */
+ void *user_data;
+
+ /**
+ * Called for every tree that has been changed during the update. This can be used to send
+ * notifiers to trigger redraws or depsgraph updates.
+ */
+ void (*tree_changed_fn)(struct ID *, struct bNodeTree *, void *user_data);
+
+ /**
+ * Called for every tree whose output value may have changed based on the provided update tags.
+ * This can be used to tag the depsgraph if necessary.
+ */
+ void (*tree_output_changed_fn)(struct ID *, struct bNodeTree *, void *user_data);
+} NodeTreeUpdateExtraParams;
+
+/**
+ * Updates #bmain based on changes to node trees.
+ */
+void BKE_ntree_update_main(struct Main *bmain, struct NodeTreeUpdateExtraParams *params);
+
+/**
+ * Same as #BKE_ntree_update_main, but will first only look at the provided tree and only looks
+ * at #bmain when something relevant for other data-blocks changed. This avoids scanning #bmain in
+ * many cases.
+ *
+ * If #bmain is null, only the provided tree is updated. This should only be used in very rare
+ * cases because it may result it incorrectly synced data in DNA.
+ *
+ * If #tree is null, this is the same as calling #BKE_ntree_update_main.
+ */
+void BKE_ntree_update_main_tree(struct Main *bmain,
+ struct bNodeTree *ntree,
+ struct NodeTreeUpdateExtraParams *params);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 03565bd3bda..99758f4ad78 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -48,6 +48,7 @@ struct RegionView3D;
struct RigidBodyWorld;
struct Scene;
struct ShaderFxData;
+struct SubsurfModifierData;
struct View3D;
struct ViewLayer;
@@ -66,11 +67,9 @@ void BKE_object_workob_calc_parent(struct Depsgraph *depsgraph,
struct Object *workob);
void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src);
-void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag);
-struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys, const int flag);
-void BKE_object_copy_particlesystems(struct Object *ob_dst,
- const struct Object *ob_src,
- const int flag);
+void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, int flag);
+struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys, int flag);
+void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src, int flag);
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);
@@ -139,11 +138,11 @@ bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, struct GpencilModif
*/
bool BKE_object_modifier_stack_copy(struct Object *ob_dst,
const struct Object *ob_src,
- const bool do_copy_all,
- const int flag_subdata);
+ bool do_copy_all,
+ int flag_subdata);
void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src);
-void BKE_object_free_modifiers(struct Object *ob, const int flag);
-void BKE_object_free_shaderfx(struct Object *ob, const int flag);
+void BKE_object_free_modifiers(struct Object *ob, int flag);
+void BKE_object_free_shaderfx(struct Object *ob, int flag);
/**
* Proxy rule:
@@ -186,7 +185,7 @@ typedef enum 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);
+int BKE_object_visibility(const struct Object *ob, int dag_eval_mode);
/**
* More general add: creates minimum required data, but without vertices etc.
@@ -267,7 +266,7 @@ struct Object *BKE_object_duplicate(struct Main *bmain,
/**
* 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_obdata_size_init(struct Object *ob, float size);
void BKE_object_scale_to_mat3(struct Object *ob, float r_mat[3][3]);
void BKE_object_rot_to_mat3(const struct Object *ob, float r_mat[3][3], bool use_drot);
@@ -288,12 +287,12 @@ 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);
+ 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);
+ bool use_compat,
+ 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);
@@ -378,20 +377,20 @@ void BKE_object_dimensions_set_ex(struct Object *ob,
const float ob_obmat_orig[4][4]);
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);
+void BKE_object_empty_draw_type_set(struct Object *ob, 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_flag(struct Object *ob, int flag, 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);
+void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], bool use_hidden);
bool BKE_object_minmax_dupli(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
float r_min[3],
float r_max[3],
- const bool use_hidden);
+ bool use_hidden);
/**
* Sometimes min-max isn't enough, we need to loop over each point.
@@ -422,7 +421,7 @@ void BKE_object_tfm_protected_backup(const struct Object *ob, ObjectTfmProtected
void BKE_object_tfm_protected_restore(struct Object *ob,
const ObjectTfmProtectedChannels *obtfm,
- const short protectflag);
+ short protectflag);
void BKE_object_tfm_copy(struct Object *object_dst, const struct Object *object_src);
@@ -470,10 +469,10 @@ void BKE_object_select_update(struct Depsgraph *depsgraph, struct Object *object
void BKE_object_eval_eval_base_flags(struct Depsgraph *depsgraph,
struct Scene *scene,
- const int view_layer_index,
+ int view_layer_index,
struct Object *object,
int base_index,
- const bool is_from_set);
+ bool is_from_set);
void BKE_object_handle_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -493,7 +492,7 @@ void BKE_object_handle_update(struct Depsgraph *depsgraph, struct Scene *scene,
*
* Function below is polluted with proxy exceptions, cleanup will follow!
*
- * The main object update call, for object matrix, constraints, keys and displist (modifiers)
+ * 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,
@@ -503,7 +502,7 @@ void BKE_object_handle_update_ex(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct RigidBodyWorld *rbw,
- const bool do_proxy_update);
+ bool do_proxy_update);
void BKE_object_sculpt_data_create(struct Object *ob);
@@ -512,6 +511,7 @@ bool BKE_object_obdata_texspace_get(struct Object *ob,
float **r_loc,
float **r_size);
+struct Mesh *BKE_object_get_evaluated_mesh_no_subsurf(const struct Object *object);
/** Get evaluated mesh for given object. */
struct Mesh *BKE_object_get_evaluated_mesh(const struct Object *object);
/**
@@ -530,6 +530,9 @@ struct Mesh *BKE_object_get_pre_modified_mesh(const struct Object *object);
*/
struct Mesh *BKE_object_get_original_mesh(const struct Object *object);
+struct Mesh *BKE_object_get_editmesh_eval_final(const struct Object *object);
+struct Mesh *BKE_object_get_editmesh_eval_cage(const struct Object *object);
+
/* Lattice accessors.
* These functions return either the regular lattice, or the edit-mode lattice,
* whichever is currently in use. */
@@ -542,7 +545,7 @@ void BKE_object_delete_ptcache(struct Object *ob, int index);
struct KeyBlock *BKE_object_shapekey_insert(struct Main *bmain,
struct Object *ob,
const char *name,
- const bool from_mix);
+ bool from_mix);
bool BKE_object_shapekey_remove(struct Main *bmain, struct Object *ob, struct KeyBlock *kb);
bool BKE_object_shapekey_free(struct Main *bmain, struct Object *ob);
@@ -592,7 +595,7 @@ 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);
+void BKE_object_runtime_reset_on_copy(struct Object *object, int flag);
/**
* The function frees memory used by the runtime data, but not the runtime field itself.
*
@@ -712,6 +715,15 @@ void BKE_object_modifiers_lib_link_common(void *userData,
struct ID **idpoin,
int cb_flag);
+/**
+ * Return the last subsurf modifier of an object, this does not check whether modifiers on top of
+ * it are disabled. Return NULL if no such modifier is found.
+ *
+ * This does not check if the modifier is enabled as it is assumed that the caller verified that it
+ * is enabled for its evaluation mode.
+ */
+struct SubsurfModifierData *BKE_object_get_last_subsurf_modifier(const struct Object *ob);
+
void BKE_object_replace_data_on_shallow_copy(struct Object *ob, struct ID *new_data);
struct PartEff;
diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h
index ddbf5178ab0..fe7a9ddc633 100644
--- a/source/blender/blenkernel/BKE_object_deform.h
+++ b/source/blender/blenkernel/BKE_object_deform.h
@@ -68,16 +68,14 @@ struct MDeformVert *BKE_object_defgroup_data_create(struct ID *id);
* \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);
+bool BKE_object_defgroup_clear(struct Object *ob, struct bDeformGroup *dg, 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);
+bool BKE_object_defgroup_clear_all(struct Object *ob, bool use_selection);
/**
* Remove given vgroup from object. Work in Object and Edit modes.
@@ -120,7 +118,7 @@ bool *BKE_object_defgroup_subset_from_select_type(struct Object *ob,
* 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 defgroup_tot,
int *r_defgroup_subset_map);
/* ********** */
@@ -129,8 +127,8 @@ void BKE_object_defgroup_subset_to_index_array(const bool *defgroup_validmap,
* 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);
+bool *BKE_object_defgroup_lock_flags_get(struct Object *ob, int defbase_tot);
+bool *BKE_object_defgroup_validmap_get(struct Object *ob, int defbase_tot);
/**
* Returns total selected vgroups,
* `wpi.defbase_sel` is assumed malloc'd, all values are set.
diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h
index 4388190221d..f598fb09773 100644
--- a/source/blender/blenkernel/BKE_ocean.h
+++ b/source/blender/blenkernel/BKE_ocean.h
@@ -73,13 +73,13 @@ typedef struct OceanCache {
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);
+bool BKE_ocean_ensure(struct OceanModifierData *omd, 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);
+ int resolution);
/**
* Return true if the ocean is valid and can be used.
@@ -162,12 +162,12 @@ void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd);
* 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);
+float BLI_ocean_spectrum_piersonmoskowitz(const struct Ocean *oc, float kx, 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);
+float BLI_ocean_spectrum_texelmarsenarsloe(const struct Ocean *oc, float kx, 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
@@ -176,7 +176,7 @@ float BLI_ocean_spectrum_texelmarsenarsloe(const struct Ocean *oc, const float k
* 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);
+float BLI_ocean_spectrum_jonswap(const struct Ocean *oc, float kx, float kz);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h
index e3deff9d8fa..87a46f5f888 100644
--- a/source/blender/blenkernel/BKE_packedFile.h
+++ b/source/blender/blenkernel/BKE_packedFile.h
@@ -120,7 +120,7 @@ int BKE_packedfile_write_to_file(struct ReportList *reports,
const char *ref_file_name,
const char *filename,
struct PackedFile *pf,
- const bool guimode);
+ bool guimode);
/* Free. */
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 40e3ab74fac..4019c4d62c4 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -148,14 +148,14 @@ bool BKE_palette_is_empty(const struct Palette *palette);
void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color);
void BKE_palette_clear(struct Palette *palette);
-void BKE_palette_sort_hsv(struct tPaletteColorHSV *color_array, const int totcol);
-void BKE_palette_sort_svh(struct tPaletteColorHSV *color_array, const int totcol);
-void BKE_palette_sort_vhs(struct tPaletteColorHSV *color_array, const int totcol);
-void BKE_palette_sort_luminance(struct tPaletteColorHSV *color_array, const int totcol);
+void BKE_palette_sort_hsv(struct tPaletteColorHSV *color_array, int totcol);
+void BKE_palette_sort_svh(struct tPaletteColorHSV *color_array, int totcol);
+void BKE_palette_sort_vhs(struct tPaletteColorHSV *color_array, int totcol);
+void BKE_palette_sort_luminance(struct tPaletteColorHSV *color_array, int totcol);
bool BKE_palette_from_hash(struct Main *bmain,
struct GHash *color_table,
const char *name,
- const bool linear);
+ bool linear);
/* Paint curves. */
@@ -172,7 +172,7 @@ void BKE_paint_free(struct Paint *p);
* #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_copy(struct Paint *src, struct Paint *tar, int flag);
void BKE_paint_runtime_init(const struct ToolSettings *ts, struct Paint *paint);
@@ -183,7 +183,7 @@ bool BKE_paint_ensure_from_paintmode(struct Scene *sce, ePaintMode mode);
struct Paint *BKE_paint_get_active_from_paintmode(struct Scene *sce, ePaintMode mode);
const struct EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode);
const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode);
-uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode);
+uint BKE_paint_get_brush_tool_offset_from_paintmode(ePaintMode mode);
struct Paint *BKE_paint_get_active(struct Scene *sce, struct ViewLayer *view_layer);
struct Paint *BKE_paint_get_active_from_context(const struct bContext *C);
ePaintMode BKE_paintmode_get_active_from_context(const struct bContext *C);
@@ -193,7 +193,7 @@ void BKE_paint_brush_set(struct Paint *paint, struct Brush *br);
struct Palette *BKE_paint_palette(struct Paint *paint);
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);
+void BKE_paint_curve_clamp_endpoint_add_index(struct PaintCurve *pc, int add_index);
/**
* Return true when in vertex/weight/texture paint + face-select mode?
@@ -231,7 +231,7 @@ bool paint_is_bmesh_face_hidden(struct BMFace *f);
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]);
+void BKE_paint_face_set_overlay_color_get(int face_set, int seed, uchar r_color[4]);
/* Stroke related. */
@@ -499,6 +499,7 @@ typedef struct SculptSession {
/* These are always assigned to base mesh data when using PBVH_FACES and PBVH_GRIDS. */
struct MVert *mvert;
+ const float (*vert_normals)[3];
struct MPoly *mpoly;
struct MLoop *mloop;
@@ -616,10 +617,6 @@ typedef struct SculptSession {
float init_pivot_rot[4];
float init_pivot_scale[3];
- float prev_pivot_pos[3];
- float prev_pivot_rot[4];
- float prev_pivot_scale[3];
-
union {
struct {
struct SculptVertexPaintGeomMap gmap;
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 972cba2d132..804331a3412 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -294,10 +294,8 @@ int count_particles_mod(struct ParticleSystem *psys, int totgr, int cur);
int psys_get_child_number(struct Scene *scene,
struct ParticleSystem *psys,
- const bool use_render_params);
-int psys_get_tot_child(struct Scene *scene,
- struct ParticleSystem *psys,
- const bool use_render_params);
+ bool use_render_params);
+int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys, bool use_render_params);
/**
* Get object's active particle system safely.
@@ -329,9 +327,7 @@ struct ParticleSystem *psys_eval_get(struct Depsgraph *depsgraph,
struct ParticleSystem *psys);
bool psys_in_edit_mode(struct Depsgraph *depsgraph, const struct ParticleSystem *psys);
-bool psys_check_enabled(struct Object *ob,
- struct ParticleSystem *psys,
- const bool use_render_params);
+bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, bool use_render_params);
bool psys_check_edited(struct ParticleSystem *psys);
void psys_find_group_weights(struct ParticleSettings *part);
@@ -392,7 +388,7 @@ void object_remove_particle_system(struct Main *bmain,
struct ParticleSettings *BKE_particlesettings_add(struct Main *bmain, const char *name);
void psys_reset(struct ParticleSystem *psys, int mode);
-void psys_find_parents(struct ParticleSimulationData *sim, const bool use_render_params);
+void psys_find_parents(struct ParticleSimulationData *sim, bool use_render_params);
void psys_unique_name(struct Object *object, struct ParticleSystem *psys, const char *defname);
@@ -402,19 +398,17 @@ void psys_unique_name(struct Object *object, struct ParticleSystem *psys, const
* - 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);
+void psys_cache_paths(struct ParticleSimulationData *sim, float cfra, bool use_render_params);
void psys_cache_edit_paths(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct PTCacheEdit *edit,
float cfra,
- const bool use_render_params);
+ bool use_render_params);
void psys_cache_child_paths(struct ParticleSimulationData *sim,
float cfra,
- const bool editupdate,
- const bool use_render_params);
+ bool editupdate,
+ bool use_render_params);
int do_guides(struct Depsgraph *depsgraph,
struct ParticleSettings *part,
struct ListBase *effectors,
@@ -438,7 +432,7 @@ float psys_get_child_size(struct ParticleSystem *psys,
void psys_get_particle_on_path(struct ParticleSimulationData *sim,
int pa_num,
struct ParticleKey *state,
- const bool vel);
+ bool vel);
/**
* Gets particle's state at a time.
* \return true if particle exists and can be seen and false if not.
@@ -446,7 +440,7 @@ void psys_get_particle_on_path(struct ParticleSimulationData *sim,
bool psys_get_particle_state(struct ParticleSimulationData *sim,
int p,
struct ParticleKey *state,
- const bool always);
+ bool always);
/* Child paths. */
@@ -539,7 +533,7 @@ void particle_system_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct ParticleSystem *psys,
- const bool use_render_params);
+ bool use_render_params);
/**
* Callback format for performing operations on ID-pointers for particle systems.
@@ -603,6 +597,7 @@ void psys_get_texture(struct ParticleSimulationData *sim,
* Interpolate a location on a face based on face coordinates.
*/
void psys_interpolate_face(struct MVert *mvert,
+ const float (*vert_normals)[3],
struct MFace *mface,
struct MTFace *tface,
float (*orcodata)[3],
@@ -678,8 +673,7 @@ void reset_particle(struct ParticleSimulationData *sim,
float dtime,
float cfra);
-float psys_get_current_display_percentage(struct ParticleSystem *psys,
- const bool use_render_params);
+float psys_get_current_display_percentage(struct ParticleSystem *psys, bool use_render_params);
/* psys_reset */
#define PSYS_RESET_ALL 1
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 5e7a9883de6..1ef1c98ce83 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -110,7 +110,7 @@ PBVH *BKE_pbvh_new(void);
* (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,
+ struct Mesh *mesh,
const struct MPoly *mpoly,
const struct MLoop *mloop,
struct MVert *verts,
@@ -137,8 +137,8 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
struct BMesh *bm,
bool smooth_shading,
struct BMLog *log,
- const int cd_vert_node_offset,
- const int cd_face_node_offset);
+ int cd_vert_node_offset,
+ int cd_face_node_offset);
void BKE_pbvh_free(PBVH *pbvh);
/* Hierarchical Search in the BVH, two methods:
@@ -279,8 +279,8 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
const float center[3],
const float view_normal[3],
float radius,
- const bool use_frontface,
- const bool use_projected);
+ bool use_frontface,
+ bool use_projected);
/* Node Access */
@@ -361,7 +361,7 @@ void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide);
/* 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);
+void BKE_pbvh_vert_coords_apply(struct PBVH *pbvh, const float (*vertCos)[3], int totvert);
bool BKE_pbvh_is_deformed(struct PBVH *pbvh);
/* Vertex Iterator. */
@@ -397,6 +397,7 @@ typedef struct PBVHVertexIter {
/* mesh */
struct MVert *mverts;
+ float (*vert_normals)[3];
int totvert;
const int *vert_indices;
struct MPropCol *vcol;
@@ -413,7 +414,7 @@ typedef struct PBVHVertexIter {
struct MVert *mvert;
struct BMVert *bm_vert;
float *co;
- short *no;
+ float *no;
float *fno;
float *mask;
float *col;
@@ -467,7 +468,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
BLI_assert(vi.visible); \
} \
vi.co = vi.mvert->co; \
- vi.no = vi.mvert->no; \
+ vi.no = vi.vert_normals[vi.vert_indices[vi.gx]]; \
vi.index = vi.vert_indices[vi.i]; \
if (vi.vmask) { \
vi.mask = &vi.vmask[vi.index]; \
@@ -533,6 +534,7 @@ void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings,
int totnode);
struct MVert *BKE_pbvh_get_verts(const PBVH *pbvh);
+const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3];
PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index 47d3d83f8bb..0749b9d6d49 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -363,7 +363,7 @@ 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);
+ int flag);
/********************** Baking *********************/
diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h
index af8a6ed293d..d330ea41e6a 100644
--- a/source/blender/blenkernel/BKE_pointcloud.h
+++ b/source/blender/blenkernel/BKE_pointcloud.h
@@ -38,10 +38,10 @@ extern const char *POINTCLOUD_ATTR_RADIUS;
void *BKE_pointcloud_add(struct Main *bmain, const char *name);
void *BKE_pointcloud_add_default(struct Main *bmain, const char *name);
-struct PointCloud *BKE_pointcloud_new_nomain(const int totpoint);
+struct PointCloud *BKE_pointcloud_new_nomain(int totpoint);
struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob);
-void BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]);
+bool BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]);
void BKE_pointcloud_update_customdata_pointers(struct PointCloud *pointcloud);
bool BKE_pointcloud_customdata_required(struct PointCloud *pointcloud,
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 1c9bad7fbe8..68f2319106e 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -60,7 +60,7 @@ void BKE_rigidbody_free_constraint(struct Object *ob);
void BKE_rigidbody_object_copy(struct Main *bmain,
struct Object *ob_dst,
const struct Object *ob_src,
- const int flag);
+ int flag);
/** \} */
@@ -122,7 +122,7 @@ void BKE_rigidbody_main_collection_object_add(struct Main *bmain,
/**
* Copy.
*/
-struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw, const int flag);
+struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw, int flag);
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw);
/**
@@ -167,11 +167,11 @@ void BKE_rigidbody_ensure_local_object(struct Main *bmain, struct Object *ob);
void BKE_rigidbody_remove_object(struct Main *bmain,
struct Scene *scene,
struct Object *ob,
- const bool free_us);
+ bool free_us);
void BKE_rigidbody_remove_constraint(struct Main *bmain,
struct Scene *scene,
struct Object *ob,
- const bool free_us);
+ bool free_us);
/** \} */
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 77cf250471f..a40359e8650 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -22,6 +22,8 @@
* \ingroup bke
*/
+#include "BLI_sys_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -81,7 +83,7 @@ struct Scene *BKE_scene_add(struct Main *bmain, const char *name);
void BKE_scene_remove_rigidbody_object(struct Main *bmain,
struct Scene *scene,
struct Object *ob,
- const bool free_us);
+ bool free_us);
/**
* Check if there is any instance of the object in the scene.
@@ -139,7 +141,7 @@ 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);
+struct ToolSettings *BKE_toolsettings_copy(struct ToolSettings *toolsettings, int flag);
void BKE_toolsettings_free(struct ToolSettings *toolsettings);
struct Scene *BKE_scene_duplicate(struct Main *bmain, struct Scene *sce, eSceneCopyMethod type);
@@ -179,7 +181,7 @@ 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);
+float BKE_scene_frame_to_ctime(const struct Scene *scene, int frame);
/**
* Get current fractional frame based on frame and sub-frame.
@@ -218,7 +220,7 @@ 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);
+void BKE_scene_graph_update_for_newframe_ex(struct Depsgraph *depsgraph, bool clear_recalc);
/**
* Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
@@ -273,7 +275,7 @@ 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);
+double BKE_scene_unit_scale(const struct UnitSettings *unit, int unit_type, double value);
/* Multi-view. */
@@ -293,9 +295,8 @@ bool BKE_scene_multiview_is_render_view_first(const struct RenderData *rd, const
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,
- const int view_id);
-const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd,
- const int view_id);
+ int view_id);
+const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd, int view_id);
int BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *viewname);
void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv,
const char *filepath,
@@ -311,16 +312,13 @@ void BKE_scene_multiview_view_filepath_get(const struct RenderData *rd,
const char *view,
char *r_filepath);
const char *BKE_scene_multiview_view_suffix_get(const struct RenderData *rd, const char *viewname);
-const char *BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, const int view_id);
+const char *BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, int view_id);
void BKE_scene_multiview_view_prefix_get(struct Scene *scene,
const char *name,
char *r_prefix,
const char **r_ext);
-void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd,
- const size_t width,
- const size_t height,
- size_t *r_width,
- size_t *r_height);
+void BKE_scene_multiview_videos_dimensions_get(
+ const struct RenderData *rd, size_t width, size_t height, size_t *r_width, size_t *r_height);
int BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
/* depsgraph */
@@ -347,7 +345,7 @@ void BKE_scene_undo_depsgraphs_restore(struct Main *bmain, struct GHash *depsgra
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);
+ int index);
/**
* \return the index that \a orientation has within \a scene's transform-orientation list
* or -1 if not found.
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index fd0682ee8f0..c85ae04a492 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -38,6 +38,7 @@ struct BlendLibReader;
struct BlendWriter;
struct Header;
struct ID;
+struct IDRemapper;
struct LibraryForeachIDData;
struct ListBase;
struct Menu;
@@ -117,10 +118,7 @@ typedef struct SpaceType {
bContextDataCallback context;
/* Used when we want to replace an ID by another (or NULL). */
- void (*id_remap)(struct ScrArea *area,
- struct SpaceLink *sl,
- struct ID *old_id,
- struct ID *new_id);
+ void (*id_remap)(struct ScrArea *area, struct SpaceLink *sl, const struct IDRemapper *mappings);
int (*space_subtype_get)(struct ScrArea *area);
void (*space_subtype_set)(struct ScrArea *area, int value);
@@ -465,20 +463,19 @@ void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizm
*/
struct ARegion *BKE_area_find_region_type(const struct ScrArea *area, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *area);
-struct ARegion *BKE_area_find_region_xy(struct ScrArea *area, const int regiontype, int x, int y);
+struct ARegion *BKE_area_find_region_xy(struct ScrArea *area, int regiontype, const int xy[2])
+ ATTR_NONNULL(3);
/**
* \note This is only for screen level regions (typically menus/popups).
*/
struct ARegion *BKE_screen_find_region_xy(struct bScreen *screen,
- const int regiontype,
- int x,
- int y) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ int regiontype,
+ const int xy[2]) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 3);
struct ARegion *BKE_screen_find_main_region_at_xy(struct bScreen *screen,
- const int space_type,
- const int x,
- const int y);
-
+ int space_type,
+ const int xy[2]) ATTR_NONNULL(1, 3);
/**
* \note Ideally we can get the area from the context,
* there are a few places however where this isn't practical.
@@ -490,14 +487,12 @@ struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen,
* \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);
+struct ScrArea *BKE_screen_find_big_area(struct bScreen *screen, int spacetype, short min);
struct ScrArea *BKE_screen_area_map_find_area_xy(const struct ScrAreaMap *areamap,
- const int spacetype,
- int x,
- int y);
-struct ScrArea *BKE_screen_find_area_xy(struct bScreen *screen, const int spacetype, int x, int y);
+ int spacetype,
+ const int xy[2]) ATTR_NONNULL(1, 3);
+struct ScrArea *BKE_screen_find_area_xy(struct bScreen *screen, int spacetype, const int xy[2])
+ ATTR_NONNULL(1, 3);
void BKE_screen_gizmo_tag_refresh(struct bScreen *screen);
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
index a82112ff967..432b334a676 100644
--- a/source/blender/blenkernel/BKE_shader_fx.h
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -164,7 +164,7 @@ 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_ex(struct ShaderFxData *fx, int flag);
void BKE_shaderfx_free(struct ShaderFxData *fx);
/**
* Check unique name.
@@ -183,9 +183,7 @@ struct ShaderFxData *BKE_shaderfx_findby_type(struct Object *ob, ShaderFxType ty
struct ShaderFxData *BKE_shaderfx_findby_name(struct Object *ob, const char *name);
void BKE_shaderfx_copydata_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
void BKE_shaderfx_copydata(struct ShaderFxData *fx, struct ShaderFxData *target);
-void BKE_shaderfx_copydata_ex(struct ShaderFxData *fx,
- struct ShaderFxData *target,
- const int flag);
+void BKE_shaderfx_copydata_ex(struct ShaderFxData *fx, struct ShaderFxData *target, int flag);
void BKE_shaderfx_copy(struct ListBase *dst, const struct ListBase *src);
void BKE_shaderfx_foreach_ID_link(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 088b270bfed..ea816812344 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -47,8 +47,8 @@ struct MDeformVert;
struct Mesh;
struct ModifierEvalContext;
struct Object;
-struct ShrinkwrapModifierData;
struct ShrinkwrapGpencilModifierData;
+struct ShrinkwrapModifierData;
struct SpaceTransform;
/* Information about boundary edges in the mesh. */
@@ -88,7 +88,7 @@ typedef struct ShrinkwrapTreeData {
BVHTree *bvh;
BVHTreeFromMesh treeData;
- float (*pnors)[3];
+ const float (*pnors)[3];
float (*clnors)[3];
ShrinkwrapBoundaryData *boundary;
} ShrinkwrapTreeData;
@@ -121,14 +121,14 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd,
struct Object *ob,
struct Mesh *mesh,
struct MDeformVert *dvert,
- const int defgrp_index,
+ int defgrp_index,
float (*vertexCos)[3],
int numVerts);
/* Implementation of the Shrinkwrap Grease Pencil modifier. */
void shrinkwrapGpencilModifier_deform(struct ShrinkwrapGpencilModifierData *mmd,
struct Object *ob,
struct MDeformVert *dvert,
- const int defgrp_index,
+ int defgrp_index,
float (*vertexCos)[3],
int numVerts);
@@ -166,7 +166,7 @@ void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me,
bool BKE_shrinkwrap_project_normal(char options,
const float vert[3],
const float dir[3],
- const float ray_radius,
+ float ray_radius,
const struct SpaceTransform *transf,
struct ShrinkwrapTreeData *tree,
BVHTreeRayHit *hit);
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index ebdc4a0ca0b..a87f76da8da 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -24,8 +24,8 @@
#include "FN_generic_virtual_array.hh"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_vector.hh"
#include "BKE_attribute_access.hh"
@@ -127,9 +127,9 @@ class Spline {
virtual int size() const = 0;
int segments_size() const;
bool is_cyclic() const;
- void set_cyclic(const bool value);
+ void set_cyclic(bool value);
- virtual void resize(const int size) = 0;
+ virtual void resize(int size) = 0;
virtual blender::MutableSpan<blender::float3> positions() = 0;
virtual blender::Span<blender::float3> positions() const = 0;
virtual blender::MutableSpan<float> radii() = 0;
@@ -175,7 +175,7 @@ class Spline {
*/
blender::Span<blender::float3> evaluated_normals() const;
- void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
+ void bounds_min_max(blender::float3 &min, blender::float3 &max, bool use_evaluated) const;
struct LookupResult {
/**
@@ -202,20 +202,20 @@ class Spline {
* 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;
+ LookupResult lookup_evaluated_factor(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;
+ LookupResult lookup_evaluated_length(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;
+ blender::Array<float> sample_uniform_index_factors(int samples_size) const;
+ LookupResult lookup_data_from_index_factor(float index_factor) const;
/**
* Sample any input data with a value for each evaluated point (already interpolated to evaluated
@@ -328,20 +328,9 @@ class BezierSpline final : public Spline {
int size() const final;
int resolution() const;
- void set_resolution(const int value);
+ void set_resolution(int value);
- /**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
- void add_point(const blender::float3 position,
- const HandleType handle_type_left,
- const blender::float3 handle_position_left,
- const HandleType handle_type_right,
- const blender::float3 handle_position_right,
- const float radius,
- const float tilt);
-
- void resize(const int size) final;
+ void resize(int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;
@@ -381,14 +370,14 @@ class BezierSpline final : public Spline {
* 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);
+ void set_handle_position_right(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);
+ void set_handle_position_left(int index, const blender::float3 &value);
- bool point_is_sharp(const int index) const;
+ bool point_is_sharp(int index) const;
void mark_cache_invalid() final;
int evaluated_points_size() const final;
@@ -425,18 +414,18 @@ class BezierSpline final : public Spline {
* 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;
+ InterpolationData interpolation_data_from_index_factor(float index_factor) const;
virtual blender::fn::GVArray interpolate_to_evaluated(
const blender::fn::GVArray &src) const override;
- void evaluate_segment(const int index,
- const int next_index,
+ void evaluate_segment(int index,
+ 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;
+ bool segment_is_vector(int start_index) const;
/** See comment and diagram for #calculate_segment_insertion. */
struct InsertResult {
@@ -465,9 +454,7 @@ class BezierSpline final : public Spline {
* point_prev point_next
* </pre>
*/
- InsertResult calculate_segment_insertion(const int index,
- const int next_index,
- const float parameter);
+ InsertResult calculate_segment_insertion(int index, int next_index, float parameter);
private:
/**
@@ -563,22 +550,14 @@ class NURBSpline final : public Spline {
int size() const final;
int resolution() const;
- void set_resolution(const int value);
+ void set_resolution(int value);
uint8_t order() const;
- void set_order(const uint8_t value);
-
- /**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
- void add_point(const blender::float3 position,
- const float radius,
- const float tilt,
- const float weight);
+ void set_order(uint8_t value);
bool check_valid_size_and_order() const;
int knots_size() const;
- void resize(const int size) final;
+ void resize(int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;
@@ -634,12 +613,7 @@ 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;
+ void resize(int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;
@@ -700,7 +674,7 @@ struct CurveEval {
*/
bool has_spline_with_type(const Spline::Type type) const;
- void resize(const int size);
+ void resize(int size);
/**
* \warning Call #reallocate on the spline's attributes after adding all splines.
*/
@@ -710,7 +684,7 @@ struct CurveEval {
void translate(const blender::float3 &translation);
void transform(const blender::float4x4 &matrix);
- void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
+ bool bounds_min_max(blender::float3 &min, blender::float3 &max, bool use_evaluated) const;
/**
* Return the start indices for each of the curve spline's control points, if they were part
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index 2fb27fad30d..697b3e9ace7 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -151,9 +151,9 @@ typedef struct SubdivDisplacement {
* Averaging of displacement for vertices created for over coarse vertices
* and edges is done by subdiv code. */
void (*eval_displacement)(struct SubdivDisplacement *displacement,
- const int ptex_face_index,
- const float u,
- const float v,
+ int ptex_face_index,
+ float u,
+ float v,
const float dPdu[3],
const float dPdv[3],
float r_D[3]);
@@ -188,7 +188,16 @@ typedef struct Subdiv {
/* Cached values, are not supposed to be accessed directly. */
struct {
/* Indexed by base face index, element indicates total number of ptex
- * faces created for preceding base faces. */
+ * faces created for preceding base faces. This also stores the final
+ * ptex offset (the total number of PTex faces) at the end of the array
+ * so that algorithms can compute the number of ptex faces for a given
+ * face by computing the delta with the offset for the next face without
+ * using a separate data structure, e.g.:
+ *
+ * const int num_face_ptex_faces = face_ptex_offset[i + 1] - face_ptex_offset[i];
+ *
+ * In total this array has a size of `num base faces + 1`.
+ */
int *face_ptex_offset;
} cache_;
} Subdiv;
@@ -257,45 +266,48 @@ void BKE_subdiv_displacement_detach(Subdiv *subdiv);
/* ============================ TOPOLOGY HELPERS ============================ */
+/* For each element in the array, this stores the total number of ptex faces up to that element,
+ * with the total number of ptex faces being the last element in the array. The array is of length
+ * `base face count + 1`. */
int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv);
/* =========================== PTEX FACES AND GRIDS ========================= */
/* For a given (ptex_u, ptex_v) within a ptex face get corresponding
* (grid_u, grid_v) within a grid. */
-BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(const float ptex_u,
- const float ptex_v,
+BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(float ptex_u,
+ float ptex_v,
float *r_grid_u,
float *r_grid_v);
/* Inverse of above. */
-BLI_INLINE void BKE_subdiv_grid_uv_to_ptex_face_uv(const float grid_u,
- const float grid_v,
+BLI_INLINE void BKE_subdiv_grid_uv_to_ptex_face_uv(float grid_u,
+ float grid_v,
float *r_ptex_u,
float *r_ptex_v);
/* For a given subdivision level (which is NOT refinement level) get size of
* CCG grid (number of grid points on a side).
*/
-BLI_INLINE int BKE_subdiv_grid_size_from_level(const int level);
+BLI_INLINE int BKE_subdiv_grid_size_from_level(int level);
/* Simplified version of mdisp_rot_face_to_crn, only handles quad and
* works in normalized coordinates.
*
* NOTE: Output coordinates are in ptex coordinates. */
-BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(const float quad_u,
- const float quad_v,
+BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(float quad_u,
+ float quad_v,
float *r_corner_u,
float *r_corner_v);
/* Converts (u, v) coordinate from within a grid to a quad coordinate in
* normalized ptex coordinates. */
BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
- const int corner, const float grid_u, const float grid_v, float *r_quad_u, float *r_quad_v);
+ int corner, float grid_u, float grid_v, float *r_quad_u, float *r_quad_v);
/* Convert Blender edge crease value to OpenSubdiv sharpness. */
-BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_f(float edge_crease);
-BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_char(char edge_crease);
+BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease);
+BLI_INLINE float BKE_subdiv_crease_to_sharpness_char(char edge_crease);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
index b7d4ab8d8ed..b3aa966e0d0 100644
--- a/source/blender/blenkernel/BKE_subdiv_ccg.h
+++ b/source/blender/blenkernel/BKE_subdiv_ccg.h
@@ -46,9 +46,9 @@ struct Subdiv;
/* Functor which evaluates mask value at a given (u, v) of given ptex face. */
typedef struct SubdivCCGMaskEvaluator {
float (*eval_mask)(struct SubdivCCGMaskEvaluator *mask_evaluator,
- const int ptex_face_index,
- const float u,
- const float v);
+ int ptex_face_index,
+ float u,
+ float v);
/* Free the data, not the evaluator itself. */
void (*free)(struct SubdivCCGMaskEvaluator *mask_evaluator);
@@ -67,8 +67,7 @@ bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator,
/* Functor which evaluates material and flags of a given coarse face. */
typedef struct SubdivCCGMaterialFlagsEvaluator {
DMFlagMat (*eval_material_flags)(
- struct SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator,
- const int coarse_face_index);
+ struct SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator, int coarse_face_index);
/* Free the data, not the evaluator itself. */
void (*free)(struct SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator);
@@ -307,10 +306,10 @@ bool BKE_subdiv_ccg_check_coord_valid(const SubdivCCG *subdiv_ccg, const SubdivC
* the current vertex are added at the end of the coords array. */
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
- const bool include_duplicates,
+ bool include_duplicates,
SubdivCCGNeighbors *r_neighbors);
-int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index);
+int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, int grid_index);
void BKE_subdiv_ccg_eval_limit_point(const SubdivCCG *subdiv_ccg,
const SubdivCCGCoord *coord,
float r_point[3]);
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
index 0b61e62c89c..23bcdcce276 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -30,16 +30,26 @@ extern "C" {
#endif
struct Mesh;
+struct OpenSubdiv_EvaluatorCache;
struct Subdiv;
+typedef enum eSubdivEvaluatorType {
+ SUBDIV_EVALUATOR_TYPE_CPU,
+ SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE,
+} eSubdivEvaluatorType;
+
/* Returns true if evaluator is ready for use. */
-bool BKE_subdiv_eval_begin(struct Subdiv *subdiv);
+bool BKE_subdiv_eval_begin(struct Subdiv *subdiv,
+ eSubdivEvaluatorType evaluator_type,
+ struct OpenSubdiv_EvaluatorCache *evaluator_cache);
/* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse
* mesh. */
bool BKE_subdiv_eval_begin_from_mesh(struct Subdiv *subdiv,
const struct Mesh *mesh,
- const float (*coarse_vertex_cos)[3]);
+ const float (*coarse_vertex_cos)[3],
+ eSubdivEvaluatorType evaluator_type,
+ struct OpenSubdiv_EvaluatorCache *evaluator_cache);
bool BKE_subdiv_eval_refine_from_mesh(struct Subdiv *subdiv,
const struct Mesh *mesh,
const float (*coarse_vertex_cos)[3]);
@@ -55,33 +65,23 @@ void BKE_subdiv_eval_init_displacement(struct Subdiv *subdiv);
/* Evaluate point at a limit surface, with optional derivatives and normal. */
void BKE_subdiv_eval_limit_point(
- struct Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3]);
+ struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3]);
void BKE_subdiv_eval_limit_point_and_derivatives(struct Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
+ int ptex_face_index,
+ float u,
+ float v,
float r_P[3],
float r_dPdu[3],
float r_dPdv[3]);
-void BKE_subdiv_eval_limit_point_and_normal(struct Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
- float r_P[3],
- float r_N[3]);
-void BKE_subdiv_eval_limit_point_and_short_normal(struct Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
- float r_P[3],
- short r_N[3]);
+void BKE_subdiv_eval_limit_point_and_normal(
+ struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], float r_N[3]);
/* Evaluate face-varying layer (such as UV). */
void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv,
- const int face_varying_channel,
- const int ptex_face_index,
- const float u,
- const float v,
+ int face_varying_channel,
+ int ptex_face_index,
+ float u,
+ float v,
float r_face_varying[2]);
/* NOTE: Expects derivatives to be correct.
@@ -91,59 +91,16 @@ void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv,
* Would be nice to have displacement evaluation function which does not require
* knowing derivatives ahead of a time. */
void BKE_subdiv_eval_displacement(struct Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
+ int ptex_face_index,
+ float u,
+ float v,
const float dPdu[3],
const float dPdv[3],
float r_D[3]);
/* Evaluate point on a limit surface with displacement applied to it. */
void BKE_subdiv_eval_final_point(
- struct Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3]);
-
-/* Patch queries at given resolution.
- *
- * Will evaluate patch at uniformly distributed (u, v) coordinates on a grid
- * of given resolution, producing resolution^2 evaluation points. The order
- * goes as u in rows, v in columns. */
-
-void BKE_subdiv_eval_limit_patch_resolution_point(struct Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *buffer,
- const int offset,
- const int stride);
-void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(struct Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *du_buffer,
- const int du_offset,
- const int du_stride,
- void *dv_buffer,
- const int dv_offset,
- const int dv_stride);
-void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(struct Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *normal_buffer,
- const int normal_offset,
- const int normal_stride);
-void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(struct Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *normal_buffer,
- const int normal_offset,
- const int normal_stride);
+ struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3]);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_subdiv_foreach.h b/source/blender/blenkernel/BKE_subdiv_foreach.h
index 3f74299455d..7d9a589666a 100644
--- a/source/blender/blenkernel/BKE_subdiv_foreach.h
+++ b/source/blender/blenkernel/BKE_subdiv_foreach.h
@@ -35,76 +35,77 @@ struct SubdivForeachContext;
struct SubdivToMeshSettings;
typedef bool (*SubdivForeachTopologyInformationCb)(const struct SubdivForeachContext *context,
- const int num_vertices,
- const int num_edges,
- const int num_loops,
- const int num_polygons);
+ int num_vertices,
+ int num_edges,
+ int num_loops,
+ int num_polygons,
+ const int *subdiv_polygon_offset);
typedef void (*SubdivForeachVertexFromCornerCb)(const struct SubdivForeachContext *context,
void *tls,
- const int ptex_face_index,
- const float u,
- const float v,
- const int coarse_vertex_index,
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index);
+ int ptex_face_index,
+ float u,
+ float v,
+ int coarse_vertex_index,
+ int coarse_poly_index,
+ int coarse_corner,
+ int subdiv_vertex_index);
typedef void (*SubdivForeachVertexFromEdgeCb)(const struct SubdivForeachContext *context,
void *tls,
- const int ptex_face_index,
- const float u,
- const float v,
- const int coarse_edge_index,
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index);
+ int ptex_face_index,
+ float u,
+ float v,
+ int coarse_edge_index,
+ int coarse_poly_index,
+ int coarse_corner,
+ int subdiv_vertex_index);
typedef void (*SubdivForeachVertexInnerCb)(const struct SubdivForeachContext *context,
void *tls,
- const int ptex_face_index,
- const float u,
- const float v,
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_vertex_index);
+ int ptex_face_index,
+ float u,
+ float v,
+ int coarse_poly_index,
+ int coarse_corner,
+ int subdiv_vertex_index);
typedef void (*SubdivForeachEdgeCb)(const struct SubdivForeachContext *context,
void *tls,
- const int coarse_edge_index,
- const int subdiv_edge_index,
- const int subdiv_v1,
- const int subdiv_v2);
+ int coarse_edge_index,
+ int subdiv_edge_index,
+ int subdiv_v1,
+ int subdiv_v2);
typedef void (*SubdivForeachLoopCb)(const struct SubdivForeachContext *context,
void *tls,
- const int ptex_face_index,
- const float u,
- const float v,
- const int coarse_loop_index,
- const int coarse_poly_index,
- const int coarse_corner,
- const int subdiv_loop_index,
- const int subdiv_vertex_index,
- const int subdiv_edge_index);
+ int ptex_face_index,
+ float u,
+ float v,
+ int coarse_loop_index,
+ int coarse_poly_index,
+ int coarse_corner,
+ int subdiv_loop_index,
+ int subdiv_vertex_index,
+ int subdiv_edge_index);
typedef void (*SubdivForeachPolygonCb)(const struct SubdivForeachContext *context,
void *tls,
- const int coarse_poly_index,
- const int subdiv_poly_index,
- const int start_loop_index,
- const int num_loops);
+ int coarse_poly_index,
+ int subdiv_poly_index,
+ int start_loop_index,
+ int num_loops);
typedef void (*SubdivForeachLooseCb)(const struct SubdivForeachContext *context,
void *tls,
- const int coarse_vertex_index,
- const int subdiv_vertex_index);
+ int coarse_vertex_index,
+ int subdiv_vertex_index);
typedef void (*SubdivForeachVertexOfLooseEdgeCb)(const struct SubdivForeachContext *context,
void *tls,
- const int coarse_edge_index,
- const float u,
- const int subdiv_vertex_index);
+ int coarse_edge_index,
+ float u,
+ int subdiv_vertex_index);
typedef struct SubdivForeachContext {
/* Is called when topology information becomes available.
diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h
new file mode 100644
index 00000000000..8a179206dd7
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_modifier.h
@@ -0,0 +1,79 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#pragma once
+
+#include "BLI_sys_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Mesh;
+struct Object;
+struct Scene;
+struct Subdiv;
+struct SubdivSettings;
+struct SubsurfModifierData;
+
+void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings,
+ const struct SubsurfModifierData *smd,
+ bool use_render_params);
+
+/**
+ * \param skip_check_is_last: When true, we assume that the modifier passed is the last enabled
+ * modifier in the stack.
+ */
+bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const struct Scene *scene,
+ const struct Object *ob,
+ const struct SubsurfModifierData *smd,
+ int required_mode,
+ bool skip_check_is_last);
+
+bool BKE_subsurf_modifier_can_do_gpu_subdiv(const struct Scene *scene,
+ const struct Object *ob,
+ int required_mode);
+
+extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv);
+
+/**
+ * Main goal of this function is to give usable subdivision surface descriptor
+ * which matches settings and topology.
+ */
+struct Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(
+ const struct SubsurfModifierData *smd,
+ const struct SubdivSettings *subdiv_settings,
+ const struct Mesh *mesh,
+ bool for_draw_code);
+
+struct SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(struct SubsurfModifierData *smd);
+
+/**
+ * Return the #ModifierMode required for the evaluation of the subsurf modifier,
+ * which should be used to check if the modifier is enabled.
+ */
+int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index a979ba6d2cc..7415cb90ff2 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -52,7 +52,7 @@ bool BKE_text_reload(struct Text *text);
struct Text *BKE_text_load_ex(struct Main *bmain,
const char *file,
const char *relpath,
- const bool is_internal);
+ bool is_internal);
/**
* Load a text file.
*
@@ -73,25 +73,25 @@ void BKE_text_file_modified_ignore(struct Text *text);
char *txt_to_buf(struct Text *text, int *r_buf_strlen);
void txt_clean_text(struct Text *text);
-void txt_order_cursors(struct Text *text, const bool reverse);
+void txt_order_cursors(struct Text *text, bool reverse);
int txt_find_string(struct Text *text, const char *findstr, int wrap, int match_case);
bool txt_has_sel(const struct Text *text);
int txt_get_span(struct TextLine *from, struct TextLine *to);
-void txt_move_up(struct Text *text, const bool sel);
-void txt_move_down(struct Text *text, const bool sel);
-void txt_move_left(struct Text *text, const bool sel);
-void txt_move_right(struct Text *text, const bool sel);
-void txt_jump_left(struct Text *text, const bool sel, const bool use_init_step);
-void txt_jump_right(struct Text *text, const bool sel, const bool use_init_step);
-void txt_move_bof(struct Text *text, const bool sel);
-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);
+void txt_move_up(struct Text *text, bool sel);
+void txt_move_down(struct Text *text, bool sel);
+void txt_move_left(struct Text *text, bool sel);
+void txt_move_right(struct Text *text, bool sel);
+void txt_jump_left(struct Text *text, bool sel, bool use_init_step);
+void txt_jump_right(struct Text *text, bool sel, bool use_init_step);
+void txt_move_bof(struct Text *text, bool sel);
+void txt_move_eof(struct Text *text, bool sel);
+void txt_move_bol(struct Text *text, bool sel);
+void txt_move_eol(struct Text *text, bool sel);
+void txt_move_toline(struct Text *text, unsigned int line, 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_move_to(struct Text *text, unsigned int line, unsigned int ch, bool sel);
void txt_pop_sel(struct Text *text);
void txt_delete_char(struct Text *text);
void txt_delete_word(struct Text *text);
@@ -117,7 +117,7 @@ bool txt_unindent(struct Text *text);
void txt_comment(struct Text *text);
void txt_indent(struct Text *text);
bool txt_uncomment(struct Text *text);
-void txt_move_lines(struct Text *text, const int direction);
+void txt_move_lines(struct Text *text, int direction);
void txt_duplicate_line(struct Text *text);
int txt_setcurr_tab_spaces(struct Text *text, int space);
bool txt_cursor_is_line_start(const struct Text *text);
@@ -129,17 +129,17 @@ int txt_calc_tab_right(struct TextLine *tl, int ch);
/**
* 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);
-bool text_check_identifier(const char ch);
-bool text_check_identifier_nodigit(const char ch);
-bool text_check_whitespace(const char ch);
+int text_check_bracket(char ch);
+bool text_check_delim(char ch);
+bool text_check_digit(char ch);
+bool text_check_identifier(char ch);
+bool text_check_identifier_nodigit(char ch);
+bool text_check_whitespace(char ch);
int text_find_identifier_start(const char *str, int i);
/* 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);
+extern int text_check_identifier_unicode(unsigned int ch);
+extern int text_check_identifier_nodigit_unicode(unsigned int ch);
enum {
TXT_MOVE_LINE_UP = -1,
diff --git a/source/blender/blenkernel/BKE_text_suggestions.h b/source/blender/blenkernel/BKE_text_suggestions.h
index 7561e1d1d08..482141c1032 100644
--- a/source/blender/blenkernel/BKE_text_suggestions.h
+++ b/source/blender/blenkernel/BKE_text_suggestions.h
@@ -66,7 +66,7 @@ short texttool_text_is_active(struct Text *text);
/* Suggestions */
void texttool_suggest_add(const char *name, char type);
-void texttool_suggest_prefix(const char *prefix, const int prefix_len);
+void texttool_suggest_prefix(const char *prefix, int prefix_len);
void texttool_suggest_clear(void);
SuggItem *texttool_suggest_first(void);
SuggItem *texttool_suggest_last(void);
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 380b5cf035c..2683ab00fa4 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -82,7 +82,7 @@ void BKE_texture_pointdensity_init_data(struct PointDensity *pd);
void BKE_texture_pointdensity_free_data(struct PointDensity *pd);
void BKE_texture_pointdensity_free(struct PointDensity *pd);
struct PointDensity *BKE_texture_pointdensity_add(void);
-struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, const int flag);
+struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, int flag);
bool BKE_texture_dependsOnTime(const struct Tex *texture);
/**
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 9caf5d31765..7769215d616 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -58,7 +58,7 @@ void BKE_tracking_free(struct MovieTracking *tracking);
*/
void BKE_tracking_copy(struct MovieTracking *tracking_dst,
const struct MovieTracking *tracking_src,
- const int flag);
+ int flag);
/**
* Initialize motion tracking settings to default values,
@@ -177,7 +177,7 @@ void BKE_tracking_track_first_last_frame_get(const struct MovieTrackingTrack *tr
* 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 num_tracks,
int *r_first_frame,
int *r_last_frame);
@@ -236,7 +236,7 @@ void BKE_tracking_tracks_join(struct MovieTracking *tracking,
void BKE_tracking_tracks_average(struct MovieTrackingTrack *dst_track,
/*const*/ struct MovieTrackingTrack **src_tracks,
- const int num_src_tracks);
+ int num_src_tracks);
struct MovieTrackingTrack *BKE_tracking_track_get_named(struct MovieTracking *tracking,
struct MovieTrackingObject *object,
@@ -301,7 +301,7 @@ struct MovieTrackingMarker *BKE_tracking_marker_ensure(struct MovieTrackingTrack
* \returns truth if the result is usable.
*/
bool BKE_tracking_marker_get_interpolated(struct MovieTrackingTrack *track,
- const int framenr,
+ int framenr,
struct MovieTrackingMarker *r_marker);
void BKE_tracking_marker_pattern_minmax(const struct MovieTrackingMarker *marker,
@@ -525,7 +525,7 @@ void BKE_tracking_refine_marker(struct MovieClip *clip,
struct AutoTrackContext *BKE_autotrack_context_new(struct MovieClip *clip,
struct MovieClipUser *user,
- const bool is_backwards);
+ bool is_backwards);
bool BKE_autotrack_context_step(struct AutoTrackContext *context);
void BKE_autotrack_context_sync(struct AutoTrackContext *context);
void BKE_autotrack_context_sync_user(struct AutoTrackContext *context, struct MovieClipUser *user);
diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h
index 6e1f9468ce4..88a9ac9d0bf 100644
--- a/source/blender/blenkernel/BKE_undo_system.h
+++ b/source/blender/blenkernel/BKE_undo_system.h
@@ -91,7 +91,7 @@ typedef struct UndoStep {
/** When this is true, undo/memfile read code is allowed to re-use old data-blocks for unchanged
* IDs, and existing depsgraphes. This has to be forbidden in some cases (like renamed IDs). */
bool use_old_bmain_data;
- /** For use by undo systems that accumulate changes (text editor, painting). */
+ /** For use by undo systems that accumulate changes (mesh-sculpt & image-painting). */
bool is_applied;
/* Over alloc 'type->struct_size'. */
} UndoStep;
@@ -133,7 +133,7 @@ typedef struct UndoType {
bool (*step_encode)(struct bContext *C, struct Main *bmain, UndoStep *us);
void (*step_decode)(
- struct bContext *C, struct Main *bmain, UndoStep *us, const eUndoStepDir dir, bool is_final);
+ struct bContext *C, struct Main *bmain, UndoStep *us, eUndoStepDir dir, bool is_final);
/**
* \note When freeing all steps,
@@ -263,7 +263,7 @@ bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
struct bContext *C,
UndoStep *us_target,
UndoStep *us_reference,
- const bool use_skip);
+ bool use_skip);
/**
* Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
*/
@@ -272,7 +272,7 @@ bool BKE_undosys_step_load_data(UndoStack *ustack, struct bContext *C, UndoStep
* 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);
+void BKE_undosys_step_load_from_index(UndoStack *ustack, struct bContext *C, int index);
/**
* Undo until `us_target` step becomes the active (currently loaded) one.
diff --git a/source/blender/blenkernel/BKE_vfont.h b/source/blender/blenkernel/BKE_vfont.h
index cd1b30b9358..3397f2ef82a 100644
--- a/source/blender/blenkernel/BKE_vfont.h
+++ b/source/blender/blenkernel/BKE_vfont.h
@@ -96,7 +96,7 @@ void BKE_vfont_build_char(struct Curve *cu,
float ofsy,
float rot,
int charidx,
- const float fsize);
+ float fsize);
int BKE_vfont_select_get(struct Object *ob, int *r_start, int *r_end);
void BKE_vfont_select_clamp(struct Object *ob);
@@ -104,7 +104,7 @@ void BKE_vfont_select_clamp(struct Object *ob);
void BKE_vfont_clipboard_free(void);
void BKE_vfont_clipboard_set(const char32_t *text_buf,
const struct CharInfo *info_buf,
- const size_t len);
+ size_t len);
void BKE_vfont_clipboard_get(char32_t **r_text_buf,
struct CharInfo **r_info_buf,
size_t *r_len_utf8,
diff --git a/source/blender/blenkernel/BKE_vfontdata.h b/source/blender/blenkernel/BKE_vfontdata.h
index 692857b0458..01ca59828fc 100644
--- a/source/blender/blenkernel/BKE_vfontdata.h
+++ b/source/blender/blenkernel/BKE_vfontdata.h
@@ -56,7 +56,7 @@ typedef struct VChar {
* \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);
+VFontData *BKE_vfontdata_copy(const VFontData *vfont_src, int flag);
VChar *BKE_vfontdata_char_from_freetypefont(struct VFont *vfont, unsigned long character);
VChar *BKE_vfontdata_char_copy(const VChar *vchar_src);
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h
index f4f00844b8d..8b42de7303d 100644
--- a/source/blender/blenkernel/BKE_volume.h
+++ b/source/blender/blenkernel/BKE_volume.h
@@ -163,8 +163,8 @@ bool BKE_volume_save(const struct Volume *volume,
* file or copy shared grids to make them writeable. */
#ifdef __cplusplus
-# include "BLI_float3.hh"
# include "BLI_float4x4.hh"
+# include "BLI_math_vec_types.hh"
# include "BLI_string_ref.hh"
bool BKE_volume_min_max(const Volume *volume, blender::float3 &r_min, blender::float3 &r_max);
@@ -181,6 +181,11 @@ bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid,
blender::float3 &r_min,
blender::float3 &r_max);
+/**
+ * Return a new grid pointer with only the metadata and transform changed.
+ * This is useful for instances, where there is a separate transform on top of the original
+ * grid transform that must be applied for some operations that only take a grid argument.
+ */
openvdb::GridBase::ConstPtr BKE_volume_grid_shallow_transform(openvdb::GridBase::ConstPtr grid,
const blender::float4x4 &transform);
@@ -189,7 +194,7 @@ openvdb::GridBase::ConstPtr BKE_volume_grid_openvdb_for_read(const struct Volume
const struct VolumeGrid *grid);
openvdb::GridBase::Ptr BKE_volume_grid_openvdb_for_write(const struct Volume *volume,
struct VolumeGrid *grid,
- const bool clear);
+ bool clear);
VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase &grid);
@@ -229,9 +234,7 @@ auto BKE_volume_grid_type_operation(const VolumeGridType grid_type, OpType &&op)
}
openvdb::GridBase::Ptr BKE_volume_grid_create_with_changed_resolution(
- const VolumeGridType grid_type,
- const openvdb::GridBase &old_grid,
- const float resolution_factor);
+ const VolumeGridType grid_type, const openvdb::GridBase &old_grid, float resolution_factor);
# endif
#endif
diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh
index dd8ae7ea554..123cb33f24f 100644
--- a/source/blender/blenkernel/BKE_volume_to_mesh.hh
+++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh
@@ -53,20 +53,29 @@ struct OpenVDBMeshData {
struct Mesh *volume_to_mesh(const openvdb::GridBase &grid,
const VolumeToMeshResolution &resolution,
- const float threshold,
- const float adaptivity);
+ float threshold,
+ float adaptivity);
+/**
+ * Convert an OpenVDB volume grid to corresponding mesh data: vertex positions and quad and
+ * triangle indices.
+ */
struct OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid,
const VolumeToMeshResolution &resolution,
- const float threshold,
- const float adaptivity);
+ float threshold,
+ float adaptivity);
+/**
+ * Convert mesh data from the format provided by OpenVDB into Blender's #Mesh data structure.
+ * This can be used to add mesh data from a grid into an existing mesh rather than merging multiple
+ * meshes later on.
+ */
void fill_mesh_from_openvdb_data(const Span<openvdb::Vec3s> vdb_verts,
const Span<openvdb::Vec3I> vdb_tris,
const Span<openvdb::Vec4I> vdb_quads,
- const int vert_offset,
- const int poly_offset,
- const int loop_offset,
+ int vert_offset,
+ int poly_offset,
+ int loop_offset,
MutableSpan<MVert> verts,
MutableSpan<MPoly> polys,
MutableSpan<MLoop> loops);
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
index ff4e21732c4..0f609be67de 100644
--- a/source/blender/blenkernel/BKE_workspace.h
+++ b/source/blender/blenkernel/BKE_workspace.h
@@ -45,7 +45,7 @@ struct WorkSpace *BKE_workspace_add(struct Main *bmain, const char *name);
void BKE_workspace_remove(struct Main *bmain, struct WorkSpace *workspace);
struct WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const struct Main *bmain,
- const int winid);
+ int winid);
void BKE_workspace_instance_hook_free(const struct Main *bmain,
struct WorkSpaceInstanceHook *hook);
@@ -97,7 +97,7 @@ struct WorkSpaceLayout *BKE_workspace_layout_iter_circular(
struct WorkSpaceLayout *start,
bool (*callback)(const struct WorkSpaceLayout *layout, void *arg),
void *arg,
- const bool iter_backward);
+ bool iter_backward);
void BKE_workspace_tool_remove(struct WorkSpace *workspace, struct bToolRef *tref)
ATTR_NONNULL(1, 2);
@@ -132,13 +132,13 @@ struct WorkSpaceLayout *BKE_workspace_active_layout_get(const struct WorkSpaceIn
* #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,
+ int winid,
struct WorkSpace *workspace,
struct WorkSpaceLayout *layout) SETTER_ATTRS;
struct bScreen *BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook)
GETTER_ATTRS;
void BKE_workspace_active_screen_set(struct WorkSpaceInstanceHook *hook,
- const int winid,
+ int winid,
struct WorkSpace *workspace,
struct bScreen *screen) SETTER_ATTRS;
diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h
index d2a5100ffad..c20de4df901 100644
--- a/source/blender/blenkernel/BKE_writeavi.h
+++ b/source/blender/blenkernel/BKE_writeavi.h
@@ -63,7 +63,7 @@ typedef struct bMovieHandle {
void (*context_free)(void *context_v);
} bMovieHandle;
-bMovieHandle *BKE_movie_handle_get(const char imtype);
+bMovieHandle *BKE_movie_handle_get(char imtype);
/**
* \note Similar to #BKE_image_path_from_imformat()
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 68a8a499d2f..220d4673075 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -118,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
@@ -126,7 +126,7 @@ set(SRC
intern/curve_eval.cc
intern/curve_to_mesh_convert.cc
intern/curveprofile.cc
- intern/customdata.c
+ intern/customdata.cc
intern/customdata_file.c
intern/data_transfer.c
intern/deform.c
@@ -156,10 +156,12 @@ set(SRC
intern/gpencil_curve.c
intern/gpencil_geom.cc
intern/gpencil_modifier.c
- intern/hair.c
+ intern/hair.cc
intern/icons.cc
intern/icons_rasterize.c
intern/idprop.c
+ intern/idprop_create.cc
+ intern/idprop_serialize.cc
intern/idprop_utils.c
intern/idtype.c
intern/image.c
@@ -178,6 +180,7 @@ set(SRC
intern/lib_id.c
intern/lib_id_delete.c
intern/lib_id_eval.c
+ intern/lib_id_remapper.cc
intern/lib_override.c
intern/lib_query.c
intern/lib_remap.c
@@ -196,6 +199,7 @@ set(SRC
intern/mesh.cc
intern/mesh_boolean_convert.cc
intern/mesh_convert.cc
+ intern/mesh_debug.cc
intern/mesh_evaluate.cc
intern/mesh_fair.cc
intern/mesh_iterators.c
@@ -227,7 +231,7 @@ set(SRC
intern/multires_versioning.c
intern/nla.c
intern/node.cc
- intern/type_conversions.cc
+ intern/node_tree_update.cc
intern/object.cc
intern/object_deform.c
intern/object_dupli.cc
@@ -275,6 +279,7 @@ set(SRC
intern/subdiv_eval.c
intern/subdiv_foreach.c
intern/subdiv_mesh.c
+ intern/subdiv_modifier.c
intern/subdiv_stats.c
intern/subdiv_topology.c
intern/subsurf_ccg.c
@@ -289,6 +294,7 @@ set(SRC
intern/tracking_solver.c
intern/tracking_stabilize.c
intern/tracking_util.c
+ intern/type_conversions.cc
intern/undo_system.c
intern/unit.c
intern/vfont.c
@@ -380,6 +386,7 @@ set(SRC
BKE_hair.h
BKE_icons.h
BKE_idprop.h
+ BKE_idprop.hh
BKE_idtype.h
BKE_image.h
BKE_image_save.h
@@ -421,6 +428,7 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
+ BKE_node_tree_update.h
BKE_object.h
BKE_object_deform.h
BKE_object_facemap.h
@@ -452,6 +460,7 @@ set(SRC
BKE_subdiv_eval.h
BKE_subdiv_foreach.h
BKE_subdiv_mesh.h
+ BKE_subdiv_modifier.h
BKE_subdiv_topology.h
BKE_subsurf.h
BKE_text.h
@@ -515,7 +524,7 @@ set(LIB
bf_simulation
# For `vfontdata_freetype.c`.
- ${FREETYPE_LIBRARY}
+ ${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}
)
if(WITH_BINRELOC)
@@ -813,10 +822,13 @@ if(WITH_GTESTS)
intern/bpath_test.cc
intern/cryptomatte_test.cc
intern/fcurve_test.cc
+ intern/idprop_serialize_test.cc
intern/image_partial_update_test.cc
intern/lattice_deform_test.cc
intern/layer_test.cc
+ intern/lib_id_remapper_test.cc
intern/lib_id_test.cc
+ intern/lib_remap_test.cc
intern/tracking_test.cc
)
set(TEST_INC
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 6c9c5490ca0..d0d19ff199d 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -38,9 +38,9 @@
#include "BLI_array.h"
#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
-#include "BLI_float2.hh"
#include "BLI_linklist.h"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_task.h"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
@@ -775,28 +775,6 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
/* Compute normals. */
const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
- /* Some modifiers may need this info from their target (other) object,
- * simpler to generate it here as well.
- * Note that they will always be generated when no loop normals are computed,
- * since they are needed by drawing code. */
- const bool do_poly_normals = ((final_datamask->pmask & CD_MASK_NORMAL) != 0);
-
- /* In case we also need poly normals, add the layer and compute them here
- * (BKE_mesh_calc_normals_split() assumes that if that data exists, it is always valid). */
- if (do_poly_normals) {
- if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
- float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
- &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
- BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert,
- mesh_final->totvert,
- mesh_final->mloop,
- mesh_final->totloop,
- mesh_final->mpoly,
- mesh_final->totpoly,
- polynors,
- nullptr);
- }
- }
if (do_loop_normals) {
/* Compute loop normals (NOTE: will compute poly and vert normals as well, if needed!). */
@@ -814,11 +792,7 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
* normals and will also have to calculate normals on the fly, try avoid
* this where possible since calculating polygon normals isn't fast,
* note that this isn't a problem for subsurf (only quads) or editmode
- * which deals with drawing differently.
- *
- * Only calc vertex normals if they are flagged as dirty.
- * If using loop normals, poly nors have already been computed.
- */
+ * which deals with drawing differently. */
if (!do_loop_normals) {
BKE_mesh_ensure_normals_for_display(mesh_final);
}
@@ -927,6 +901,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
* constructive modifier is executed, or a deform modifier needs normals
* or certain data layers. */
Mesh *mesh_input = (Mesh *)ob->data;
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh_input);
Mesh *mesh_final = nullptr;
Mesh *mesh_deform = nullptr;
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
@@ -1458,26 +1433,6 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
- /* Some modifiers may need this info from their target (other) object,
- * simpler to generate it here as well. */
- const bool do_poly_normals = ((final_datamask->pmask & CD_MASK_NORMAL) != 0);
-
- /* In case we also need poly normals, add the layer and compute them here
- * (BKE_mesh_calc_normals_split() assumes that if that data exists, it is always valid). */
- if (do_poly_normals) {
- if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
- float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
- &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
- BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert,
- mesh_final->totvert,
- mesh_final->mloop,
- mesh_final->totloop,
- mesh_final->mpoly,
- mesh_final->totpoly,
- polynors,
- nullptr);
- }
- }
if (do_loop_normals) {
/* Compute loop normals */
@@ -1808,31 +1763,12 @@ static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob, Mesh
}
}
-static void mesh_runtime_check_normals_valid(const Mesh *mesh)
-{
- UNUSED_VARS_NDEBUG(mesh);
- BLI_assert(!(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL));
- BLI_assert(!(mesh->runtime.cd_dirty_loop & CD_MASK_NORMAL));
- BLI_assert(!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL));
-}
-
static void mesh_build_data(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
const CustomData_MeshMasks *dataMask,
const bool need_mapping)
{
- BLI_assert(ob->type == OB_MESH);
-
- /* Evaluated meshes aren't supposed to be created on original instances. If you do,
- * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
- BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
-
- BKE_object_free_derived_caches(ob);
- if (DEG_is_active(depsgraph)) {
- BKE_sculpt_update_object_before_eval(ob);
- }
-
#if 0 /* XXX This is already taken care of in mesh_calc_modifiers()... */
if (need_mapping) {
/* Also add the flag so that it is recorded in lastDataMask. */
@@ -1890,7 +1826,6 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
}
}
- mesh_runtime_check_normals_valid(mesh_eval);
mesh_build_extra_data(depsgraph, ob, mesh_eval);
}
@@ -1900,15 +1835,7 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
BMEditMesh *em,
CustomData_MeshMasks *dataMask)
{
- BLI_assert(obedit->id.tag & LIB_TAG_COPIED_ON_WRITE);
-
- BKE_object_free_derived_caches(obedit);
- if (DEG_is_active(depsgraph)) {
- BKE_sculpt_update_object_before_eval(obedit);
- }
-
- BKE_editmesh_free_derived_caches(em);
-
+ Mesh *mesh = static_cast<Mesh *>(obedit->data);
Mesh *me_cage;
Mesh *me_final;
GeometrySet *non_mesh_components;
@@ -1916,15 +1843,33 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
editbmesh_calc_modifiers(
depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final, &non_mesh_components);
- em->mesh_eval_final = me_final;
- em->mesh_eval_cage = me_cage;
- obedit->runtime.geometry_set_eval = non_mesh_components;
+ /* The modifier stack result is expected to share edit mesh pointer with the input.
+ * This is similar `mesh_calc_finalize()`. */
+ BKE_mesh_free_editmesh(me_final);
+ BKE_mesh_free_editmesh(me_cage);
+ me_final->edit_mesh = me_cage->edit_mesh = em;
+
+ /* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object
+ * with is in edit mode).
+ * Convert edit mesh to mesh until the draw manager can draw mesh wrapper which is not in the
+ * edit mode. */
+ if (!(obedit->mode & OB_MODE_EDIT)) {
+ BKE_mesh_wrapper_ensure_mdata(me_final);
+ if (me_final != me_cage) {
+ BKE_mesh_wrapper_ensure_mdata(me_cage);
+ }
+ }
+
+ const bool is_mesh_eval_owned = (me_final != mesh->runtime.mesh_eval);
+ BKE_object_eval_assign_data(obedit, &me_final->id, is_mesh_eval_owned);
+
+ obedit->runtime.editmesh_eval_cage = me_cage;
- BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final);
+ obedit->runtime.geometry_set_eval = non_mesh_components;
- em->lastDataMask = *dataMask;
+ BKE_object_boundbox_calc_from_mesh(obedit, me_final);
- mesh_runtime_check_normals_valid(em->mesh_eval_final);
+ obedit->runtime.last_data_mask = *dataMask;
}
static void object_get_datamask(const Depsgraph *depsgraph,
@@ -1980,9 +1925,25 @@ static void object_get_datamask(const Depsgraph *depsgraph,
void makeDerivedMesh(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
- BMEditMesh *em,
const CustomData_MeshMasks *dataMask)
{
+ BLI_assert(ob->type == OB_MESH);
+
+ /* Evaluated meshes aren't supposed to be created on original instances. If you do,
+ * they aren't cleaned up properly on mode switch, causing crashes, e.g T58150. */
+ BLI_assert(ob->id.tag & LIB_TAG_COPIED_ON_WRITE);
+
+ BKE_object_free_derived_caches(ob);
+ if (DEG_is_active(depsgraph)) {
+ BKE_sculpt_update_object_before_eval(ob);
+ }
+
+ /* NOTE: Access the `edit_mesh` after freeing the derived caches, so that `ob->data` is restored
+ * to the pre-evaluated state. This is because the evaluated state is not necessarily sharing the
+ * `edit_mesh` pointer with the input. For example, if the object is first evaluated in the
+ * object mode, and then user in another scene moves object to edit mode. */
+ BMEditMesh *em = ((Mesh *)ob->data)->edit_mesh;
+
bool need_mapping;
CustomData_MeshMasks cddata_masks = *dataMask;
object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping);
@@ -2021,8 +1982,9 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph,
!CustomData_MeshMasks_are_matching(&(ob->runtime.last_data_mask), &cddata_masks) ||
(need_mapping && !ob->runtime.last_need_mapping)) {
CustomData_MeshMasks_update(&cddata_masks, &ob->runtime.last_data_mask);
- mesh_build_data(
- depsgraph, scene, ob, &cddata_masks, need_mapping || ob->runtime.last_need_mapping);
+
+ makeDerivedMesh(depsgraph, scene, ob, dataMask);
+
mesh_eval = BKE_object_get_evaluated_mesh(ob);
}
@@ -2037,6 +1999,15 @@ Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph,
Object *ob,
const CustomData_MeshMasks *dataMask)
{
+ BMEditMesh *em = ((Mesh *)ob->data)->edit_mesh;
+ if (em != nullptr) {
+ /* There is no such a concept as deformed mesh in edit mode.
+ * Explicitly disallow this request so that the evaluated result is not modified with evaluated
+ * result from the wrong mode. */
+ BLI_assert_msg(0, "Request of derformed mesh of object which is in edit mode");
+ return nullptr;
+ }
+
/* This function isn't thread-safe and can't be used during evaluation. */
BLI_assert(DEG_is_evaluating(depsgraph) == false);
@@ -2074,18 +2045,6 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
return result;
}
-Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- const CustomData_MeshMasks *dataMask,
- int index)
-{
- Mesh *result;
- mesh_calc_modifiers(
- depsgraph, scene, ob, true, false, dataMask, index, false, false, nullptr, &result, nullptr);
- return result;
-}
-
Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -2110,33 +2069,6 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
/***/
-Mesh *editbmesh_get_eval_cage_and_final(Depsgraph *depsgraph,
- Scene *scene,
- Object *obedit,
- BMEditMesh *em,
- const CustomData_MeshMasks *dataMask,
- /* return args */
- Mesh **r_final)
-{
- CustomData_MeshMasks cddata_masks = *dataMask;
-
- /* if there's no derived mesh or the last data mask used doesn't include
- * the data we need, rebuild the derived mesh
- */
- object_get_datamask(depsgraph, obedit, &cddata_masks, nullptr);
-
- if (!em->mesh_eval_cage ||
- !CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) {
- editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
- }
-
- *r_final = em->mesh_eval_final;
- if (em->mesh_eval_final) {
- BLI_assert(!(em->mesh_eval_final->runtime.cd_dirty_vert & DM_DIRTY_NORMALS));
- }
- return em->mesh_eval_cage;
-}
-
Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
Scene *scene,
Object *obedit,
@@ -2150,12 +2082,12 @@ Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph,
*/
object_get_datamask(depsgraph, obedit, &cddata_masks, nullptr);
- if (!em->mesh_eval_cage ||
- !CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) {
+ if (!obedit->runtime.editmesh_eval_cage ||
+ !CustomData_MeshMasks_are_matching(&(obedit->runtime.last_data_mask), &cddata_masks)) {
editbmesh_build_data(depsgraph, scene, obedit, em, &cddata_masks);
}
- return em->mesh_eval_cage;
+ return obedit->runtime.editmesh_eval_cage;
}
Mesh *editbmesh_get_eval_cage_from_orig(struct Depsgraph *depsgraph,
@@ -2181,8 +2113,7 @@ struct MappedUserData {
static void make_vertexcos__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
MappedUserData *mappedData = (MappedUserData *)userData;
@@ -2229,6 +2160,7 @@ void DM_calc_loop_tangents(DerivedMesh *dm,
calc_active_tangent,
tangent_names,
tangent_names_len,
+ (const float(*)[3])CustomData_get_layer(&dm->vertData, CD_NORMAL),
(const float(*)[3])CustomData_get_layer(&dm->polyData, CD_NORMAL),
(const float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL),
(const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* may be nullptr */
@@ -2311,145 +2243,3 @@ static void mesh_init_origspace(Mesh *mesh)
BKE_mesh_tessface_clear(mesh);
}
-
-/* derivedmesh info printing function,
- * to help track down differences DM output */
-
-#ifndef NDEBUG
-# include "BLI_dynstr.h"
-
-static void dm_debug_info_layers(DynStr *dynstr,
- DerivedMesh *dm,
- CustomData *cd,
- void *(*getElemDataArray)(DerivedMesh *, int))
-{
- int type;
-
- for (type = 0; type < CD_NUMTYPES; type++) {
- if (CustomData_has_layer(cd, type)) {
- /* NOTE: doesn't account for multiple layers. */
- const char *name = CustomData_layertype_name(type);
- const int size = CustomData_sizeof(type);
- const void *pt = getElemDataArray(dm, type);
- const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
- const char *structname;
- int structnum;
- CustomData_file_write_info(type, &structname, &structnum);
- BLI_dynstr_appendf(
- dynstr,
- " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
- name,
- structname,
- type,
- (const void *)pt,
- size,
- pt_size);
- }
- }
-}
-
-char *DM_debug_info(DerivedMesh *dm)
-{
- DynStr *dynstr = BLI_dynstr_new();
- char *ret;
- const char *tstr;
-
- BLI_dynstr_append(dynstr, "{\n");
- BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)dm);
- switch (dm->type) {
- case DM_TYPE_CDDM:
- tstr = "DM_TYPE_CDDM";
- break;
- case DM_TYPE_CCGDM:
- tstr = "DM_TYPE_CCGDM";
- break;
- default:
- tstr = "UNKNOWN";
- break;
- }
- BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
- BLI_dynstr_appendf(dynstr, " 'numVertData': %d,\n", dm->numVertData);
- BLI_dynstr_appendf(dynstr, " 'numEdgeData': %d,\n", dm->numEdgeData);
- BLI_dynstr_appendf(dynstr, " 'numTessFaceData': %d,\n", dm->numTessFaceData);
- BLI_dynstr_appendf(dynstr, " 'numPolyData': %d,\n", dm->numPolyData);
- BLI_dynstr_appendf(dynstr, " 'deformedOnly': %d,\n", dm->deformedOnly);
-
- BLI_dynstr_append(dynstr, " 'vertexLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->vertData, dm->getVertDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'edgeLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->edgeData, dm->getEdgeDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'loopLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->loopData, dm->getLoopDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'polyLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->polyData, dm->getPolyDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->faceData, dm->getTessFaceDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, "}\n");
-
- ret = BLI_dynstr_get_cstring(dynstr);
- BLI_dynstr_free(dynstr);
- return ret;
-}
-
-void DM_debug_print(DerivedMesh *dm)
-{
- char *str = DM_debug_info(dm);
- puts(str);
- fflush(stdout);
- MEM_freeN(str);
-}
-
-bool DM_is_valid(DerivedMesh *dm)
-{
- const bool do_verbose = true;
- const bool do_fixes = false;
-
- bool is_valid = true;
- bool changed = true;
-
- is_valid &= BKE_mesh_validate_all_customdata(
- dm->getVertDataLayout(dm),
- dm->getNumVerts(dm),
- dm->getEdgeDataLayout(dm),
- dm->getNumEdges(dm),
- dm->getLoopDataLayout(dm),
- dm->getNumLoops(dm),
- dm->getPolyDataLayout(dm),
- dm->getNumPolys(dm),
- false, /* setting mask here isn't useful, gives false positives */
- do_verbose,
- do_fixes,
- &changed);
-
- is_valid &= BKE_mesh_validate_arrays(nullptr,
- dm->getVertArray(dm),
- dm->getNumVerts(dm),
- dm->getEdgeArray(dm),
- dm->getNumEdges(dm),
- dm->getTessFaceArray(dm),
- dm->getNumTessFaces(dm),
- dm->getLoopArray(dm),
- dm->getNumLoops(dm),
- dm->getPolyArray(dm),
- dm->getNumPolys(dm),
- (MDeformVert *)dm->getVertDataArray(dm, CD_MDEFORMVERT),
- do_verbose,
- do_fixes,
- &changed);
-
- BLI_assert(changed == false);
-
- return is_valid;
-}
-
-#endif /* NDEBUG */
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index ddba726ba83..fde42304185 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -307,7 +307,7 @@ static void action_asset_pre_save(void *asset_ptr, struct AssetMetaData *asset_d
BKE_asset_metadata_idprop_ensure(asset_data, action_type);
}
-AssetTypeInfo AssetType_AC = {
+static AssetTypeInfo AssetType_AC = {
/* pre_save_fn */ action_asset_pre_save,
};
@@ -705,7 +705,12 @@ bool BKE_pose_channels_is_valid(const bPose *pose)
#endif
-bPoseChannel *BKE_pose_channel_active(Object *ob)
+bool BKE_pose_is_layer_visible(const bArmature *arm, const bPoseChannel *pchan)
+{
+ return (pchan->bone->layer & arm->layer);
+}
+
+bPoseChannel *BKE_pose_channel_active(Object *ob, const bool check_arm_layer)
{
bArmature *arm = (ob) ? ob->data : NULL;
bPoseChannel *pchan;
@@ -716,14 +721,21 @@ bPoseChannel *BKE_pose_channel_active(Object *ob)
/* find active */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone) && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer)) {
- return pchan;
+ if ((pchan->bone) && (pchan->bone == arm->act_bone)) {
+ if (!check_arm_layer || BKE_pose_is_layer_visible(arm, pchan)) {
+ return pchan;
+ }
}
}
return NULL;
}
+bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob)
+{
+ return BKE_pose_channel_active(ob, true);
+}
+
bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
{
bArmature *arm = (ob) ? ob->data : NULL;
@@ -732,7 +744,7 @@ bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
return NULL;
}
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && (pchan->bone->flag & BONE_SELECTED) && PBONE_VISIBLE(arm, pchan->bone)) {
return pchan;
}
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index d93d5c456d8..42b72a7cd66 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -676,41 +676,6 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa
}
}
-char *BKE_animdata_driver_path_hack(bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- char *base_path)
-{
- ID *id = ptr->owner_id;
- ScrArea *area = CTX_wm_area(C);
-
- /* get standard path which may be extended */
- char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop);
- char *path = basepath; /* in case no remapping is needed */
-
- /* Remapping will only be performed in the Properties Editor, as only this
- * restricts the subspace of options to the 'active' data (a manageable state)
- */
- /* TODO: watch out for pinned context? */
- if ((area) && (area->spacetype == SPACE_PROPERTIES)) {
- Object *ob = CTX_data_active_object(C);
-
- if (ob && id) {
- /* TODO: after material textures were removed, this function serves
- * no purpose anymore, but could be used again so was not removed. */
-
- /* fix RNA pointer, as we've now changed the ID root by changing the paths */
- if (basepath != path) {
- /* rebase provided pointer so that it starts from object... */
- RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
- }
- }
- }
-
- /* the path should now have been corrected for use */
- return path;
-}
-
/* Path Validation -------------------------------------------- */
/* Check if a given RNA Path is valid, by tracing it from the given ID,
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 0a91d662c1b..5704ef6e42f 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1356,9 +1356,12 @@ static void ease_handle_axis(const float deriv1[3], const float deriv2[3], float
copy_v3_v3(r_axis, deriv1);
- float len1 = len_squared_v3(deriv1), len2 = len_squared_v3(deriv2);
- float ratio = len1 / len2;
-
+ const float len2 = len_squared_v3(deriv2);
+ if (UNLIKELY(len2 == 0.0f)) {
+ return;
+ }
+ const float len1 = len_squared_v3(deriv1);
+ const float ratio = len1 / len2;
if (ratio < gap * gap) {
madd_v3_v3fl(r_axis, deriv2, gap - sqrtf(ratio));
}
@@ -2098,6 +2101,79 @@ void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_mat[3][3])
{
+ /**
+ * 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.
+ */
+
const float SAFE_THRESHOLD = 6.1e-3f; /* Theta above this value has good enough precision. */
const float CRITICAL_THRESHOLD = 2.5e-4f; /* True singularity if XZ distance is below this. */
const float THRESHOLD_SQUARED = CRITICAL_THRESHOLD * CRITICAL_THRESHOLD;
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index aec622bb71f..06dd623ff28 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -24,7 +24,7 @@
#include "BKE_asset_catalog.hh"
#include "BKE_asset_library.h"
-#include "BLI_fileops.h"
+#include "BLI_fileops.hh"
#include "BLI_path_util.h"
/* For S_ISREG() and S_ISDIR() on Windows. */
@@ -32,6 +32,10 @@
# include "BLI_winstuff.h"
#endif
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"bke.asset_service"};
+
namespace blender::bke {
const CatalogFilePath AssetCatalogService::DEFAULT_CATALOG_FILENAME = "blender_assets.cats.txt";
@@ -311,6 +315,7 @@ void AssetCatalogService::load_from_disk(const CatalogFilePath &file_or_director
BLI_stat_t status;
if (BLI_stat(file_or_directory_path.data(), &status) == -1) {
/* TODO(@sybren): throw an appropriate exception. */
+ CLOG_WARN(&LOG, "path not found: %s", file_or_directory_path.data());
return;
}
@@ -337,6 +342,7 @@ void AssetCatalogService::load_directory_recursive(const CatalogFilePath &direct
if (!BLI_exists(file_path.data())) {
/* No file to be loaded is perfectly fine. */
+ CLOG_INFO(&LOG, 2, "path not found: %s", file_path.data());
return;
}
@@ -514,7 +520,7 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing(
"A non-empty .blend file path is required to be able to determine where the "
"catalog definition file should be put");
- /* Ask the asset library API for an appropriate location. */
+ /* Ask the asset library API for an appropriate location. */
char suitable_root_path[PATH_MAX];
const bool asset_lib_root_found = BKE_asset_library_find_suitable_root_path_from_path(
blend_file_path.c_str(), suitable_root_path);
@@ -824,8 +830,12 @@ void AssetCatalogDefinitionFile::parse_catalog_file(
const CatalogFilePath &catalog_definition_file_path,
AssetCatalogParsedFn catalog_loaded_callback)
{
- std::fstream infile(catalog_definition_file_path);
+ fstream infile(catalog_definition_file_path, std::ios::in);
+ if (!infile.is_open()) {
+ CLOG_ERROR(&LOG, "%s: unable to open file", catalog_definition_file_path.c_str());
+ return;
+ }
bool seen_version_number = false;
std::string line;
while (std::getline(infile, line)) {
@@ -956,7 +966,7 @@ bool AssetCatalogDefinitionFile::write_to_disk_unsafe(const CatalogFilePath &des
return false;
}
- std::ofstream output(dest_file_path);
+ fstream output(dest_file_path, std::ios::out);
/* TODO(@sybren): remember the line ending style that was originally read, then use that to write
* the file again. */
diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc
index ba8f8716823..8c39bfc9770 100644
--- a/source/blender/blenkernel/intern/asset_catalog_test.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_test.cc
@@ -27,6 +27,8 @@
#include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
+#include "CLG_log.h"
+
#include "testing/testing.h"
namespace blender::bke::tests {
@@ -93,6 +95,18 @@ class AssetCatalogTest : public testing::Test {
CatalogFilePath asset_library_root_;
CatalogFilePath temp_library_path_;
+ static void SetUpTestSuite()
+ {
+ testing::Test::SetUpTestSuite();
+ CLG_init();
+ }
+
+ static void TearDownTestSuite()
+ {
+ CLG_exit();
+ testing::Test::TearDownTestSuite();
+ }
+
void SetUp() override
{
const std::string test_files_dir = blender::tests::flags_test_asset_dir();
@@ -225,7 +239,7 @@ class AssetCatalogTest : public testing::Test {
}
/* Create an empty CDF to add complexity. It should not save to this, but to the top-level
- * one.*/
+ * one. */
ASSERT_TRUE(BLI_file_touch(cdf_in_subdir.c_str()));
ASSERT_EQ(0, BLI_file_size(cdf_in_subdir.c_str()));
@@ -549,6 +563,30 @@ TEST_F(AssetCatalogTest, write_single_file)
/* TODO(@sybren): test ordering of catalogs in the file. */
}
+TEST_F(AssetCatalogTest, read_write_unicode_filepath)
+{
+ TestableAssetCatalogService service(asset_library_root_);
+ const CatalogFilePath load_from_path = asset_library_root_ + "/новый/" +
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME;
+ service.load_from_disk(load_from_path);
+
+ const CatalogFilePath save_to_path = use_temp_path() + "новый.cats.txt";
+ AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file();
+ ASSERT_NE(nullptr, cdf) << "unable to load " << load_from_path;
+ EXPECT_TRUE(cdf->write_to_disk(save_to_path));
+
+ AssetCatalogService loaded_service(save_to_path);
+ loaded_service.load_from_disk();
+
+ /* Test that the file was loaded correctly. */
+ const bUUID materials_uuid("a2151dff-dead-4f29-b6bc-b2c7d6cccdb4");
+ const AssetCatalog *cat = loaded_service.find_catalog(materials_uuid);
+ ASSERT_NE(nullptr, cat);
+ EXPECT_EQ(materials_uuid, cat->catalog_id);
+ EXPECT_EQ(AssetCatalogPath("Материалы"), cat->path);
+ EXPECT_EQ("Russian Materials", cat->simple_name);
+}
+
TEST_F(AssetCatalogTest, no_writing_empty_files)
{
const CatalogFilePath temp_lib_root = create_temp_path();
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 1a4265d936b..cc43a3e26a8 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -30,7 +30,7 @@
#include "DNA_pointcloud_types.h"
#include "BLI_color.hh"
-#include "BLI_float2.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "BLT_translation.h"
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
index b77d7010efa..2cd128081eb 100644
--- a/source/blender/blenkernel/intern/attribute_access_intern.hh
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -161,7 +161,7 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
bool try_create(GeometryComponent &component,
const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
+ AttributeDomain domain,
const CustomDataType data_type,
const AttributeInit &initializer) const final;
@@ -185,8 +185,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
*/
class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
private:
- using AsReadAttribute = GVArray (*)(const void *data, const int domain_size);
- using AsWriteAttribute = GVMutableArray (*)(void *data, const int domain_size);
+ using AsReadAttribute = GVArray (*)(const void *data, int domain_size);
+ using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_size);
const AttributeDomain domain_;
const CustomDataType attribute_type_;
const CustomDataType stored_type_;
@@ -229,8 +229,8 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
* if the stored type is the same as the attribute type.
*/
class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
- using AsReadAttribute = GVArray (*)(const void *data, const int domain_size);
- using AsWriteAttribute = GVMutableArray (*)(void *data, const int domain_size);
+ using AsReadAttribute = GVArray (*)(const void *data, int domain_size);
+ using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_size);
using UpdateOnRead = void (*)(const GeometryComponent &component);
using UpdateOnWrite = void (*)(GeometryComponent &component);
const CustomDataType stored_type_;
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
index c265a6e2b7d..9b3f4c2fae8 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -440,6 +440,16 @@ static bool object_in_any_collection(Main *bmain, Object *ob)
return false;
}
+static bool collection_instantiated_by_any_object(Main *bmain, Collection *collection)
+{
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_EMPTY && ob->instance_collection == collection) {
+ return true;
+ }
+ }
+ return false;
+}
+
static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *instantiate_context,
BlendfileLinkAppendContextItem *item)
{
@@ -633,12 +643,19 @@ static void loose_data_instantiate_collection_process(
* children.
*/
Collection *collection = (Collection *)id;
+ /* The collection could be linked/appended together with an Empty object instantiating it,
+ * better not instantiate the collection in the view-layer in that case.
+ *
+ * Can easily happen when copy/pasting such instantiating empty, see T93839. */
+ const bool collection_is_instantiated = collection_instantiated_by_any_object(bmain,
+ collection);
/* Always consider adding collections directly selected by the user. */
- bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0;
+ bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0 &&
+ !collection_is_instantiated;
/* In linking case, do not enforce instantiating non-directly linked collections/objects.
- * This avoids cluttering the ViewLayers, user can instantiate themselves specific collections
+ * This avoids cluttering the view-layers, user can instantiate themselves specific collections
* or objects easily from the Outliner if needed. */
- if (!do_add_collection && do_append) {
+ if (!do_add_collection && do_append && !collection_is_instantiated) {
LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
Object *ob = coll_ob->ob;
if (!object_in_any_scene(bmain, ob)) {
@@ -664,21 +681,25 @@ static void loose_data_instantiate_collection_process(
Collection *collection = (Collection *)id;
bool do_add_collection = (id->tag & LIB_TAG_DOIT) != 0;
+ if (!do_add_collection) {
+ continue;
+ }
/* 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))) {
+ * instantiated. */
+ if (!do_instantiate_as_empty &&
+ loose_data_instantiate_collection_parents_check_recursive(collection)) {
+ continue;
+ }
+ /* When instantiated as empty, do not add indirectly linked (i.e. non-user-selected)
+ * collections. */
+ if (do_instantiate_as_empty && (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) {
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) {
+ if (do_instantiate_as_empty) {
/* 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;
@@ -726,6 +747,8 @@ static void loose_data_instantiate_object_process(LooseDataInstantiateContext *i
* if you want it do it at the editor level. */
const bool object_set_active = false;
+ const bool is_linking = (lapp_context->params->flag & FILE_LINK) != 0;
+
/* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used
* anywhere. */
LinkNode *itemlink;
@@ -736,6 +759,17 @@ static void loose_data_instantiate_object_process(LooseDataInstantiateContext *i
continue;
}
+ /* In linking case, never instantiate stray objects that are not directly linked.
+ *
+ * While this is not ideal (in theory no object should remain un-owned), in case of indirectly
+ * linked objects, the other solution would be to add them to a local collection, which would
+ * make them directly linked. Think for now keeping them indirectly linked is more important.
+ * Ref. T93757.
+ */
+ if (is_linking && (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) {
+ continue;
+ }
+
Object *ob = (Object *)id;
if (object_in_any_collection(bmain, ob)) {
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 85e49774dfd..a1570b4e031 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -236,7 +236,8 @@ void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
BKE_bpath_foreach_path_main(&(BPathForeachPathData){
.bmain = bmain,
.callback_function = check_missing_files_foreach_path_cb,
- .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED,
+ .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED |
+ BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN | BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES,
.user_data = reports});
}
@@ -384,7 +385,8 @@ void BKE_bpath_missing_files_find(Main *bmain,
const bool find_all)
{
struct BPathFind_Data data = {NULL};
- const int flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_RELOAD_EDITED;
+ const int flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_RELOAD_EDITED |
+ BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN;
data.basedir = BKE_main_blendfile_path(bmain);
data.reports = reports;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 153a65d67db..c86d4658cc9 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -149,16 +149,9 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
Brush *brush = (Brush *)id;
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
- bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
- bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
- BLI_assert(force_copy == false || force_copy != force_local);
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing (unless force_local is set)
- * - only local users: set flag
- * - mixed: make copy
- */
+ bool force_local, force_copy;
+ BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
if (brush->clone.image) {
/* Special case: ima always local immediately. Clone image should only have one user anyway. */
@@ -171,18 +164,6 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
BLI_assert(brush->clone.image->id.lib == NULL && brush->clone.image->id.newid == NULL);
}
- if (!force_local && !force_copy) {
- BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib);
- if (lib_local || is_local) {
- if (!is_lib) {
- force_local = true;
- }
- else {
- force_copy = true;
- }
- }
- }
-
if (force_local) {
BKE_lib_id_clear_library_data(bmain, &brush->id, flags);
BKE_lib_id_expand_local(bmain, &brush->id, flags);
diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc
index a68119fbc1d..5e7a4eea0cd 100644
--- a/source/blender/blenkernel/intern/bvhutils.cc
+++ b/source/blender/blenkernel/intern/bvhutils.cc
@@ -127,7 +127,7 @@ bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree)
BVHCache *bvhcache_init()
{
- BVHCache *cache = (BVHCache *)MEM_callocN(sizeof(BVHCache), __func__);
+ BVHCache *cache = MEM_cnew<BVHCache>(__func__);
BLI_mutex_init(&cache->mutex);
return cache;
}
@@ -1601,6 +1601,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
memset(data, 0, sizeof(*data));
}
+ data->vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+
return tree;
}
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 8833f3eabe9..75df2e98fcd 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -54,6 +54,8 @@
#include "BLO_read_write.h"
+#include "MEM_guardedalloc.h"
+
#ifdef WITH_ALEMBIC
# include "ABC_alembic.h"
#endif
@@ -86,6 +88,7 @@ static void cache_file_copy_data(Main *UNUSED(bmain),
cache_file_dst->handle = NULL;
cache_file_dst->handle_readers = NULL;
BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_src->object_paths);
+ BLI_duplicatelist(&cache_file_dst->layers, &cache_file_src->layers);
}
static void cache_file_free_data(ID *id)
@@ -93,6 +96,7 @@ static void cache_file_free_data(ID *id)
CacheFile *cache_file = (CacheFile *)id;
cachefile_handle_free(cache_file);
BLI_freelistN(&cache_file->object_paths);
+ BLI_freelistN(&cache_file->layers);
}
static void cache_file_foreach_path(ID *id, BPathForeachPathData *bpath_data)
@@ -117,6 +121,11 @@ static void cache_file_blend_write(BlendWriter *writer, ID *id, const void *id_a
if (cache_file->adt) {
BKE_animdata_blend_write(writer, cache_file->adt);
}
+
+ /* write layers */
+ LISTBASE_FOREACH (CacheFileLayer *, layer, &cache_file->layers) {
+ BLO_write_struct(writer, CacheFileLayer, layer);
+ }
}
static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
@@ -130,6 +139,9 @@ static void cache_file_blend_read_data(BlendDataReader *reader, ID *id)
/* relink animdata */
BLO_read_data_address(reader, &cache_file->adt);
BKE_animdata_blend_read_data(reader, cache_file->adt);
+
+ /* relink layers */
+ BLO_read_list(reader, &cache_file->layers);
}
IDTypeInfo IDType_ID_CF = {
@@ -364,7 +376,8 @@ void BKE_cachefile_eval(Main *bmain, Depsgraph *depsgraph, CacheFile *cache_file
#ifdef WITH_ALEMBIC
if (BLI_path_extension_check_glob(filepath, "*abc")) {
cache_file->type = CACHEFILE_TYPE_ALEMBIC;
- cache_file->handle = ABC_create_handle(bmain, filepath, &cache_file->object_paths);
+ cache_file->handle = ABC_create_handle(
+ bmain, filepath, cache_file->layers.first, &cache_file->object_paths);
BLI_strncpy(cache_file->handle_filepath, filepath, FILE_MAX);
}
#endif
@@ -435,3 +448,35 @@ bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file,
const bool is_final_render = (eEvaluationMode)dag_eval_mode == DAG_EVAL_RENDER;
return cache_file->use_render_procedural && !is_final_render;
}
+
+CacheFileLayer *BKE_cachefile_add_layer(CacheFile *cache_file, const char filename[1024])
+{
+ for (CacheFileLayer *layer = cache_file->layers.first; layer; layer = layer->next) {
+ if (STREQ(layer->filepath, filename)) {
+ return NULL;
+ }
+ }
+
+ const int num_layers = BLI_listbase_count(&cache_file->layers);
+
+ CacheFileLayer *layer = MEM_callocN(sizeof(CacheFileLayer), "CacheFileLayer");
+ BLI_strncpy(layer->filepath, filename, sizeof(layer->filepath));
+
+ BLI_addtail(&cache_file->layers, layer);
+
+ cache_file->active_layer = (char)(num_layers + 1);
+
+ return layer;
+}
+
+CacheFileLayer *BKE_cachefile_get_active_layer(CacheFile *cache_file)
+{
+ return BLI_findlink(&cache_file->layers, cache_file->active_layer - 1);
+}
+
+void BKE_cachefile_remove_layer(CacheFile *cache_file, CacheFileLayer *layer)
+{
+ cache_file->active_layer = 0;
+ BLI_remlink(&cache_file->layers, layer);
+ MEM_freeN(layer);
+}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index c93d320787a..a4f3e84a2bf 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -56,6 +56,7 @@ typedef struct {
/* these point to data in the DerivedMesh custom data layers,
* they are only here for efficiency and convenience */
MVert *mvert;
+ const float (*vert_normals)[3];
MEdge *medge;
MFace *mface;
MLoop *mloop;
@@ -143,7 +144,7 @@ static void cdDM_getVertCo(DerivedMesh *dm, int index, float r_co[3])
static void cdDM_getVertNo(DerivedMesh *dm, int index, float r_no[3])
{
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- normal_short_to_float_v3(r_no, cddm->mvert[index].no);
+ copy_v3_v3(r_no, cddm->vert_normals[index]);
}
static const MeshElemMap *cdDM_getPolyMap(Object *ob, DerivedMesh *dm)
@@ -281,6 +282,7 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh,
CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, alloctype, mesh->totpoly);
cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+ cddm->vert_normals = CustomData_get_layer(&dm->vertData, CD_NORMAL);
cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 42633ff3809..43b8690e219 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -1400,8 +1400,7 @@ static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata,
float radius;
copy_v3_v3(co, treedata->vert[v_idx].co);
- normal_short_to_float_v3(no, treedata->vert[v_idx].no);
- negate_v3(no);
+ negate_v3_v3(no, treedata->vert_normals[v_idx]);
float vec_len = sin(max_diversion);
float offset[3];
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 21a9159004f..e6ce4eb9440 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -186,7 +186,7 @@ static ID *collection_owner_get(Main *bmain, ID *id)
Collection *master_collection = (Collection *)id;
BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->master_collection == master_collection) {
return &scene->id;
}
@@ -1205,9 +1205,7 @@ static void collection_object_remove_nulls(Collection *collection)
{
bool changed = false;
- for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) {
- cob_next = cob->next;
-
+ LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) {
if (cob->ob == NULL) {
BLI_freelinkN(&collection->gobject, cob);
changed = true;
@@ -1221,22 +1219,61 @@ static void collection_object_remove_nulls(Collection *collection)
void BKE_collections_object_remove_nulls(Main *bmain)
{
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
collection_object_remove_nulls(scene->master_collection);
}
- for (Collection *collection = bmain->collections.first; collection;
- collection = collection->id.next) {
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
collection_object_remove_nulls(collection);
}
}
-static void collection_null_children_remove(Collection *collection)
+/*
+ * Remove all duplicate objects from collections.
+ * This is used for library remapping, happens when remapping an object to another one already
+ * present in the collection. Otherwise this should never happen.
+ */
+static void collection_object_remove_duplicates(Collection *collection)
{
- for (CollectionChild *child = collection->children.first, *child_next = NULL; child;
- child = child_next) {
- child_next = child->next;
+ bool changed = false;
+
+ LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) {
+ if (cob->ob->runtime.collection_management) {
+ BLI_freelinkN(&collection->gobject, cob);
+ changed = true;
+ continue;
+ }
+ cob->ob->runtime.collection_management = true;
+ }
+ /* Cleanup. */
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
+ cob->ob->runtime.collection_management = false;
+ }
+
+ if (changed) {
+ BKE_collection_object_cache_free(collection);
+ }
+}
+
+void BKE_collections_object_remove_duplicates(struct Main *bmain)
+{
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ ob->runtime.collection_management = false;
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ collection_object_remove_duplicates(scene->master_collection);
+ }
+
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ collection_object_remove_duplicates(collection);
+ }
+}
+
+static void collection_null_children_remove(Collection *collection)
+{
+ LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection->children) {
if (child->collection == NULL) {
BLI_freelinkN(&collection->children, child);
}
@@ -1245,9 +1282,7 @@ static void collection_null_children_remove(Collection *collection)
static void collection_missing_parents_remove(Collection *collection)
{
- for (CollectionParent *parent = collection->parents.first, *parent_next; parent != NULL;
- parent = parent_next) {
- parent_next = parent->next;
+ LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &collection->parents) {
if ((parent->collection == NULL) || !collection_find_child(parent->collection, collection)) {
BLI_freelinkN(&collection->parents, parent);
}
@@ -1267,28 +1302,23 @@ void BKE_collections_child_remove_nulls(Main *bmain,
* otherwise we can miss some cases...
* Also, master collections are not in bmain, so we also need to loop over scenes.
*/
- for (child_collection = bmain->collections.first; child_collection != NULL;
- child_collection = child_collection->id.next) {
- collection_null_children_remove(child_collection);
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ collection_null_children_remove(collection);
}
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
collection_null_children_remove(scene->master_collection);
}
}
- for (child_collection = bmain->collections.first; child_collection != NULL;
- child_collection = child_collection->id.next) {
- collection_missing_parents_remove(child_collection);
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ collection_missing_parents_remove(collection);
}
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
collection_missing_parents_remove(scene->master_collection);
}
}
else {
- for (CollectionParent *parent = child_collection->parents.first, *parent_next; parent;
- parent = parent_next) {
- parent_next = parent->next;
-
+ LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &child_collection->parents) {
collection_null_children_remove(parent->collection);
if (!collection_find_child(parent->collection, child_collection)) {
@@ -1586,9 +1616,9 @@ static void collection_parents_rebuild_recursive(Collection *collection)
BKE_collection_parent_relations_rebuild(collection);
collection->tag &= ~COLLECTION_TAG_RELATION_REBUILD;
- for (CollectionChild *child = collection->children.first; child != NULL; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
/* See comment above in `BKE_collection_parent_relations_rebuild`. */
- if ((collection->id.tag & (LIB_TAG_NO_MAIN | LIB_TAG_COPIED_ON_WRITE)) != 0) {
+ if ((child->collection->id.tag & (LIB_TAG_NO_MAIN | LIB_TAG_COPIED_ON_WRITE)) != 0) {
continue;
}
collection_parents_rebuild_recursive(child->collection);
@@ -1598,8 +1628,7 @@ static void collection_parents_rebuild_recursive(Collection *collection)
void BKE_main_collections_parent_relations_rebuild(Main *bmain)
{
/* Only collections not in bmain (master ones in scenes) have no parent... */
- for (Collection *collection = bmain->collections.first; collection != NULL;
- collection = collection->id.next) {
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
BLI_freelistN(&collection->parents);
collection->tag |= COLLECTION_TAG_RELATION_REBUILD;
@@ -1607,7 +1636,7 @@ void BKE_main_collections_parent_relations_rebuild(Main *bmain)
/* Scene's master collections will be 'root' parent of most of our collections, so start with
* them. */
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
/* This function can be called from readfile.c, when this pointer is not guaranteed to be NULL.
*/
if (scene->master_collection != NULL) {
@@ -1619,8 +1648,7 @@ void BKE_main_collections_parent_relations_rebuild(Main *bmain)
/* We may have parent chains outside of scene's master_collection context? At least, readfile's
* lib_link_collection_data() seems to assume that, so do the same here. */
- for (Collection *collection = bmain->collections.first; collection != NULL;
- collection = collection->id.next) {
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
if (collection->tag & COLLECTION_TAG_RELATION_REBUILD) {
/* NOTE: we do not have easy access to 'which collections is root' info in that case, which
* means test for cycles in collection relationships may fail here. I don't think that is an
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index d284c32b1df..f013ef99dde 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -34,6 +34,7 @@
#include "BLI_blenlib.h"
#include "BLI_kdopbvh.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
@@ -71,6 +72,7 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_movieclip.h"
#include "BKE_object.h"
@@ -543,6 +545,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[
float vec[3] = {0.0f, 0.0f, 0.0f};
float normal[3] = {0.0f, 0.0f, 0.0f};
float weightsum = 0.0f;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me_eval);
if (me_eval) {
const MDeformVert *dvert = CustomData_get_layer(&me_eval->vdata, CD_MDEFORMVERT);
int numVerts = me_eval->totvert;
@@ -557,10 +560,8 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[
const MDeformWeight *dw = BKE_defvert_find_index(dv, defgroup);
if (dw && dw->weight > 0.0f) {
- float nor[3];
- normal_short_to_float_v3(nor, mv->no);
madd_v3_v3fl(vec, mv->co, dw->weight);
- madd_v3_v3fl(normal, nor, dw->weight);
+ madd_v3_v3fl(normal, vert_normals[i], dw->weight);
weightsum += dw->weight;
}
}
@@ -3755,7 +3756,7 @@ static void minmax_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ
copy_m4_m4(tarmat, ct->matrix);
if (data->flag & MINMAX_USEROT) {
- /* take rotation of target into account by doing the transaction in target's localspace */
+ /* Take rotation of target into account by doing the transaction in target's local-space. */
invert_m4_m4(imat, tarmat);
mul_m4_m4m4(tmat, imat, obmat);
copy_m4_m4(obmat, tmat);
@@ -3800,7 +3801,7 @@ static void minmax_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ
if (val1 > val2) {
obmat[3][index] = tarmat[3][index] + data->offset;
if (data->flag & MINMAX_USEROT) {
- /* get out of localspace */
+ /* Get out of local-space. */
mul_m4_m4m4(tmat, ct->matrix, obmat);
copy_m4_m4(cob->matrix, tmat);
}
@@ -5676,13 +5677,19 @@ bool BKE_constraint_apply_for_object(Depsgraph *depsgraph,
const float ctime = BKE_scene_frame_get(scene);
- bConstraint *new_con = BKE_constraint_duplicate_ex(con, 0, !ID_IS_LINKED(ob));
+ /* Do this all in the evaluated domain (e.g. shrinkwrap needs to access evaluated constraint
+ * target mesh). */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bConstraint *con_eval = BKE_constraints_find_name(&ob_eval->constraints, con->name);
+
+ bConstraint *new_con = BKE_constraint_duplicate_ex(con_eval, 0, !ID_IS_LINKED(ob));
ListBase single_con = {new_con, new_con};
bConstraintOb *cob = BKE_constraints_make_evalob(
- depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ depsgraph, scene_eval, ob_eval, NULL, CONSTRAINT_OBTYPE_OBJECT);
/* Undo the effect of the current constraint stack evaluation. */
- mul_m4_m4m4(cob->matrix, ob->constinv, cob->matrix);
+ mul_m4_m4m4(cob->matrix, ob_eval->constinv, cob->matrix);
/* Evaluate single constraint. */
BKE_constraints_solve(depsgraph, &single_con, cob, ctime);
@@ -5695,7 +5702,7 @@ bool BKE_constraint_apply_for_object(Depsgraph *depsgraph,
BLI_freelinkN(&single_con, new_con);
/* Apply transform from matrix. */
- BKE_object_apply_mat4(ob, ob->obmat, true, true);
+ BKE_object_apply_mat4(ob, ob_eval->obmat, true, true);
return true;
}
@@ -5722,18 +5729,25 @@ bool BKE_constraint_apply_for_pose(
const float ctime = BKE_scene_frame_get(scene);
- bConstraint *new_con = BKE_constraint_duplicate_ex(con, 0, !ID_IS_LINKED(ob));
+ /* Do this all in the evaluated domain (e.g. shrinkwrap needs to access evaluated constraint
+ * target mesh). */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name);
+ bConstraint *con_eval = BKE_constraints_find_name(&pchan_eval->constraints, con->name);
+
+ bConstraint *new_con = BKE_constraint_duplicate_ex(con_eval, 0, !ID_IS_LINKED(ob));
ListBase single_con;
single_con.first = new_con;
single_con.last = new_con;
float vec[3];
- copy_v3_v3(vec, pchan->pose_mat[3]);
+ copy_v3_v3(vec, pchan_eval->pose_mat[3]);
bConstraintOb *cob = BKE_constraints_make_evalob(
- depsgraph, scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
+ depsgraph, scene_eval, ob_eval, pchan_eval, CONSTRAINT_OBTYPE_BONE);
/* Undo the effects of currently applied constraints. */
- mul_m4_m4m4(cob->matrix, pchan->constinv, cob->matrix);
+ mul_m4_m4m4(cob->matrix, pchan_eval->constinv, cob->matrix);
/* Evaluate single constraint. */
BKE_constraints_solve(depsgraph, &single_con, cob, ctime);
BKE_constraints_clear_evalob(cob);
@@ -5744,12 +5758,12 @@ bool BKE_constraint_apply_for_pose(
/* Prevent constraints breaking a chain. */
if (pchan->bone->flag & BONE_CONNECTED) {
- copy_v3_v3(pchan->pose_mat[3], vec);
+ copy_v3_v3(pchan_eval->pose_mat[3], vec);
}
/* Apply transform from matrix. */
float mat[4][4];
- BKE_armature_mat_pose_to_bone(pchan, pchan->pose_mat, mat);
+ BKE_armature_mat_pose_to_bone(pchan, pchan_eval->pose_mat, mat);
BKE_pchan_apply_mat4(pchan, mat, true);
return true;
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 6bbb9957b03..573595b6f90 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -41,6 +41,7 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
+#include "BKE_report.h"
#include "DEG_depsgraph_query.h"
@@ -109,7 +110,7 @@ float (*BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, Object
/* disable subsurf temporal, get mapped cos, and enable it */
if (modifiers_disable_subsurf_temporary(scene_eval, obedit_eval)) {
/* need to make new derivemesh */
- makeDerivedMesh(depsgraph, scene_eval, obedit_eval, editmesh_eval, &CD_MASK_BAREMESH);
+ makeDerivedMesh(depsgraph, scene_eval, obedit_eval, &CD_MASK_BAREMESH);
}
/* now get the cage */
@@ -516,3 +517,85 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
}
}
}
+
+/* -------------------------------------------------------------------- */
+/** \name Crazyspace API
+ * \{ */
+
+void BKE_crazyspace_api_eval(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *object,
+ struct ReportList *reports)
+{
+ if (object->runtime.crazyspace_deform_imats != NULL ||
+ object->runtime.crazyspace_deform_cos != NULL) {
+ return;
+ }
+
+ if (object->type != OB_MESH) {
+ BKE_report(reports,
+ RPT_ERROR,
+ "Crazyspace transformation is only available for Mesh type of objects");
+ return;
+ }
+
+ const Mesh *mesh = (const Mesh *)object->data;
+ object->runtime.crazyspace_num_verts = mesh->totvert;
+ BKE_crazyspace_build_sculpt(depsgraph,
+ scene,
+ object,
+ &object->runtime.crazyspace_deform_imats,
+ &object->runtime.crazyspace_deform_cos);
+}
+
+void BKE_crazyspace_api_displacement_to_deformed(struct Object *object,
+ struct ReportList *reports,
+ int vertex_index,
+ float displacement[3],
+ float r_displacement_deformed[3])
+{
+ if (vertex_index < 0 || vertex_index >= object->runtime.crazyspace_num_verts) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Invalid vertex index %d (expected to be within 0 to %d range)",
+ vertex_index,
+ object->runtime.crazyspace_num_verts);
+ return;
+ }
+
+ mul_v3_m3v3(r_displacement_deformed,
+ object->runtime.crazyspace_deform_imats[vertex_index],
+ displacement);
+}
+
+void BKE_crazyspace_api_displacement_to_original(struct Object *object,
+ struct ReportList *reports,
+ int vertex_index,
+ float displacement_deformed[3],
+ float r_displacement[3])
+{
+ if (vertex_index < 0 || vertex_index >= object->runtime.crazyspace_num_verts) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Invalid vertex index %d (expected to be within 0 to %d range))",
+ vertex_index,
+ object->runtime.crazyspace_num_verts);
+ return;
+ }
+
+ float mat[3][3];
+ if (!invert_m3_m3(mat, object->runtime.crazyspace_deform_imats[vertex_index])) {
+ copy_v3_v3(r_displacement, displacement_deformed);
+ return;
+ }
+
+ mul_v3_m3v3(r_displacement, mat, displacement_deformed);
+}
+
+void BKE_crazyspace_api_eval_clear(Object *object)
+{
+ MEM_SAFE_FREE(object->runtime.crazyspace_deform_imats);
+ MEM_SAFE_FREE(object->runtime.crazyspace_deform_cos);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index d532ed9e4b2..7481d4df351 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -278,13 +278,13 @@ void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const ch
token = token.substr(first, (last - first + 1));
if (*token.begin() == '<' && *(--token.end()) == '>') {
float encoded_hash = atof(token.substr(1, token.length() - 2).c_str());
- entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__);
+ entry = MEM_cnew<CryptomatteEntry>(__func__);
entry->encoded_hash = encoded_hash;
}
else {
const char *name = token.c_str();
int name_len = token.length();
- entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__);
+ entry = MEM_cnew<CryptomatteEntry>(__func__);
STRNCPY(entry->name, name);
uint32_t hash = BKE_cryptomatte_hash(name, name_len);
entry->encoded_hash = BKE_cryptomatte_hash_to_float(hash);
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.cc
index 2f1b01316a1..70edaccb244 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -21,15 +21,16 @@
* \ingroup bke
*/
-#include <math.h> /* floor */
-#include <stdlib.h>
-#include <string.h>
+#include <cmath> /* floor */
+#include <cstdlib>
+#include <cstring>
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_endian_switch.h"
#include "BLI_ghash.h"
+#include "BLI_index_range.hh"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -43,7 +44,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"
@@ -67,10 +68,12 @@
#include "BLO_read_write.h"
+using blender::IndexRange;
+
/* globals */
/* local */
-static CLG_LogRef LOG = {"bke.curve"};
+// static CLG_LogRef LOG = {"bke.curve"};
static void curve_init_data(ID *id)
{
@@ -89,12 +92,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 +107,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 +151,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 +191,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 +221,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 +244,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 +264,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,33 +307,33 @@ 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,
- .asset_type_info = NULL,
-
- .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,
- .foreach_path = 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,
};
void BKE_curve_editfont_free(Curve *cu)
@@ -349,21 +352,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)
@@ -371,8 +374,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)
@@ -381,7 +384,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;
}
}
@@ -395,12 +398,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) {
@@ -408,7 +411,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)
@@ -416,7 +419,7 @@ 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);
@@ -429,7 +432,7 @@ ListBase *BKE_curve_editNurbs_get(Curve *cu)
return &cu->editnurb->nurbs;
}
- return NULL;
+ return nullptr;
}
const ListBase *BKE_curve_editNurbs_get_for_read(const Curve *cu)
@@ -438,7 +441,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 +484,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 +498,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 +621,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 +648,7 @@ void BKE_nurb_free(Nurb *nu)
void BKE_nurbList_free(ListBase *lb)
{
- if (lb == NULL) {
+ if (lb == nullptr) {
return;
}
@@ -661,8 +664,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 +678,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);
}
}
@@ -707,8 +710,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");
@@ -837,7 +840,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) {
@@ -881,9 +884,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;
@@ -911,7 +914,7 @@ float BKE_nurb_calc_length(const Nurb *nu, int resolution)
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;
@@ -927,7 +930,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;
@@ -978,7 +981,7 @@ BezTriple *BKE_nurb_bezt_get_next(Nurb *nu, BezTriple *bezt)
bezt_next = nu->bezt;
}
else {
- bezt_next = NULL;
+ bezt_next = nullptr;
}
}
else {
@@ -999,7 +1002,7 @@ BPoint *BKE_nurb_bpoint_get_next(Nurb *nu, BPoint *bp)
bp_next = nu->bp;
}
else {
- bp_next = NULL;
+ bp_next = nullptr;
}
}
else {
@@ -1021,7 +1024,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 {
@@ -1043,7 +1046,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 {
@@ -1160,81 +1163,34 @@ void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3])
static void calcknots(float *knots, const int pnts, const short order, const short flag)
{
- /* knots: number of pnts NOT corrected for cyclic */
- const int pnts_order = pnts + order;
- float k;
- int a;
-
- switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) {
- case CU_NURB_ENDPOINT:
- k = 0.0;
- for (a = 1; a <= pnts_order; a++) {
- knots[a - 1] = k;
- if (a >= order && a <= pnts) {
- k += 1.0f;
- }
- }
- break;
- case CU_NURB_BEZIER:
- /* Warning, the order MUST be 2 or 4,
- * if this is not enforced, the displist will be corrupt */
- if (order == 4) {
- k = 0.34;
- for (a = 0; a < pnts_order; a++) {
- knots[a] = floorf(k);
- k += (1.0f / 3.0f);
- }
- }
- else if (order == 3) {
- k = 0.6f;
- for (a = 0; a < pnts_order; a++) {
- if (a >= order && a <= pnts) {
- k += 0.5f;
- }
- knots[a] = floorf(k);
- }
- }
- else {
- CLOG_ERROR(&LOG, "bez nurb curve order is not 3 or 4, should never happen");
- }
- break;
- default:
- for (a = 0; a < pnts_order; a++) {
- knots[a] = (float)a;
- }
- break;
- }
-}
-
-static void makecyclicknots(float *knots, int pnts, short order)
-/* pnts, order: number of pnts NOT corrected for cyclic */
-{
- int a, b, order2, c;
+ const bool is_cyclic = flag & CU_NURB_CYCLIC;
+ const bool is_bezier = flag & CU_NURB_BEZIER && !(flag & CU_NURB_ENDPOINT);
+ const bool is_end_point = flag & CU_NURB_ENDPOINT && !(flag & CU_NURB_BEZIER);
+ /* Inner knots are always repeated once except on Bezier case. */
+ const int repeat_inner = is_bezier ? order - 1 : 1;
+ /* How many times to repeat 0.0 at the beginning of knot. */
+ const int head = is_end_point && !is_cyclic ? order : (is_bezier ? order / 2 : 1);
+ /* Number of knots replicating widths of the starting knots.
+ * Covers both Cyclic and EndPoint cases. */
+ const int tail = is_cyclic ? 2 * order - 1 : (is_end_point ? order : 0);
- if (knots == NULL) {
- return;
- }
+ const int knot_count = pnts + order + (is_cyclic ? order - 1 : 0);
- order2 = order - 1;
+ int r = head;
+ float current = 0.0f;
- /* do first long rows (order -1), remove identical knots at endpoints */
- if (order > 2) {
- b = pnts + order2;
- for (a = 1; a < order2; a++) {
- if (knots[b] != knots[b - a]) {
- break;
- }
- }
- if (a == order2) {
- knots[pnts + order - 2] += 1.0f;
+ for (const int i : IndexRange(knot_count - tail)) {
+ knots[i] = current;
+ r--;
+ if (r == 0) {
+ current += 1.0;
+ r = repeat_inner;
}
}
- b = order;
- c = pnts + order + order2;
- for (a = pnts + order2; a < c; a++) {
- knots[a] = knots[a - 1] + (knots[b] - knots[b - 1]);
- b--;
+ const int tail_index = knot_count - tail;
+ for (const int i : IndexRange(tail)) {
+ knots[tail_index + i] = current + (knots[i] - knots[0]);
}
}
@@ -1246,17 +1202,11 @@ 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");
- 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);
- }
- else {
- calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu);
- }
+ nu->knotsu = (float *)MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots");
+ calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu);
}
else {
- nu->knotsu = NULL;
+ nu->knotsu = nullptr;
}
}
else if (uv == 2) {
@@ -1264,17 +1214,11 @@ 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");
- 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);
- }
- else {
- calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv);
- }
+ nu->knotsv = (float *)MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots");
+ calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv);
}
else {
- nu->knotsv = NULL;
+ nu->knotsv = nullptr;
}
}
}
@@ -1378,7 +1322,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) {
@@ -1387,7 +1331,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;
}
@@ -1438,7 +1382,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;
}
@@ -1576,13 +1520,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;
}
@@ -1676,16 +1620,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;
@@ -1734,7 +1678,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) {
@@ -1747,19 +1691,19 @@ 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);
}
@@ -1784,7 +1728,7 @@ 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;
@@ -1809,7 +1753,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;
}
@@ -1835,7 +1779,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);
}
}
@@ -1948,7 +1892,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;
@@ -2022,7 +1966,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;
}
@@ -2070,7 +2014,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) {
@@ -2084,14 +2028,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) {
@@ -2099,15 +2043,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;
@@ -2329,14 +2273,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];
@@ -2489,12 +2433,15 @@ static void make_bevel_list_segment_3D(BevList *bl)
normalize_v3(bevp1->dir);
vec_to_quat(bevp1->quat, bevp1->dir, 5, 1);
-
axis_angle_to_quat(q, bevp1->dir, bevp1->tilt);
mul_qt_qtqt(bevp1->quat, q, bevp1->quat);
normalize_qt(bevp1->quat);
+
copy_v3_v3(bevp2->dir, bevp1->dir);
- copy_qt_qt(bevp2->quat, bevp1->quat);
+ vec_to_quat(bevp2->quat, bevp2->dir, 5, 1);
+ axis_angle_to_quat(q, bevp2->dir, bevp2->tilt);
+ mul_qt_qtqt(bevp2->quat, q, bevp2->quat);
+ normalize_qt(bevp2->quat);
}
/* only for 2 points */
@@ -2597,13 +2544,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);
@@ -2614,22 +2561,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;
@@ -2637,7 +2583,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);
@@ -2654,7 +2600,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) {
@@ -2665,8 +2611,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;
@@ -2695,11 +2641,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 = MEM_cnew<BevList>(__func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = 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);
@@ -2719,7 +2665,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;
@@ -2745,11 +2691,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 = MEM_cnew<BevList>(__func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = 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);
@@ -2761,7 +2707,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;
}
@@ -2793,7 +2739,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++;
@@ -2805,10 +2751,10 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
}
else {
- /* always do all three, to prevent data hanging around */
+ /* Always do all three, to prevent data hanging around. */
int j;
- /* BevPoint must stay aligned to 4 so sizeof(BevPoint)/sizeof(float) works */
+ /* #BevPoint must stay aligned to 4 so `sizeof(BevPoint) / sizeof(float)` works. */
for (j = 0; j < 3; j++) {
BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
prevbezt->vec[2][j],
@@ -2819,13 +2765,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));
@@ -2839,15 +2785,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;
@@ -2881,11 +2827,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 = MEM_cnew<BevList>(__func__);
+ bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
- bl->seglen = 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;
@@ -2899,14 +2845,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++;
@@ -2958,7 +2904,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++;
@@ -2980,10 +2926,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;
@@ -2992,7 +2938,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;
@@ -3004,7 +2950,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);
@@ -3023,7 +2969,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;
@@ -3114,7 +3060,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ else if (bl->nr == 2) { /* 2 points, treat separately. */
make_bevel_list_segment_2D(bl);
}
else {
@@ -3129,7 +3075,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 {
@@ -3169,7 +3115,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];
@@ -3180,7 +3126,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];
@@ -3258,13 +3204,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;
}
}
}
@@ -3285,13 +3231,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;
}
}
}
@@ -3321,13 +3267,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;
}
@@ -3402,19 +3348,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 {
@@ -3430,7 +3376,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.
*/
@@ -3449,10 +3396,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;
@@ -3521,9 +3468,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) {
@@ -3790,7 +3737,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;
@@ -3819,7 +3766,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;
}
@@ -3995,8 +3942,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++) {
@@ -4024,7 +3971,7 @@ void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
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);
}
void BKE_nurb_handle_calc_ex(BezTriple *bezt,
@@ -4034,12 +3981,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);
}
/**
@@ -4072,7 +4020,7 @@ 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);
}
}
@@ -4172,7 +4120,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;
}
@@ -4187,13 +4135,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;
@@ -4207,13 +4155,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;
}
@@ -4545,7 +4493,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--) {
@@ -4615,7 +4563,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;
@@ -4654,7 +4603,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);
}
}
@@ -4690,14 +4639,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) {
@@ -4857,7 +4806,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;
@@ -4873,7 +4822,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;
@@ -4895,7 +4844,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;
@@ -4927,7 +4876,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;
@@ -4947,20 +4896,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;
@@ -4979,9 +4928,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;
}
@@ -5010,7 +4959,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 {
@@ -5023,13 +4972,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);
}
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;
@@ -5065,12 +5014,12 @@ void BKE_curve_nurb_vert_active_set(Curve *cu, const Nurb *nu, const void *vert)
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) {
@@ -5087,7 +5036,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)
@@ -5097,13 +5046,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;
}
@@ -5118,7 +5067,7 @@ void BKE_curve_nurb_vert_active_validate(Curve *cu)
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.
*
@@ -5127,7 +5076,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. */
@@ -5232,7 +5181,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) {
@@ -5290,7 +5239,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) {
@@ -5442,11 +5391,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);
}
}
@@ -5536,8 +5484,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_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index 38f736e6907..e2461adaaca 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -100,11 +100,17 @@ void CurveEval::transform(const float4x4 &matrix)
}
}
-void CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
+bool CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
{
+ bool have_minmax = false;
for (const SplinePtr &spline : this->splines()) {
- spline->bounds_min_max(min, max, use_evaluated);
+ if (spline->size()) {
+ spline->bounds_min_max(min, max, use_evaluated);
+ have_minmax = true;
+ }
}
+
+ return have_minmax;
}
float CurveEval::total_length() const
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 5522a84d094..073d9d18a04 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -401,10 +401,8 @@ struct ResultAttributes {
};
static ResultAttributes create_result_attributes(const CurveEval &curve,
const CurveEval &profile,
- Mesh &mesh)
+ MeshComponent &mesh_component)
{
- MeshComponent mesh_component;
- mesh_component.replace(&mesh, GeometryOwnershipType::Editable);
Set<AttributeIDRef> curve_attributes;
/* In order to prefer attributes on the main curve input when there are name collisions, first
@@ -708,7 +706,11 @@ Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, cons
mesh->smoothresh = DEG2RADF(180.0f);
BKE_mesh_normals_tag_dirty(mesh);
- ResultAttributes attributes = create_result_attributes(curve, profile, *mesh);
+ /* Create the mesh component for retrieving attributes at this scope, since output attributes
+ * can keep a reference to the component for updating after retrieving write access. */
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ ResultAttributes attributes = create_result_attributes(curve, profile, mesh_component);
threading::parallel_for(curves.index_range(), 128, [&](IndexRange curves_range) {
for (const int i_spline : curves_range) {
@@ -760,7 +762,10 @@ static CurveEval get_curve_single_vert()
{
CurveEval curve;
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- spline->add_point(float3(0), 0, 0.0f);
+ spline->resize(1.0f);
+ spline->positions().fill(float3(0));
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
curve.add_spline(std::move(spline));
return curve;
diff --git a/source/blender/blenkernel/intern/curveprofile.cc b/source/blender/blenkernel/intern/curveprofile.cc
index 387709fca29..8f387be41d3 100644
--- a/source/blender/blenkernel/intern/curveprofile.cc
+++ b/source/blender/blenkernel/intern/curveprofile.cc
@@ -46,7 +46,7 @@
struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset)
{
- CurveProfile *profile = (CurveProfile *)MEM_callocN(sizeof(CurveProfile), __func__);
+ CurveProfile *profile = MEM_cnew<CurveProfile>(__func__);
BKE_curveprofile_set_defaults(profile);
profile->preset = preset;
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.cc
index 090de26c230..5e3beab9b72 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -44,6 +44,10 @@
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
+#ifndef NDEBUG
+# include "BLI_dynstr.h"
+#endif
+
#include "BLT_translation.h"
#include "BKE_anonymous_attribute.h"
@@ -69,7 +73,7 @@
#define CUSTOMDATA_GROW 5
/* ensure typemap size is ok */
-BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "size mismatch");
+BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)nullptr)->typemap) == CD_NUMTYPES, "size mismatch");
static CLG_LogRef LOG = {"bke.customdata"};
@@ -94,7 +98,7 @@ bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
}
/********************* Layer type information **********************/
-typedef struct LayerTypeInfo {
+struct LayerTypeInfo {
int size; /* the memory size of one element of this layer's data */
/** name of the struct used, for file writing */
@@ -105,7 +109,7 @@ typedef struct LayerTypeInfo {
/**
* default layer name.
*
- * \note when NULL this is a way to ensure there is only ever one item
+ * \note when null this is a way to ensure there is only ever one item
* see: CustomData_layertype_is_singleton().
*/
const char *defaultname;
@@ -113,7 +117,7 @@ typedef struct LayerTypeInfo {
/**
* a function to copy count elements of this layer's data
* (deep copy if appropriate)
- * if NULL, memcpy is used
+ * if null, memcpy is used
*/
cd_copy copy;
@@ -128,7 +132,7 @@ typedef struct LayerTypeInfo {
/**
* a function to interpolate between count source elements of this
* layer's data and store the result in dest
- * if weights == NULL or sub_weights == NULL, they should default to 1
+ * if weights == null or sub_weights == null, they should default to 1
*
* weights gives the weight for each element in sources
* sub_weights gives the sub-element weights for each element in sources
@@ -146,7 +150,7 @@ typedef struct LayerTypeInfo {
void (*swap)(void *data, const int *corner_indices);
/**
- * a function to set a layer's data to default values. if NULL, the
+ * a function to set a layer's data to default values. if null, the
* default is assumed to be all zeros */
void (*set_default)(void *data, int count);
@@ -171,9 +175,9 @@ typedef struct LayerTypeInfo {
size_t (*filesize)(CDataFile *cdf, const void *data, int count);
/** a function to determine max allowed number of layers,
- * should be NULL or return -1 if no limit */
- int (*layers_max)(void);
-} LayerTypeInfo;
+ * should be null or return -1 if no limit */
+ int (*layers_max)();
+};
static void layerCopy_mdeformvert(const void *source, void *dest, int count)
{
@@ -182,17 +186,17 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count)
memcpy(dest, source, count * size);
for (i = 0; i < count; i++) {
- MDeformVert *dvert = POINTER_OFFSET(dest, i * size);
+ MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(dest, i * size));
if (dvert->totweight) {
- MDeformWeight *dw = MEM_malloc_arrayN(
- dvert->totweight, sizeof(*dw), "layerCopy_mdeformvert dw");
+ MDeformWeight *dw = static_cast<MDeformWeight *>(
+ MEM_malloc_arrayN(dvert->totweight, sizeof(*dw), __func__));
memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
dvert->dw = dw;
}
else {
- dvert->dw = NULL;
+ dvert->dw = nullptr;
}
}
}
@@ -200,11 +204,11 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count)
static void layerFree_mdeformvert(void *data, int count, int size)
{
for (int i = 0; i < count; i++) {
- MDeformVert *dvert = POINTER_OFFSET(data, i * size);
+ MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(data, i * size));
if (dvert->dw) {
MEM_freeN(dvert->dw);
- dvert->dw = NULL;
+ dvert->dw = nullptr;
dvert->totweight = 0;
}
}
@@ -216,8 +220,8 @@ static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest,
const int size = sizeof(void *);
for (int i = 0; i < count; i++) {
- void **ptr = POINTER_OFFSET(dest, i * size);
- *ptr = NULL;
+ void **ptr = (void **)POINTER_OFFSET(dest, i * size);
+ *ptr = nullptr;
}
}
@@ -231,9 +235,9 @@ void bpy_bm_generic_invalidate(struct BPy_BMGeneric *UNUSED(self))
static void layerFree_bmesh_elem_py_ptr(void *data, int count, int size)
{
for (int i = 0; i < count; i++) {
- void **ptr = POINTER_OFFSET(data, i * size);
+ void **ptr = (void **)POINTER_OFFSET(data, i * size);
if (*ptr) {
- bpy_bm_generic_invalidate(*ptr);
+ bpy_bm_generic_invalidate(static_cast<BPy_BMGeneric *>(*ptr));
}
}
}
@@ -251,14 +255,14 @@ static void layerInterp_mdeformvert(const void **sources,
MDeformWeight dw;
};
- MDeformVert *dvert = dest;
- struct MDeformWeight_Link *dest_dwlink = NULL;
+ MDeformVert *dvert = static_cast<MDeformVert *>(dest);
+ struct MDeformWeight_Link *dest_dwlink = nullptr;
struct MDeformWeight_Link *node;
/* build a list of unique def_nrs for dest */
int totweight = 0;
for (int i = 0; i < count; i++) {
- const MDeformVert *source = sources[i];
+ const MDeformVert *source = static_cast<const MDeformVert *>(sources[i]);
float interp_weight = weights[i];
for (int j = 0; j < source->totweight; j++) {
@@ -280,11 +284,12 @@ static void layerInterp_mdeformvert(const void **sources,
/* if this def_nr is not in the list, add it */
if (!node) {
- struct MDeformWeight_Link *tmp_dwlink = alloca(sizeof(*tmp_dwlink));
+ struct MDeformWeight_Link *tmp_dwlink = static_cast<MDeformWeight_Link *>(
+ alloca(sizeof(*tmp_dwlink)));
tmp_dwlink->dw.def_nr = dw->def_nr;
tmp_dwlink->dw.weight = weight;
- /* inline linklist */
+ /* Inline linked-list. */
tmp_dwlink->next = dest_dwlink;
dest_dwlink = tmp_dwlink;
@@ -305,7 +310,8 @@ static void layerInterp_mdeformvert(const void **sources,
}
if (totweight) {
- dvert->dw = MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__);
+ dvert->dw = static_cast<MDeformWeight *>(
+ MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__));
}
}
@@ -343,37 +349,13 @@ static void layerInterp_normal(const void **sources,
normalize_v3_v3((float *)dest, no);
}
-static bool layerValidate_normal(void *data, const uint totitems, const bool do_fixes)
-{
- static const float no_default[3] = {0.0f, 0.0f, 1.0f}; /* Z-up default normal... */
- float(*no)[3] = data;
- bool has_errors = false;
-
- for (int i = 0; i < totitems; i++, no++) {
- if (!is_finite_v3((float *)no)) {
- has_errors = true;
- if (do_fixes) {
- copy_v3_v3((float *)no, no_default);
- }
- }
- else if (!compare_ff(len_squared_v3((float *)no), 1.0f, 1e-6f)) {
- has_errors = true;
- if (do_fixes) {
- normalize_v3((float *)no);
- }
- }
- }
-
- return has_errors;
-}
-
static void layerCopyValue_normal(const void *source,
void *dest,
const int mixmode,
const float mixfactor)
{
- const float *no_src = source;
- float *no_dst = dest;
+ const float *no_src = (const float *)source;
+ float *no_dst = (float *)dest;
float no_tmp[3];
if (ELEM(mixmode,
@@ -416,13 +398,13 @@ static void layerCopy_tface(const void *source, void *dest, int count)
static void layerInterp_tface(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
- MTFace *tf = dest;
+ MTFace *tf = static_cast<MTFace *>(dest);
float uv[4][2] = {{0.0f}};
const float *sub_weight = sub_weights;
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MTFace *src = sources[i];
+ const MTFace *src = static_cast<const MTFace *>(sources[i]);
for (int j = 0; j < 4; j++) {
if (sub_weights) {
@@ -443,7 +425,7 @@ static void layerInterp_tface(
static void layerSwap_tface(void *data, const int *corner_indices)
{
- MTFace *tf = data;
+ MTFace *tf = static_cast<MTFace *>(data);
float uv[4][2];
for (int j = 0; j < 4; j++) {
@@ -464,7 +446,7 @@ static void layerDefault_tface(void *data, int count)
}
}
-static int layerMaxNum_tface(void)
+static int layerMaxNum_tface()
{
return MAX_MTFACE;
}
@@ -491,7 +473,7 @@ static void layerInterp_propFloat(const void **sources,
static bool layerValidate_propFloat(void *data, const uint totitems, const bool do_fixes)
{
- MFloatProperty *fp = data;
+ MFloatProperty *fp = static_cast<MFloatProperty *>(data);
bool has_errors = false;
for (int i = 0; i < totitems; i++, fp++) {
@@ -529,13 +511,13 @@ static void layerCopy_origspace_face(const void *source, void *dest, int count)
static void layerInterp_origspace_face(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
- OrigSpaceFace *osf = dest;
+ OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(dest);
float uv[4][2] = {{0.0f}};
const float *sub_weight = sub_weights;
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const OrigSpaceFace *src = sources[i];
+ const OrigSpaceFace *src = static_cast<const OrigSpaceFace *>(sources[i]);
for (int j = 0; j < 4; j++) {
if (sub_weights) {
@@ -555,7 +537,7 @@ static void layerInterp_origspace_face(
static void layerSwap_origspace_face(void *data, const int *corner_indices)
{
- OrigSpaceFace *osf = data;
+ OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(data);
float uv[4][2];
for (int j = 0; j < 4; j++) {
@@ -576,7 +558,7 @@ static void layerDefault_origspace_face(void *data, int count)
static void layerSwap_mdisps(void *data, const int *ci)
{
- MDisps *s = data;
+ MDisps *s = static_cast<MDisps *>(data);
if (s->disps) {
int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */
@@ -589,11 +571,11 @@ static void layerSwap_mdisps(void *data, const int *ci)
MEM_freeN(s->disps);
s->totdisp = (s->totdisp / corners) * nverts;
- s->disps = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisp swap");
+ s->disps = (float(*)[3])MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisp swap");
return;
}
- float(*d)[3] = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap");
+ float(*d)[3] = (float(*)[3])MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap");
for (int S = 0; S < corners; S++) {
memcpy(d + cornersize * S, s->disps + cornersize * ci[S], sizeof(float[3]) * cornersize);
@@ -606,17 +588,17 @@ static void layerSwap_mdisps(void *data, const int *ci)
static void layerCopy_mdisps(const void *source, void *dest, int count)
{
- const MDisps *s = source;
- MDisps *d = dest;
+ const MDisps *s = static_cast<const MDisps *>(source);
+ MDisps *d = static_cast<MDisps *>(dest);
for (int i = 0; i < count; i++) {
if (s[i].disps) {
- d[i].disps = MEM_dupallocN(s[i].disps);
- d[i].hidden = MEM_dupallocN(s[i].hidden);
+ d[i].disps = static_cast<float(*)[3]>(MEM_dupallocN(s[i].disps));
+ d[i].hidden = static_cast<unsigned int *>(MEM_dupallocN(s[i].hidden));
}
else {
- d[i].disps = NULL;
- d[i].hidden = NULL;
+ d[i].disps = nullptr;
+ d[i].hidden = nullptr;
}
/* still copy even if not in memory, displacement can be external */
@@ -627,7 +609,7 @@ static void layerCopy_mdisps(const void *source, void *dest, int count)
static void layerFree_mdisps(void *data, int count, int UNUSED(size))
{
- MDisps *d = data;
+ MDisps *d = static_cast<MDisps *>(data);
for (int i = 0; i < count; i++) {
if (d[i].disps) {
@@ -636,8 +618,8 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size))
if (d[i].hidden) {
MEM_freeN(d[i].hidden);
}
- d[i].disps = NULL;
- d[i].hidden = NULL;
+ d[i].disps = nullptr;
+ d[i].hidden = nullptr;
d[i].totdisp = 0;
d[i].level = 0;
}
@@ -645,16 +627,16 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size))
static bool layerRead_mdisps(CDataFile *cdf, void *data, int count)
{
- MDisps *d = data;
+ MDisps *d = static_cast<MDisps *>(data);
for (int i = 0; i < count; i++) {
if (!d[i].disps) {
- d[i].disps = MEM_calloc_arrayN(d[i].totdisp, sizeof(float[3]), "mdisps read");
+ d[i].disps = (float(*)[3])MEM_calloc_arrayN(d[i].totdisp, sizeof(float[3]), "mdisps read");
}
if (!cdf_read_data(cdf, sizeof(float[3]) * d[i].totdisp, d[i].disps)) {
CLOG_ERROR(&LOG, "failed to read multires displacement %d/%d %d", i, count, d[i].totdisp);
- return 0;
+ return false;
}
}
@@ -663,12 +645,12 @@ static bool layerRead_mdisps(CDataFile *cdf, void *data, int count)
static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count)
{
- const MDisps *d = data;
+ const MDisps *d = static_cast<const MDisps *>(data);
for (int i = 0; i < count; i++) {
if (!cdf_write_data(cdf, sizeof(float[3]) * d[i].totdisp, d[i].disps)) {
CLOG_ERROR(&LOG, "failed to write multires displacement %d/%d %d", i, count, d[i].totdisp);
- return 0;
+ return false;
}
}
@@ -677,7 +659,7 @@ static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count)
static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int count)
{
- const MDisps *d = data;
+ const MDisps *d = static_cast<const MDisps *>(data);
size_t size = 0;
for (int i = 0; i < count; i++) {
@@ -695,7 +677,7 @@ static void layerInterp_paint_mask(const void **sources,
float mask = 0.0f;
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const float *src = sources[i];
+ const float *src = static_cast<const float *>(sources[i]);
mask += (*src) * interp_weight;
}
*(float *)dest = mask;
@@ -703,16 +685,16 @@ static void layerInterp_paint_mask(const void **sources,
static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
{
- const GridPaintMask *s = source;
- GridPaintMask *d = dest;
+ const GridPaintMask *s = static_cast<const GridPaintMask *>(source);
+ GridPaintMask *d = static_cast<GridPaintMask *>(dest);
for (int i = 0; i < count; i++) {
if (s[i].data) {
- d[i].data = MEM_dupallocN(s[i].data);
+ d[i].data = static_cast<float *>(MEM_dupallocN(s[i].data));
d[i].level = s[i].level;
}
else {
- d[i].data = NULL;
+ d[i].data = nullptr;
d[i].level = 0;
}
}
@@ -720,7 +702,7 @@ static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size))
{
- GridPaintMask *gpm = data;
+ GridPaintMask *gpm = static_cast<GridPaintMask *>(data);
for (int i = 0; i < count; i++) {
MEM_SAFE_FREE(gpm[i].data);
@@ -734,8 +716,8 @@ static void layerCopyValue_mloopcol(const void *source,
const int mixmode,
const float mixfactor)
{
- const MLoopCol *m1 = source;
- MLoopCol *m2 = dest;
+ const MLoopCol *m1 = static_cast<const MLoopCol *>(source);
+ MLoopCol *m2 = static_cast<MLoopCol *>(dest);
unsigned char tmp_col[4];
if (ELEM(mixmode,
@@ -789,7 +771,8 @@ static void layerCopyValue_mloopcol(const void *source,
static bool layerEqual_mloopcol(const void *data1, const void *data2)
{
- const MLoopCol *m1 = data1, *m2 = data2;
+ const MLoopCol *m1 = static_cast<const MLoopCol *>(data1);
+ const MLoopCol *m2 = static_cast<const MLoopCol *>(data2);
float r, g, b, a;
r = m1->r - m2->r;
@@ -802,7 +785,7 @@ static bool layerEqual_mloopcol(const void *data1, const void *data2)
static void layerMultiply_mloopcol(void *data, float fac)
{
- MLoopCol *m = data;
+ MLoopCol *m = static_cast<MLoopCol *>(data);
m->r = (float)m->r * fac;
m->g = (float)m->g * fac;
@@ -812,8 +795,8 @@ static void layerMultiply_mloopcol(void *data, float fac)
static void layerAdd_mloopcol(void *data1, const void *data2)
{
- MLoopCol *m = data1;
- const MLoopCol *m2 = data2;
+ MLoopCol *m = static_cast<MLoopCol *>(data1);
+ const MLoopCol *m2 = static_cast<const MLoopCol *>(data2);
m->r += m2->r;
m->g += m2->g;
@@ -823,8 +806,9 @@ static void layerAdd_mloopcol(void *data1, const void *data2)
static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax)
{
- const MLoopCol *m = data;
- MLoopCol *min = vmin, *max = vmax;
+ const MLoopCol *m = static_cast<const MLoopCol *>(data);
+ MLoopCol *min = static_cast<MLoopCol *>(vmin);
+ MLoopCol *max = static_cast<MLoopCol *>(vmax);
if (m->r < min->r) {
min->r = m->r;
@@ -854,7 +838,8 @@ static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax)
static void layerInitMinMax_mloopcol(void *vmin, void *vmax)
{
- MLoopCol *min = vmin, *max = vmax;
+ MLoopCol *min = static_cast<MLoopCol *>(vmin);
+ MLoopCol *max = static_cast<MLoopCol *>(vmax);
min->r = 255;
min->g = 255;
@@ -882,7 +867,7 @@ static void layerInterp_mloopcol(const void **sources,
int count,
void *dest)
{
- MLoopCol *mc = dest;
+ MLoopCol *mc = static_cast<MLoopCol *>(dest);
struct {
float a;
float r;
@@ -892,7 +877,7 @@ static void layerInterp_mloopcol(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MLoopCol *src = sources[i];
+ const MLoopCol *src = static_cast<const MLoopCol *>(sources[i]);
col.r += src->r * interp_weight;
col.g += src->g * interp_weight;
col.b += src->b * interp_weight;
@@ -909,7 +894,7 @@ static void layerInterp_mloopcol(const void **sources,
mc->a = round_fl_to_uchar_clamp(col.a);
}
-static int layerMaxNum_mloopcol(void)
+static int layerMaxNum_mloopcol()
{
return MAX_MCOL;
}
@@ -919,8 +904,8 @@ static void layerCopyValue_mloopuv(const void *source,
const int mixmode,
const float mixfactor)
{
- const MLoopUV *luv1 = source;
- MLoopUV *luv2 = dest;
+ const MLoopUV *luv1 = static_cast<const MLoopUV *>(source);
+ MLoopUV *luv2 = static_cast<MLoopUV *>(dest);
/* We only support a limited subset of advanced mixing here -
* namely the mixfactor interpolation. */
@@ -935,37 +920,40 @@ static void layerCopyValue_mloopuv(const void *source,
static bool layerEqual_mloopuv(const void *data1, const void *data2)
{
- const MLoopUV *luv1 = data1, *luv2 = data2;
+ const MLoopUV *luv1 = static_cast<const MLoopUV *>(data1);
+ const MLoopUV *luv2 = static_cast<const MLoopUV *>(data2);
return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
}
static void layerMultiply_mloopuv(void *data, float fac)
{
- MLoopUV *luv = data;
+ MLoopUV *luv = static_cast<MLoopUV *>(data);
mul_v2_fl(luv->uv, fac);
}
static void layerInitMinMax_mloopuv(void *vmin, void *vmax)
{
- MLoopUV *min = vmin, *max = vmax;
+ MLoopUV *min = static_cast<MLoopUV *>(vmin);
+ MLoopUV *max = static_cast<MLoopUV *>(vmax);
INIT_MINMAX2(min->uv, max->uv);
}
static void layerDoMinMax_mloopuv(const void *data, void *vmin, void *vmax)
{
- const MLoopUV *luv = data;
- MLoopUV *min = vmin, *max = vmax;
+ const MLoopUV *luv = static_cast<const MLoopUV *>(data);
+ MLoopUV *min = static_cast<MLoopUV *>(vmin);
+ MLoopUV *max = static_cast<MLoopUV *>(vmax);
minmax_v2v2_v2(min->uv, max->uv, luv->uv);
}
static void layerAdd_mloopuv(void *data1, const void *data2)
{
- MLoopUV *l1 = data1;
- const MLoopUV *l2 = data2;
+ MLoopUV *l1 = static_cast<MLoopUV *>(data1);
+ const MLoopUV *l2 = static_cast<const MLoopUV *>(data2);
add_v2_v2(l1->uv, l2->uv);
}
@@ -983,7 +971,7 @@ static void layerInterp_mloopuv(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MLoopUV *src = sources[i];
+ const MLoopUV *src = static_cast<const MLoopUV *>(sources[i]);
madd_v2_v2fl(uv, src->uv, interp_weight);
if (interp_weight > 0.0f) {
flag |= src->flag;
@@ -997,7 +985,7 @@ static void layerInterp_mloopuv(const void **sources,
static bool layerValidate_mloopuv(void *data, const uint totitems, const bool do_fixes)
{
- MLoopUV *uv = data;
+ MLoopUV *uv = static_cast<MLoopUV *>(data);
bool has_errors = false;
for (int i = 0; i < totitems; i++, uv++) {
@@ -1018,45 +1006,48 @@ static void layerCopyValue_mloop_origspace(const void *source,
const int UNUSED(mixmode),
const float UNUSED(mixfactor))
{
- const OrigSpaceLoop *luv1 = source;
- OrigSpaceLoop *luv2 = dest;
+ const OrigSpaceLoop *luv1 = static_cast<const OrigSpaceLoop *>(source);
+ OrigSpaceLoop *luv2 = static_cast<OrigSpaceLoop *>(dest);
copy_v2_v2(luv2->uv, luv1->uv);
}
static bool layerEqual_mloop_origspace(const void *data1, const void *data2)
{
- const OrigSpaceLoop *luv1 = data1, *luv2 = data2;
+ const OrigSpaceLoop *luv1 = static_cast<const OrigSpaceLoop *>(data1);
+ const OrigSpaceLoop *luv2 = static_cast<const OrigSpaceLoop *>(data2);
return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
}
static void layerMultiply_mloop_origspace(void *data, float fac)
{
- OrigSpaceLoop *luv = data;
+ OrigSpaceLoop *luv = static_cast<OrigSpaceLoop *>(data);
mul_v2_fl(luv->uv, fac);
}
static void layerInitMinMax_mloop_origspace(void *vmin, void *vmax)
{
- OrigSpaceLoop *min = vmin, *max = vmax;
+ OrigSpaceLoop *min = static_cast<OrigSpaceLoop *>(vmin);
+ OrigSpaceLoop *max = static_cast<OrigSpaceLoop *>(vmax);
INIT_MINMAX2(min->uv, max->uv);
}
static void layerDoMinMax_mloop_origspace(const void *data, void *vmin, void *vmax)
{
- const OrigSpaceLoop *luv = data;
- OrigSpaceLoop *min = vmin, *max = vmax;
+ const OrigSpaceLoop *luv = static_cast<const OrigSpaceLoop *>(data);
+ OrigSpaceLoop *min = static_cast<OrigSpaceLoop *>(vmin);
+ OrigSpaceLoop *max = static_cast<OrigSpaceLoop *>(vmax);
minmax_v2v2_v2(min->uv, max->uv, luv->uv);
}
static void layerAdd_mloop_origspace(void *data1, const void *data2)
{
- OrigSpaceLoop *l1 = data1;
- const OrigSpaceLoop *l2 = data2;
+ OrigSpaceLoop *l1 = static_cast<OrigSpaceLoop *>(data1);
+ const OrigSpaceLoop *l2 = static_cast<const OrigSpaceLoop *>(data2);
add_v2_v2(l1->uv, l2->uv);
}
@@ -1072,7 +1063,7 @@ static void layerInterp_mloop_origspace(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const OrigSpaceLoop *src = sources[i];
+ const OrigSpaceLoop *src = static_cast<const OrigSpaceLoop *>(sources[i]);
madd_v2_v2fl(uv, src->uv, interp_weight);
}
@@ -1084,7 +1075,7 @@ static void layerInterp_mloop_origspace(const void **sources,
static void layerInterp_mcol(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
- MCol *mc = dest;
+ MCol *mc = static_cast<MCol *>(dest);
struct {
float a;
float r;
@@ -1098,7 +1089,7 @@ static void layerInterp_mcol(
for (int j = 0; j < 4; j++) {
if (sub_weights) {
- const MCol *src = sources[i];
+ const MCol *src = static_cast<const MCol *>(sources[i]);
for (int k = 0; k < 4; k++, sub_weight++, src++) {
const float w = (*sub_weight) * interp_weight;
col[j].a += src->a * w;
@@ -1108,7 +1099,7 @@ static void layerInterp_mcol(
}
}
else {
- const MCol *src = sources[i];
+ const MCol *src = static_cast<const MCol *>(sources[i]);
col[j].a += src[j].a * interp_weight;
col[j].r += src[j].r * interp_weight;
col[j].g += src[j].g * interp_weight;
@@ -1131,7 +1122,7 @@ static void layerInterp_mcol(
static void layerSwap_mcol(void *data, const int *corner_indices)
{
- MCol *mcol = data;
+ MCol *mcol = static_cast<MCol *>(data);
MCol col[4];
for (int j = 0; j < 4; j++) {
@@ -1205,7 +1196,7 @@ static void layerInterp_shapekey(const void **sources,
static void layerDefault_mvert_skin(void *data, int count)
{
- MVertSkin *vs = data;
+ MVertSkin *vs = static_cast<MVertSkin *>(data);
for (int i = 0; i < count; i++) {
copy_v3_fl(vs[i].radius, 0.25f);
@@ -1229,20 +1220,20 @@ static void layerInterp_mvert_skin(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MVertSkin *vs_src = sources[i];
+ const MVertSkin *vs_src = static_cast<const MVertSkin *>(sources[i]);
madd_v3_v3fl(radius, vs_src->radius, interp_weight);
}
/* Delay writing to the destination in case dest is in sources. */
- MVertSkin *vs_dst = dest;
+ MVertSkin *vs_dst = static_cast<MVertSkin *>(dest);
copy_v3_v3(vs_dst->radius, radius);
vs_dst->flag &= ~MVERT_SKIN_ROOT;
}
static void layerSwap_flnor(void *data, const int *corner_indices)
{
- short(*flnors)[4][3] = data;
+ short(*flnors)[4][3] = static_cast<short(*)[4][3]>(data);
short nors[4][3];
int i = 4;
@@ -1266,8 +1257,8 @@ static void layerCopyValue_propcol(const void *source,
const int mixmode,
const float mixfactor)
{
- const MPropCol *m1 = source;
- MPropCol *m2 = dest;
+ const MPropCol *m1 = static_cast<const MPropCol *>(source);
+ MPropCol *m2 = static_cast<MPropCol *>(dest);
float tmp_col[4];
if (ELEM(mixmode,
@@ -1311,7 +1302,8 @@ static void layerCopyValue_propcol(const void *source,
static bool layerEqual_propcol(const void *data1, const void *data2)
{
- const MPropCol *m1 = data1, *m2 = data2;
+ const MPropCol *m1 = static_cast<const MPropCol *>(data1);
+ const MPropCol *m2 = static_cast<const MPropCol *>(data2);
float tot = 0;
for (int i = 0; i < 4; i++) {
@@ -1324,27 +1316,29 @@ static bool layerEqual_propcol(const void *data1, const void *data2)
static void layerMultiply_propcol(void *data, float fac)
{
- MPropCol *m = data;
+ MPropCol *m = static_cast<MPropCol *>(data);
mul_v4_fl(m->color, fac);
}
static void layerAdd_propcol(void *data1, const void *data2)
{
- MPropCol *m = data1;
- const MPropCol *m2 = data2;
+ MPropCol *m = static_cast<MPropCol *>(data1);
+ const MPropCol *m2 = static_cast<const MPropCol *>(data2);
add_v4_v4(m->color, m2->color);
}
static void layerDoMinMax_propcol(const void *data, void *vmin, void *vmax)
{
- const MPropCol *m = data;
- MPropCol *min = vmin, *max = vmax;
+ const MPropCol *m = static_cast<const MPropCol *>(data);
+ MPropCol *min = static_cast<MPropCol *>(vmin);
+ MPropCol *max = static_cast<MPropCol *>(vmax);
minmax_v4v4_v4(min->color, max->color, m->color);
}
static void layerInitMinMax_propcol(void *vmin, void *vmax)
{
- MPropCol *min = vmin, *max = vmax;
+ MPropCol *min = static_cast<MPropCol *>(vmin);
+ MPropCol *max = static_cast<MPropCol *>(vmax);
copy_v4_fl(min->color, FLT_MAX);
copy_v4_fl(max->color, FLT_MIN);
@@ -1366,17 +1360,17 @@ static void layerInterp_propcol(const void **sources,
int count,
void *dest)
{
- MPropCol *mc = dest;
+ MPropCol *mc = static_cast<MPropCol *>(dest);
float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MPropCol *src = sources[i];
+ const MPropCol *src = static_cast<const MPropCol *>(sources[i]);
madd_v4_v4fl(col, src->color, interp_weight);
}
copy_v4_v4(mc->color, col);
}
-static int layerMaxNum_propcol(void)
+static int layerMaxNum_propcol()
{
return MAX_MCOL;
}
@@ -1390,7 +1384,7 @@ static void layerInterp_propfloat3(const void **sources,
vec3f result = {0.0f, 0.0f, 0.0f};
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const vec3f *src = sources[i];
+ const vec3f *src = static_cast<const vec3f *>(sources[i]);
madd_v3_v3fl(&result.x, &src->x, interp_weight);
}
copy_v3_v3((float *)dest, &result.x);
@@ -1398,7 +1392,7 @@ static void layerInterp_propfloat3(const void **sources,
static void layerMultiply_propfloat3(void *data, float fac)
{
- vec3f *vec = data;
+ vec3f *vec = static_cast<vec3f *>(data);
vec->x *= fac;
vec->y *= fac;
vec->z *= fac;
@@ -1406,8 +1400,8 @@ static void layerMultiply_propfloat3(void *data, float fac)
static void layerAdd_propfloat3(void *data1, const void *data2)
{
- vec3f *vec1 = data1;
- const vec3f *vec2 = data2;
+ vec3f *vec1 = static_cast<vec3f *>(data1);
+ const vec3f *vec2 = static_cast<const vec3f *>(data2);
vec1->x += vec2->x;
vec1->y += vec2->y;
vec1->z += vec2->z;
@@ -1415,7 +1409,7 @@ static void layerAdd_propfloat3(void *data1, const void *data2)
static bool layerValidate_propfloat3(void *data, const uint totitems, const bool do_fixes)
{
- float *values = data;
+ float *values = static_cast<float *>(data);
bool has_errors = false;
for (int i = 0; i < totitems * 3; i++) {
if (!isfinite(values[i])) {
@@ -1437,7 +1431,7 @@ static void layerInterp_propfloat2(const void **sources,
vec2f result = {0.0f, 0.0f};
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const vec2f *src = sources[i];
+ const vec2f *src = static_cast<const vec2f *>(sources[i]);
madd_v2_v2fl(&result.x, &src->x, interp_weight);
}
copy_v2_v2((float *)dest, &result.x);
@@ -1445,22 +1439,22 @@ static void layerInterp_propfloat2(const void **sources,
static void layerMultiply_propfloat2(void *data, float fac)
{
- vec2f *vec = data;
+ vec2f *vec = static_cast<vec2f *>(data);
vec->x *= fac;
vec->y *= fac;
}
static void layerAdd_propfloat2(void *data1, const void *data2)
{
- vec2f *vec1 = data1;
- const vec2f *vec2 = data2;
+ vec2f *vec1 = static_cast<vec2f *>(data1);
+ const vec2f *vec2 = static_cast<const vec2f *>(data2);
vec1->x += vec2->x;
vec1->y += vec2->y;
}
static bool layerValidate_propfloat2(void *data, const uint totitems, const bool do_fixes)
{
- float *values = data;
+ float *values = static_cast<float *>(data);
bool has_errors = false;
for (int i = 0; i < totitems * 2; i++) {
if (!isfinite(values[i])) {
@@ -1475,136 +1469,130 @@ static bool layerValidate_propfloat2(void *data, const uint totitems, const bool
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */
- {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MVert), "MVert", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 1: CD_MSTICKY */ /* DEPRECATED */
- {sizeof(float[2]), "", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[2]), "", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 2: CD_MDEFORMVERT */
{sizeof(MDeformVert),
"MDeformVert",
1,
- NULL,
+ nullptr,
layerCopy_mdeformvert,
layerFree_mdeformvert,
layerInterp_mdeformvert,
- NULL,
- NULL},
+ nullptr,
+ nullptr},
/* 3: CD_MEDGE */
- {sizeof(MEdge), "MEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MEdge), "MEdge", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 4: CD_MFACE */
- {sizeof(MFace), "MFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MFace), "MFace", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 5: CD_MTFACE */
- {sizeof(MTFace),
- "MTFace",
- 1,
- N_("UVMap"),
- layerCopy_tface,
- NULL,
- layerInterp_tface,
- layerSwap_tface,
- layerDefault_tface,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- layerMaxNum_tface},
+ {sizeof(MTFace), "MTFace", 1,
+ N_("UVMap"), layerCopy_tface, nullptr,
+ layerInterp_tface, layerSwap_tface, layerDefault_tface,
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr,
+ nullptr, layerMaxNum_tface},
/* 6: CD_MCOL */
/* 4 MCol structs per face */
{sizeof(MCol[4]),
"MCol",
4,
N_("Col"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mcol,
layerSwap_mcol,
layerDefault_mcol,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_mloopcol},
/* 7: CD_ORIGINDEX */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_origindex},
/* 8: CD_NORMAL */
/* 3 floats per normal vector */
{sizeof(float[3]),
"vec3f",
1,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerInterp_normal,
- NULL,
- NULL,
- layerValidate_normal,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
layerCopyValue_normal},
/* 9: CD_FACEMAP */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_fmap, nullptr},
/* 10: CD_PROP_FLOAT */
{sizeof(MFloatProperty),
"MFloatProperty",
1,
N_("Float"),
layerCopy_propFloat,
- NULL,
+ nullptr,
layerInterp_propFloat,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_propFloat},
/* 11: CD_PROP_INT32 */
- {sizeof(MIntProperty), "MIntProperty", 1, N_("Int"), layerCopy_propInt, NULL, NULL, NULL},
+ {sizeof(MIntProperty),
+ "MIntProperty",
+ 1,
+ N_("Int"),
+ layerCopy_propInt,
+ nullptr,
+ nullptr,
+ nullptr},
/* 12: CD_PROP_STRING */
{sizeof(MStringProperty),
"MStringProperty",
1,
N_("String"),
layerCopy_propString,
- NULL,
- NULL,
- NULL},
+ nullptr,
+ nullptr,
+ nullptr},
/* 13: CD_ORIGSPACE */
{sizeof(OrigSpaceFace),
"OrigSpaceFace",
1,
N_("UVMap"),
layerCopy_origspace_face,
- NULL,
+ nullptr,
layerInterp_origspace_face,
layerSwap_origspace_face,
layerDefault_origspace_face},
/* 14: CD_ORCO */
- {sizeof(float[3]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[3]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 15: CD_MTEXPOLY */ /* DEPRECATED */
/* NOTE: when we expose the UV Map / TexFace split to the user,
* change this back to face Texture. */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 16: CD_MLOOPUV */
{sizeof(MLoopUV),
"MLoopUV",
1,
N_("UVMap"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloopuv,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_mloopuv,
layerEqual_mloopuv,
layerMultiply_mloopuv,
@@ -1612,50 +1600,50 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerAdd_mloopuv,
layerDoMinMax_mloopuv,
layerCopyValue_mloopuv,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_tface},
/* 17: CD_MLOOPCOL */
{sizeof(MLoopCol),
"MLoopCol",
1,
N_("Col"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloopcol,
- NULL,
+ nullptr,
layerDefault_mloopcol,
- NULL,
+ nullptr,
layerEqual_mloopcol,
layerMultiply_mloopcol,
layerInitMinMax_mloopcol,
layerAdd_mloopcol,
layerDoMinMax_mloopcol,
layerCopyValue_mloopcol,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_mloopcol},
/* 18: CD_TANGENT */
- {sizeof(float[4][4]), "", 0, N_("Tangent"), NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[4][4]), "", 0, N_("Tangent"), nullptr, nullptr, nullptr, nullptr, nullptr},
/* 19: CD_MDISPS */
{sizeof(MDisps),
"MDisps",
1,
- NULL,
+ nullptr,
layerCopy_mdisps,
layerFree_mdisps,
- NULL,
+ nullptr,
layerSwap_mdisps,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
layerRead_mdisps,
layerWrite_mdisps,
layerFilesize_mdisps},
@@ -1664,52 +1652,60 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
"MCol",
4,
N_("PreviewCol"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mcol,
layerSwap_mcol,
layerDefault_mcol},
/* 21: CD_ID_MCOL */ /* DEPRECATED */
- {sizeof(MCol[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MCol[4]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 22: CD_TEXTURE_MCOL */
{sizeof(MCol[4]),
"MCol",
4,
N_("TexturedCol"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mcol,
layerSwap_mcol,
layerDefault_mcol},
/* 23: CD_CLOTH_ORCO */
- {sizeof(float[3]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[3]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 24: CD_RECAST */
- {sizeof(MRecast), "MRecast", 1, N_("Recast"), NULL, NULL, NULL, NULL},
-
- /* BMESH ONLY */
+ {sizeof(MRecast), "MRecast", 1, N_("Recast"), nullptr, nullptr, nullptr, nullptr},
/* 25: CD_MPOLY */
- {sizeof(MPoly), "MPoly", 1, N_("NGon Face"), NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MPoly), "MPoly", 1, N_("NGon Face"), nullptr, nullptr, nullptr, nullptr, nullptr},
/* 26: CD_MLOOP */
- {sizeof(MLoop), "MLoop", 1, N_("NGon Face-Vertex"), NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MLoop),
+ "MLoop",
+ 1,
+ N_("NGon Face-Vertex"),
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 27: CD_SHAPE_KEYINDEX */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 28: CD_SHAPEKEY */
- {sizeof(float[3]), "", 0, N_("ShapeKey"), NULL, NULL, layerInterp_shapekey},
+ {sizeof(float[3]), "", 0, N_("ShapeKey"), nullptr, nullptr, layerInterp_shapekey},
/* 29: CD_BWEIGHT */
- {sizeof(float), "", 0, N_("BevelWeight"), NULL, NULL, layerInterp_bweight},
+ {sizeof(float), "", 0, N_("BevelWeight"), nullptr, nullptr, layerInterp_bweight},
/* 30: CD_CREASE */
- {sizeof(float), "", 0, N_("SubSurfCrease"), NULL, NULL, layerInterp_bweight},
+ /* NOTE: we do not interpolate crease data as it should be either inherited for subdivided
+ * edges, or for vertex creases, only present on the original vertex. */
+ {sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, nullptr},
/* 31: CD_ORIGSPACE_MLOOP */
{sizeof(OrigSpaceLoop),
"OrigSpaceLoop",
1,
N_("OS Loop"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloop_origspace,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerEqual_mloop_origspace,
layerMultiply_mloop_origspace,
layerInitMinMax_mloop_origspace,
@@ -1721,12 +1717,12 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
"MLoopCol",
1,
N_("PreviewLoopCol"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloopcol,
- NULL,
+ nullptr,
layerDefault_mloopcol,
- NULL,
+ nullptr,
layerEqual_mloopcol,
layerMultiply_mloopcol,
layerInitMinMax_mloopcol,
@@ -1737,125 +1733,138 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(void *),
"",
1,
- NULL,
+ nullptr,
layerCopy_bmesh_elem_py_ptr,
layerFree_bmesh_elem_py_ptr,
- NULL,
- NULL,
- NULL},
-
- /* END BMESH ONLY */
-
+ nullptr,
+ nullptr,
+ nullptr},
/* 34: CD_PAINT_MASK */
- {sizeof(float), "", 0, NULL, NULL, NULL, layerInterp_paint_mask, NULL, NULL},
+ {sizeof(float), "", 0, nullptr, nullptr, nullptr, layerInterp_paint_mask, nullptr, nullptr},
/* 35: CD_GRID_PAINT_MASK */
{sizeof(GridPaintMask),
"GridPaintMask",
1,
- NULL,
+ nullptr,
layerCopy_grid_paint_mask,
layerFree_grid_paint_mask,
- NULL,
- NULL,
- NULL},
+ nullptr,
+ nullptr,
+ nullptr},
/* 36: CD_MVERT_SKIN */
{sizeof(MVertSkin),
"MVertSkin",
1,
- NULL,
+ nullptr,
layerCopy_mvert_skin,
- NULL,
+ nullptr,
layerInterp_mvert_skin,
- NULL,
+ nullptr,
layerDefault_mvert_skin},
/* 37: CD_FREESTYLE_EDGE */
- {sizeof(FreestyleEdge), "FreestyleEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(FreestyleEdge),
+ "FreestyleEdge",
+ 1,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 38: CD_FREESTYLE_FACE */
- {sizeof(FreestyleFace), "FreestyleFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(FreestyleFace),
+ "FreestyleFace",
+ 1,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 39: CD_MLOOPTANGENT */
- {sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[4]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 40: CD_TESSLOOPNORMAL */
- {sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, layerSwap_flnor, NULL},
+ {sizeof(short[4][3]), "", 0, nullptr, nullptr, nullptr, nullptr, layerSwap_flnor, nullptr},
/* 41: CD_CUSTOMLOOPNORMAL */
- {sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(short[2]), "vec2s", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 42: CD_SCULPT_FACE_SETS */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 43: CD_LOCATION */
- {sizeof(float[3]), "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 44: CD_RADIUS */
- {sizeof(float), "MFloatProperty", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float), "MFloatProperty", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 45: CD_HAIRCURVE */
- {sizeof(HairCurve), "HairCurve", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(HairCurve), "HairCurve", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 46: CD_HAIRMAPPING */
- {sizeof(HairMapping), "HairMapping", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(HairMapping), "HairMapping", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 47: CD_PROP_COLOR */
{sizeof(MPropCol),
"MPropCol",
1,
N_("Color"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_propcol,
- NULL,
+ nullptr,
layerDefault_propcol,
- NULL,
+ nullptr,
layerEqual_propcol,
layerMultiply_propcol,
layerInitMinMax_propcol,
layerAdd_propcol,
layerDoMinMax_propcol,
layerCopyValue_propcol,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_propcol},
/* 48: CD_PROP_FLOAT3 */
{sizeof(float[3]),
"vec3f",
1,
N_("Float3"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_propfloat3,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_propfloat3,
- NULL,
+ nullptr,
layerMultiply_propfloat3,
- NULL,
+ nullptr,
layerAdd_propfloat3},
/* 49: CD_PROP_FLOAT2 */
{sizeof(float[2]),
"vec2f",
1,
N_("Float2"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_propfloat2,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_propfloat2,
- NULL,
+ nullptr,
layerMultiply_propfloat2,
- NULL,
+ nullptr,
layerAdd_propfloat2},
/* 50: CD_PROP_BOOL */
{sizeof(bool),
"bool",
1,
N_("Boolean"),
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 51: CD_HAIRLENGTH */
- {sizeof(float), "float", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float), "float", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
@@ -1916,95 +1925,106 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
- .vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT,
- .emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT,
- .fmask = 0,
- .lmask = CD_MASK_MLOOP,
- .pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP,
+ /* vmask */ CD_MASK_MVERT | CD_MASK_BWEIGHT,
+ /* emask */ CD_MASK_MEDGE | CD_MASK_BWEIGHT,
+ /* fmask */ 0,
+ /* pmask */ CD_MASK_MPOLY | CD_MASK_FACEMAP,
+ /* lmask */ CD_MASK_MLOOP,
};
const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
- .vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
- .emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
- .fmask = 0,
- .lmask = CD_MASK_MLOOP,
- .pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX,
+ /* vmask */ CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
+ /* emask */ CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
+ /* fmask */ 0,
+ /* pmask */ CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX,
+ /* lmask */ CD_MASK_MLOOP,
};
const CustomData_MeshMasks CD_MASK_MESH = {
- .vmask = (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
- CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = 0,
- .lmask = (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
- CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
+ CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ /* emask */ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */ 0,
+ /* pmask */
+ (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
+ CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
const CustomData_MeshMasks CD_MASK_EDITMESH = {
- .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
- CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_PROP_ALL),
- .fmask = 0,
- .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
+ CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ /* emask */ (CD_MASK_PROP_ALL),
+ /* fmask */ 0,
+ /* pmask */ (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
- .vmask = (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
- CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
- CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
- .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
- CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
- .pmask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
+ CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
+ CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ /* emask */ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
+ /* pmask */
+ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
+ CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_PREVIEW_MLOOPCOL |
+ CD_MASK_ORIGSPACE_MLOOP | CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
};
const CustomData_MeshMasks CD_MASK_BMESH = {
- .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
- CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = 0,
- .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
+ CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL |
+ CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ /* emask */ (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */ 0,
+ /* pmask */
+ (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
/**
* cover values copied by #mesh_loops_to_tessdata
*/
const CustomData_MeshMasks CD_MASK_FACECORNERS = {
- .vmask = 0,
- .emask = 0,
- .fmask = (CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_PREVIEW_MCOL | CD_MASK_ORIGSPACE |
- CD_MASK_TESSLOOPNORMAL | CD_MASK_TANGENT),
- .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL |
- CD_MASK_ORIGSPACE_MLOOP | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT),
- .pmask = 0,
+ /* vmask */ 0,
+ /* emask */ 0,
+ /* fmask */
+ (CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_PREVIEW_MCOL | CD_MASK_ORIGSPACE |
+ CD_MASK_TESSLOOPNORMAL | CD_MASK_TANGENT),
+ /* pmask */ 0,
+ /* lmask */
+ (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
+ CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT),
};
const CustomData_MeshMasks CD_MASK_EVERYTHING = {
- .vmask = (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
- CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO |
- CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK |
- CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT |
- CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL |
- CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL |
- CD_MASK_PROP_ALL),
- .lmask = (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL |
- CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_MLOOPTANGENT | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
- CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
+ CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO |
+ CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX |
+ CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ /* emask */
+ (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | CD_MASK_CREASE |
+ CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */
+ (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL |
+ CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL |
+ CD_MASK_PROP_ALL),
+ /* pmask */
+ (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_FACEMAP |
+ CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | CD_MASK_MLOOPUV |
+ CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_MLOOPTANGENT |
+ CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_GRID_PAINT_MASK |
+ CD_MASK_PROP_ALL),
};
static const LayerTypeInfo *layerType_getInfo(int type)
{
if (type < 0 || type >= CD_NUMTYPES) {
- return NULL;
+ return nullptr;
}
return &LAYERTYPEINFO[type];
@@ -2013,7 +2033,7 @@ static const LayerTypeInfo *layerType_getInfo(int type)
static const char *layerType_getName(int type)
{
if (type < 0 || type >= CD_NUMTYPES) {
- return NULL;
+ return nullptr;
}
return LAYERTYPENAMES[type];
@@ -2147,7 +2167,7 @@ bool CustomData_merge(const struct CustomData *source,
data = layer->data;
break;
default:
- data = NULL;
+ data = nullptr;
break;
}
@@ -2169,7 +2189,7 @@ bool CustomData_merge(const struct CustomData *source,
newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY);
changed = true;
- if (layer->anonymous_id != NULL) {
+ if (layer->anonymous_id != nullptr) {
BKE_anonymous_attribute_id_increment_weak(layer->anonymous_id);
newlayer->anonymous_id = layer->anonymous_id;
}
@@ -2189,7 +2209,9 @@ void CustomData_realloc(CustomData *data, int totelem)
continue;
}
typeInfo = layerType_getInfo(layer->type);
- layer->data = MEM_reallocN(layer->data, (size_t)totelem * typeInfo->size);
+ /* Use calloc to avoid the need to manually initialize new data in layers.
+ * Useful for types like #MDeformVert which contain a pointer. */
+ layer->data = MEM_recallocN(layer->data, (size_t)totelem * typeInfo->size);
}
}
@@ -2202,7 +2224,7 @@ void CustomData_copy(const struct CustomData *source,
CustomData_reset(dest);
if (source->external) {
- dest->external = MEM_dupallocN(source->external);
+ dest->external = static_cast<CustomDataExternal *>(MEM_dupallocN(source->external));
}
CustomData_merge(source, dest, mask, alloctype, totelem);
@@ -2212,9 +2234,9 @@ static void customData_free_layer__internal(CustomDataLayer *layer, int totelem)
{
const LayerTypeInfo *typeInfo;
- if (layer->anonymous_id != NULL) {
+ if (layer->anonymous_id != nullptr) {
BKE_anonymous_attribute_id_decrement_weak(layer->anonymous_id);
- layer->anonymous_id = NULL;
+ layer->anonymous_id = nullptr;
}
if (!(layer->flag & CD_FLAG_NOFREE) && layer->data) {
typeInfo = layerType_getInfo(layer->type);
@@ -2233,7 +2255,7 @@ static void CustomData_external_free(CustomData *data)
{
if (data->external) {
MEM_freeN(data->external);
- data->external = NULL;
+ data->external = nullptr;
}
}
@@ -2499,8 +2521,8 @@ void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag)
static bool customData_resize(CustomData *data, int amount)
{
- CustomDataLayer *tmp = MEM_calloc_arrayN(
- (data->maxlayer + amount), sizeof(*tmp), "CustomData->layers");
+ CustomDataLayer *tmp = static_cast<CustomDataLayer *>(
+ MEM_calloc_arrayN((data->maxlayer + amount), sizeof(*tmp), __func__));
if (!tmp) {
return false;
}
@@ -2524,7 +2546,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
int flag = 0, index = data->totlayer;
- void *newlayerdata = NULL;
+ void *newlayerdata = nullptr;
/* Passing a layer-data to copy from with an alloctype that won't copy is
* most likely a bug */
@@ -2546,7 +2568,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
}
if (!newlayerdata) {
- return NULL;
+ return nullptr;
}
}
@@ -2574,7 +2596,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
if (newlayerdata != layerdata) {
MEM_freeN(newlayerdata);
}
- return NULL;
+ return nullptr;
}
}
@@ -2640,7 +2662,7 @@ void *CustomData_add_layer(
return layer->data;
}
- return NULL;
+ return nullptr;
}
void *CustomData_add_layer_named(CustomData *data,
@@ -2658,7 +2680,7 @@ void *CustomData_add_layer_named(CustomData *data,
return layer->data;
}
- return NULL;
+ return nullptr;
}
void *CustomData_add_layer_anonymous(struct CustomData *data,
@@ -2673,8 +2695,8 @@ void *CustomData_add_layer_anonymous(struct CustomData *data,
data, type, alloctype, layerdata, totelem, name);
CustomData_update_typemap(data);
- if (layer == NULL) {
- return NULL;
+ if (layer == nullptr) {
+ return nullptr;
}
BKE_anonymous_attribute_id_increment_weak(anonymous_id);
@@ -2787,7 +2809,7 @@ static void *customData_duplicate_referenced_layer_index(CustomData *data,
const int totelem)
{
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
CustomDataLayer *layer = &data->layers[layer_index];
@@ -2856,7 +2878,7 @@ void *CustomData_duplicate_referenced_layer_anonymous(CustomData *data,
}
}
BLI_assert_unreachable();
- return NULL;
+ return nullptr;
}
void CustomData_duplicate_referenced_layers(CustomData *data, int totelem)
@@ -2952,7 +2974,7 @@ void CustomData_copy_data_layer(const CustomData *source,
const size_t dst_offset = (size_t)dst_index * typeInfo->size;
if (!count || !src_data || !dst_data) {
- if (count && !(src_data == NULL && dst_data == NULL)) {
+ if (count && !(src_data == nullptr && dst_data == nullptr)) {
CLOG_WARN(&LOG,
"null data for %s type (%p --> %p), skipping",
layerType_getName(source->layers[src_layer_index].type),
@@ -3079,15 +3101,16 @@ void CustomData_interp(const CustomData *source,
/* Slow fallback in case we're interpolating a ridiculous number of elements. */
if (count > SOURCE_BUF_SIZE) {
- sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
+ sources = static_cast<const void **>(MEM_malloc_arrayN(count, sizeof(*sources), __func__));
}
/* If no weights are given, generate default ones to produce an average result. */
float default_weights_buf[SOURCE_BUF_SIZE];
- float *default_weights = NULL;
- if (weights == NULL) {
+ float *default_weights = nullptr;
+ if (weights == nullptr) {
default_weights = (count > SOURCE_BUF_SIZE) ?
- MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) :
+ static_cast<float *>(
+ MEM_mallocN(sizeof(*weights) * (size_t)count, __func__)) :
default_weights_buf;
copy_vn_fl(default_weights, count, 1.0f / count);
weights = default_weights;
@@ -3139,7 +3162,7 @@ void CustomData_interp(const CustomData *source,
if (count > SOURCE_BUF_SIZE) {
MEM_freeN((void *)sources);
}
- if (!ELEM(default_weights, NULL, default_weights_buf)) {
+ if (!ELEM(default_weights, nullptr, default_weights_buf)) {
MEM_freeN(default_weights);
}
}
@@ -3191,7 +3214,7 @@ void *CustomData_get(const CustomData *data, int index, int type)
/* get the layer index of the active layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
/* get the offset of the desired element */
@@ -3207,7 +3230,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n)
/* get the layer index of the first layer of type */
int layer_index = data->typemap[type];
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
const size_t offset = (size_t)index * layerType_getInfo(type)->size;
@@ -3219,7 +3242,7 @@ void *CustomData_get_layer(const CustomData *data, int type)
/* get the layer index of the active layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return data->layers[layer_index].data;
@@ -3230,7 +3253,7 @@ void *CustomData_get_layer_n(const CustomData *data, int type, int n)
/* get the layer index of the active layer of type */
int layer_index = CustomData_get_layer_index_n(data, type, n);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return data->layers[layer_index].data;
@@ -3240,7 +3263,7 @@ void *CustomData_get_layer_named(const struct CustomData *data, int type, const
{
int layer_index = CustomData_get_named_layer_index(data, type, name);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return data->layers[layer_index].data;
@@ -3286,7 +3309,7 @@ const char *CustomData_get_layer_name(const CustomData *data, int type, int n)
{
const int layer_index = CustomData_get_layer_index_n(data, type, n);
- return (layer_index == -1) ? NULL : data->layers[layer_index].name;
+ return (layer_index == -1) ? nullptr : data->layers[layer_index].name;
}
void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
@@ -3295,7 +3318,7 @@ void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
data->layers[layer_index].data = ptr;
@@ -3308,7 +3331,7 @@ void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, voi
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_layer_index_n(data, type, n);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
data->layers[layer_index].data = ptr;
@@ -3340,19 +3363,19 @@ void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop)
for (int i = 0; i < fdata->totlayer; i++) {
if (fdata->layers[i].type == CD_MTFACE) {
CustomData_add_layer_named(
- ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_MLOOPUV, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_MCOL) {
CustomData_add_layer_named(
- ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_MLOOPCOL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_MDISPS) {
CustomData_add_layer_named(
- ldata, CD_MDISPS, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_MDISPS, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) {
CustomData_add_layer_named(
- ldata, CD_NORMAL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_NORMAL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
}
}
@@ -3364,25 +3387,27 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *ldata, int total)
for (int i = 0; i < ldata->totlayer; i++) {
if (ldata->layers[i].type == CD_MLOOPUV) {
- CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ CustomData_add_layer_named(
+ fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
if (ldata->layers[i].type == CD_MLOOPCOL) {
- CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) {
CustomData_add_layer_named(
- fdata, CD_PREVIEW_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ fdata, CD_PREVIEW_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) {
CustomData_add_layer_named(
- fdata, CD_ORIGSPACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ fdata, CD_ORIGSPACE, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_NORMAL) {
CustomData_add_layer_named(
- fdata, CD_TESSLOOPNORMAL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ fdata, CD_TESSLOOPNORMAL, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_TANGENT) {
- CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ CustomData_add_layer_named(
+ fdata, CD_TANGENT, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
}
@@ -3495,7 +3520,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
int chunksize;
/* Dispose old pools before calling here to avoid leaks */
- BLI_assert(data->pool == NULL);
+ BLI_assert(data->pool == nullptr);
switch (htype) {
case BM_VERT:
@@ -3538,7 +3563,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
* the new allocation */
CustomData destold = *dest;
if (destold.layers) {
- destold.layers = MEM_dupallocN(destold.layers);
+ destold.layers = static_cast<CustomDataLayer *>(MEM_dupallocN(destold.layers));
}
if (CustomData_merge(source, dest, mask, alloctype, 0) == false) {
@@ -3574,7 +3599,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
break;
}
- dest->pool = NULL;
+ dest->pool = nullptr;
CustomData_bmesh_init_pool(dest, totelem, htype);
if (iter_type != BM_LOOPS_OF_FACE) {
@@ -3582,7 +3607,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
BMIter iter;
/* Ensure all current elements follow new customdata layout. */
BM_ITER_MESH (h, &iter, bm, iter_type) {
- void *tmp = NULL;
+ void *tmp = nullptr;
CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp);
CustomData_bmesh_free_block(&destold, &h->data);
h->data = tmp;
@@ -3597,7 +3622,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
/* Ensure all current elements follow new customdata layout. */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- void *tmp = NULL;
+ void *tmp = nullptr;
CustomData_bmesh_copy_data(&destold, dest, l->head.data, &tmp);
CustomData_bmesh_free_block(&destold, &l->head.data);
l->head.data = tmp;
@@ -3616,7 +3641,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
void CustomData_bmesh_free_block(CustomData *data, void **block)
{
- if (*block == NULL) {
+ if (*block == nullptr) {
return;
}
@@ -3635,12 +3660,12 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
BLI_mempool_free(data->pool, *block);
}
- *block = NULL;
+ *block = nullptr;
}
void CustomData_bmesh_free_block_data(CustomData *data, void *block)
{
- if (block == NULL) {
+ if (block == nullptr) {
return;
}
for (int i = 0; i < data->totlayer; i++) {
@@ -3667,7 +3692,7 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
*block = BLI_mempool_alloc(data->pool);
}
else {
- *block = NULL;
+ *block = nullptr;
}
}
@@ -3675,7 +3700,7 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
void *block,
const CustomDataMask mask_exclude)
{
- if (block == NULL) {
+ if (block == nullptr) {
return;
}
for (int i = 0; i < data->totlayer; i++) {
@@ -3707,7 +3732,7 @@ static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n
void CustomData_bmesh_set_default(CustomData *data, void **block)
{
- if (*block == NULL) {
+ if (*block == nullptr) {
CustomData_bmesh_alloc_block(data, block);
}
@@ -3726,7 +3751,7 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
* would cause too much duplicate code, so add a check instead. */
const bool no_mask = (mask_exclude == 0);
- if (*dest_block == NULL) {
+ if (*dest_block == nullptr) {
CustomData_bmesh_alloc_block(dest, dest_block);
if (*dest_block) {
memset(*dest_block, 0, dest->totsize);
@@ -3792,7 +3817,7 @@ void *CustomData_bmesh_get(const CustomData *data, void *block, int type)
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return POINTER_OFFSET(block, data->layers[layer_index].offset);
@@ -3803,7 +3828,7 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return POINTER_OFFSET(block, data->layers[layer_index + n].offset);
@@ -3812,7 +3837,7 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int
void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
{
if (n < 0 || n >= data->totlayer) {
- return NULL;
+ return nullptr;
}
return POINTER_OFFSET(block, data->layers[n].offset);
@@ -4028,7 +4053,7 @@ void CustomData_bmesh_interp_n(CustomData *data,
void *dst_block_ofs,
int n)
{
- BLI_assert(weights != NULL);
+ BLI_assert(weights != nullptr);
BLI_assert(count > 0);
CustomDataLayer *layer = &data->layers[n];
@@ -4053,15 +4078,15 @@ void CustomData_bmesh_interp(CustomData *data,
/* Slow fallback in case we're interpolating a ridiculous number of elements. */
if (count > SOURCE_BUF_SIZE) {
- sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
+ sources = (const void **)MEM_malloc_arrayN(count, sizeof(*sources), __func__);
}
/* If no weights are given, generate default ones to produce an average result. */
float default_weights_buf[SOURCE_BUF_SIZE];
- float *default_weights = NULL;
- if (weights == NULL) {
+ float *default_weights = nullptr;
+ if (weights == nullptr) {
default_weights = (count > SOURCE_BUF_SIZE) ?
- MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) :
+ (float *)MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) :
default_weights_buf;
copy_vn_fl(default_weights, count, 1.0f / count);
weights = default_weights;
@@ -4083,7 +4108,7 @@ void CustomData_bmesh_interp(CustomData *data,
if (count > SOURCE_BUF_SIZE) {
MEM_freeN((void *)sources);
}
- if (!ELEM(default_weights, NULL, default_weights_buf)) {
+ if (!ELEM(default_weights, nullptr, default_weights_buf)) {
MEM_freeN(default_weights);
}
}
@@ -4094,7 +4119,7 @@ void CustomData_to_bmesh_block(const CustomData *source,
void **dest_block,
bool use_default_init)
{
- if (*dest_block == NULL) {
+ if (*dest_block == nullptr) {
CustomData_bmesh_alloc_block(dest, dest_block);
}
@@ -4216,22 +4241,22 @@ void CustomData_blend_write_prepare(CustomData *data,
for (i = 0, j = 0; i < totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
/* Layers with this flag set are not written to file. */
- if ((layer->flag & CD_FLAG_NOCOPY) || layer->anonymous_id != NULL) {
+ if ((layer->flag & CD_FLAG_NOCOPY) || layer->anonymous_id != nullptr) {
data->totlayer--;
// CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name);
}
else {
if (UNLIKELY((size_t)j >= write_layers_size)) {
if (write_layers == write_layers_buff) {
- write_layers = MEM_malloc_arrayN(
+ write_layers = (CustomDataLayer *)MEM_malloc_arrayN(
(write_layers_size + chunk_size), sizeof(*write_layers), __func__);
if (write_layers_buff) {
memcpy(write_layers, write_layers_buff, sizeof(*write_layers) * write_layers_size);
}
}
else {
- write_layers = MEM_reallocN(write_layers,
- sizeof(*write_layers) * (write_layers_size + chunk_size));
+ write_layers = (CustomDataLayer *)MEM_reallocN(
+ write_layers, sizeof(*write_layers) * (write_layers_size + chunk_size));
}
write_layers_size += chunk_size;
}
@@ -4258,14 +4283,14 @@ const char *CustomData_layertype_name(int type)
bool CustomData_layertype_is_singleton(int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- return typeInfo->defaultname == NULL;
+ return typeInfo->defaultname == nullptr;
}
bool CustomData_layertype_is_dynamic(int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- return (typeInfo->free != NULL);
+ return (typeInfo->free != nullptr);
}
int CustomData_layertype_layers_max(const int type)
@@ -4273,10 +4298,10 @@ int CustomData_layertype_layers_max(const int type)
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
/* Same test as for singleton above. */
- if (typeInfo->defaultname == NULL) {
+ if (typeInfo->defaultname == nullptr) {
return 1;
}
- if (typeInfo->layers_max == NULL) {
+ if (typeInfo->layers_max == nullptr) {
return -1;
}
@@ -4306,13 +4331,15 @@ static bool cd_layer_find_dupe(CustomData *data, const char *name, int type, int
return false;
}
+struct CustomDataUniqueCheckData {
+ CustomData *data;
+ int type;
+ int index;
+};
+
static bool customdata_unique_check(void *arg, const char *name)
{
- struct {
- CustomData *data;
- int type;
- int index;
- } *data_arg = arg;
+ CustomDataUniqueCheckData *data_arg = static_cast<CustomDataUniqueCheckData *>(arg);
return cd_layer_find_dupe(data_arg->data, name, data_arg->type, data_arg->index);
}
@@ -4321,14 +4348,7 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
CustomDataLayer *nlayer = &data->layers[index];
const LayerTypeInfo *typeInfo = layerType_getInfo(nlayer->type);
- struct {
- CustomData *data;
- int type;
- int index;
- } data_arg;
- data_arg.data = data;
- data_arg.type = nlayer->type;
- data_arg.index = index;
+ CustomDataUniqueCheckData data_arg{data, nlayer->type, index};
if (!typeInfo->defaultname) {
return;
@@ -4341,7 +4361,7 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
}
BLI_uniquename_cb(
- customdata_unique_check, &data_arg, NULL, '.', nlayer->name, sizeof(nlayer->name));
+ customdata_unique_check, &data_arg, nullptr, '.', nlayer->name, sizeof(nlayer->name));
}
void CustomData_validate_layer_name(const CustomData *data,
@@ -4393,7 +4413,12 @@ bool CustomData_verify_versions(struct CustomData *data, int index)
/* 0 structnum is used in writing code to tag layer types that should not be written. */
else if (typeInfo->structnum == 0 &&
/* XXX Not sure why those three are exception, maybe that should be fixed? */
- !ELEM(layer->type, CD_PAINT_MASK, CD_FACEMAP, CD_MTEXPOLY, CD_SCULPT_FACE_SETS)) {
+ !ELEM(layer->type,
+ CD_PAINT_MASK,
+ CD_FACEMAP,
+ CD_MTEXPOLY,
+ CD_SCULPT_FACE_SETS,
+ CD_CREASE)) {
keeplayer = false;
CLOG_WARN(&LOG, ".blend file read: removing a data layer that should not have been written");
}
@@ -4413,7 +4438,7 @@ bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, cons
{
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
- if (typeInfo->validate != NULL) {
+ if (typeInfo->validate != nullptr) {
return typeInfo->validate(layer->data, totitems, do_fixes);
}
@@ -4665,7 +4690,7 @@ void CustomData_external_add(
}
if (!external) {
- external = MEM_callocN(sizeof(CustomDataExternal), "CustomDataExternal");
+ external = MEM_cnew<CustomDataExternal>(__func__);
data->external = external;
}
BLI_strncpy(external->filename, filename, sizeof(external->filename));
@@ -4764,7 +4789,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
const int count,
const float mix_factor)
{
- BLI_assert(weights != NULL);
+ BLI_assert(weights != nullptr);
BLI_assert(count > 0);
/* Fake interpolation, we actually copy highest weighted source to dest.
@@ -4779,8 +4804,8 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
size_t data_size;
const uint64_t data_flag = laymap->data_flag;
- cd_interp interp_cd = NULL;
- cd_copy copy_cd = NULL;
+ cd_interp interp_cd = nullptr;
+ cd_copy copy_cd = nullptr;
if (!sources) {
/* Not supported here, abort. */
@@ -4834,7 +4859,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
BLI_assert(best_src_idx >= 0);
if (interp_cd) {
- interp_cd(sources, weights, NULL, count, tmp_dst);
+ interp_cd(sources, weights, nullptr, count, tmp_dst);
}
else if (data_flag) {
copy_bit_flag(tmp_dst, sources[best_src_idx], data_size, data_flag);
@@ -4879,13 +4904,13 @@ void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLaye
const int count,
const float mix_factor)
{
- BLI_assert(weights != NULL);
+ BLI_assert(weights != nullptr);
BLI_assert(count > 0);
const int data_type = laymap->data_type;
const int mix_mode = laymap->mix_mode;
- SpaceTransform *space_transform = laymap->interp_data;
+ SpaceTransform *space_transform = static_cast<SpaceTransform *>(laymap->interp_data);
const LayerTypeInfo *type_info = layerType_getInfo(data_type);
cd_interp interp_cd = type_info->interp;
@@ -4899,7 +4924,7 @@ void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLaye
return;
}
- interp_cd(sources, weights, NULL, count, tmp_dst);
+ interp_cd(sources, weights, nullptr, count, tmp_dst);
if (space_transform) {
/* tmp_dst is in source space so far, bring it back in destination space. */
BLI_space_transform_invert_normal(space_transform, tmp_dst);
@@ -4922,18 +4947,19 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap,
size_t data_size;
size_t data_offset;
- cd_datatransfer_interp interp = NULL;
+ cd_datatransfer_interp interp = nullptr;
size_t tmp_buff_size = 32;
- const void **tmp_data_src = NULL;
+ const void **tmp_data_src = nullptr;
- /* NOTE: NULL data_src may happen and be valid (see vgroups...). */
+ /* NOTE: null data_src may happen and be valid (see vgroups...). */
if (!data_dst) {
return;
}
if (data_src) {
- tmp_data_src = MEM_malloc_arrayN(tmp_buff_size, sizeof(*tmp_data_src), __func__);
+ tmp_data_src = (const void **)MEM_malloc_arrayN(
+ tmp_buff_size, sizeof(*tmp_data_src), __func__);
}
if (data_type & CD_FAKE) {
@@ -4965,7 +4991,8 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap,
if (tmp_data_src) {
if (UNLIKELY(sources_num > tmp_buff_size)) {
tmp_buff_size = (size_t)sources_num;
- tmp_data_src = MEM_reallocN((void *)tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size);
+ tmp_data_src = (const void **)MEM_reallocN((void *)tmp_data_src,
+ sizeof(*tmp_data_src) * tmp_buff_size);
}
for (int j = 0; j < sources_num; j++) {
@@ -5037,28 +5064,33 @@ void CustomData_blend_write(BlendWriter *writer,
if (layer->type == CD_MDEFORMVERT) {
/* layer types that allocate own memory need special handling */
- BKE_defvert_blend_write(writer, count, layer->data);
+ BKE_defvert_blend_write(writer, count, static_cast<struct MDeformVert *>(layer->data));
}
else if (layer->type == CD_MDISPS) {
- write_mdisps(writer, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
+ write_mdisps(
+ writer, count, static_cast<MDisps *>(layer->data), layer->flag & CD_FLAG_EXTERNAL);
}
else if (layer->type == CD_PAINT_MASK) {
- const float *layer_data = layer->data;
+ const float *layer_data = static_cast<const float *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else if (layer->type == CD_SCULPT_FACE_SETS) {
- const float *layer_data = layer->data;
+ const float *layer_data = static_cast<const float *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else if (layer->type == CD_GRID_PAINT_MASK) {
- write_grid_paint_mask(writer, count, layer->data);
+ write_grid_paint_mask(writer, count, static_cast<GridPaintMask *>(layer->data));
}
else if (layer->type == CD_FACEMAP) {
- const int *layer_data = layer->data;
+ const int *layer_data = static_cast<const int *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else if (layer->type == CD_PROP_BOOL) {
- const bool *layer_data = layer->data;
+ const bool *layer_data = static_cast<const bool *>(layer->data);
+ BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
+ }
+ else if (layer->type == CD_CREASE) {
+ const float *layer_data = static_cast<const float *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else {
@@ -5131,7 +5163,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
/* Annoying workaround for bug T31079 loading legacy files with
* no polygons _but_ have stale custom-data. */
- if (UNLIKELY(count == 0 && data->layers == NULL && data->totlayer != 0)) {
+ if (UNLIKELY(count == 0 && data->layers == nullptr && data->totlayer != 0)) {
CustomData_reset(data);
return;
}
@@ -5150,7 +5182,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
if (CustomData_verify_versions(data, i)) {
BLO_read_data_address(reader, &layer->data);
- if (layer->data == NULL && count > 0 && layer->type == CD_PROP_BOOL) {
+ if (layer->data == nullptr && count > 0 && layer->type == CD_PROP_BOOL) {
/* Usually this should never happen, except when a custom data layer has not been written
* to a file correctly. */
CLOG_WARN(&LOG, "Reallocating custom data layer that was not saved correctly.");
@@ -5161,10 +5193,11 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
}
}
if (layer->type == CD_MDISPS) {
- blend_read_mdisps(reader, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
+ blend_read_mdisps(
+ reader, count, static_cast<MDisps *>(layer->data), layer->flag & CD_FLAG_EXTERNAL);
}
else if (layer->type == CD_GRID_PAINT_MASK) {
- blend_read_paint_mask(reader, count, layer->data);
+ blend_read_paint_mask(reader, count, static_cast<GridPaintMask *>(layer->data));
}
i++;
}
@@ -5172,3 +5205,33 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
CustomData_update_typemap(data);
}
+
+#ifndef NDEBUG
+
+void CustomData_debug_info_from_layers(const CustomData *data, const char *indent, DynStr *dynstr)
+{
+ for (int type = 0; type < CD_NUMTYPES; type++) {
+ if (CustomData_has_layer(data, type)) {
+ /* NOTE: doesn't account for multiple layers. */
+ const char *name = CustomData_layertype_name(type);
+ const int size = CustomData_sizeof(type);
+ const void *pt = CustomData_get_layer(data, type);
+ const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(type, &structname, &structnum);
+ BLI_dynstr_appendf(
+ dynstr,
+ "%sdict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ indent,
+ name,
+ structname,
+ type,
+ (const void *)pt,
+ size,
+ pt_size);
+ }
+ }
+}
+
+#endif /* NDEBUG */
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index f036f1ced87..0ad7efb6347 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -273,7 +273,6 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
const int num_polys_dst = me_dst->totpoly;
MLoop *loops_dst = me_dst->mloop;
const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
CustomData *ldata_dst = &me_dst->ldata;
const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
@@ -284,26 +283,9 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
BLI_assert(CustomData_get_layer(&me_src->pdata, CD_NORMAL) != NULL);
(void)me_src;
- float(*poly_nors_dst)[3];
float(*loop_nors_dst)[3];
short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- const bool do_poly_nors_dst = (poly_nors_dst == NULL);
- if (do_poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst || do_poly_nors_dst) {
- BKE_mesh_calc_normals_poly(verts_dst,
- num_verts_dst,
- loops_dst,
- num_loops_dst,
- polys_dst,
- num_polys_dst,
- poly_nors_dst);
- }
/* Cache loop nors into a temp CDLayer. */
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
const bool do_loop_nors_dst = (loop_nors_dst == NULL);
@@ -313,6 +295,7 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
}
if (dirty_nors_dst || do_loop_nors_dst) {
BKE_mesh_normals_loop_split(verts_dst,
+ BKE_mesh_vertex_normals_ensure(me_dst),
num_verts_dst,
edges_dst,
num_edges_dst,
@@ -320,7 +303,7 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
loop_nors_dst,
num_loops_dst,
polys_dst,
- (const float(*)[3])poly_nors_dst,
+ BKE_mesh_poly_normals_ensure(me_dst),
num_polys_dst,
use_split_nors_dst,
split_angle_dst,
@@ -368,6 +351,7 @@ static void data_transfer_dtdata_type_postprocess(Object *UNUSED(ob_src),
/* Note loop_nors_dst contains our custom normals as transferred from source... */
BKE_mesh_normals_loop_custom_set(verts_dst,
+ BKE_mesh_vertex_normals_ensure(me_dst),
num_verts_dst,
edges_dst,
num_edges_dst,
@@ -1651,7 +1635,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
const int num_polys_dst = me_dst->totpoly;
MLoop *loops_dst = me_dst->mloop;
const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
CustomData *ldata_dst = &me_dst->ldata;
MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
@@ -1685,6 +1668,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
space_transform,
max_distance,
ray_radius,
+ me_dst,
verts_dst,
num_verts_dst,
edges_dst,
@@ -1694,7 +1678,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
polys_dst,
num_polys_dst,
ldata_dst,
- pdata_dst,
(me_dst->flag & ME_AUTOSMOOTH) != 0,
me_dst->smoothresh,
dirty_nors_dst,
@@ -1745,7 +1728,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
const int num_polys_dst = me_dst->totpoly;
MLoop *loops_dst = me_dst->mloop;
const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
if (!geom_map_init[PDATA]) {
const int num_polys_src = me_src->totpoly;
@@ -1776,14 +1758,11 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
space_transform,
max_distance,
ray_radius,
+ me_dst,
verts_dst,
- num_verts_dst,
loops_dst,
- num_loops_dst,
polys_dst,
num_polys_dst,
- pdata_dst,
- dirty_nors_dst,
me_src,
&geom_map[PDATA]);
geom_map_init[PDATA] = true;
diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h
index e40b4946f52..b5b3db31fbf 100644
--- a/source/blender/blenkernel/intern/data_transfer_intern.h
+++ b/source/blender/blenkernel/intern/data_transfer_intern.h
@@ -25,47 +25,48 @@
#include "BKE_customdata.h" /* For cd_datatransfer_interp */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct CustomData;
struct CustomDataTransferLayerMap;
struct ListBase;
-float data_transfer_interp_float_do(const int mix_mode,
- const float val_dst,
- const float val_src,
- const float mix_factor);
+float data_transfer_interp_float_do(int mix_mode, float val_dst, float val_src, float mix_factor);
void data_transfer_layersmapping_add_item(struct ListBase *r_map,
- const int data_type,
- const int mix_mode,
- const float mix_factor,
+ int data_type,
+ int mix_mode,
+ float mix_factor,
const float *mix_weights,
const void *data_src,
void *data_dst,
- const int data_src_n,
- const int data_dst_n,
- const size_t elem_size,
- const size_t data_size,
- const size_t data_offset,
- const uint64_t data_flag,
+ int data_src_n,
+ int data_dst_n,
+ size_t elem_size,
+ size_t data_size,
+ size_t data_offset,
+ uint64_t data_flag,
cd_datatransfer_interp interp,
void *interp_data);
/* Type-specific. */
bool data_transfer_layersmapping_vgroups(struct ListBase *r_map,
- const int mix_mode,
- const float mix_factor,
+ int mix_mode,
+ float mix_factor,
const float *mix_weights,
- const int num_elem_dst,
- const bool use_create,
- const bool use_delete,
+ int num_elem_dst,
+ bool use_create,
+ bool use_delete,
struct Object *ob_src,
struct Object *ob_dst,
struct CustomData *cd_src,
struct CustomData *cd_dst,
- const bool use_dupref_dst,
- const int fromlayers,
- const int tolayers);
+ bool use_dupref_dst,
+ int fromlayers,
+ int tolayers);
/* Defined in customdata.c */
@@ -76,5 +77,9 @@ void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLaye
void *data_dst,
const void **sources,
const float *weights,
- const int count,
- const float mix_factor);
+ int count,
+ float mix_factor);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index edf043de63f..78177095a77 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -316,7 +316,7 @@ static void curve_to_displist(const Curve *cu,
* and resolution > 1. */
const bool use_cyclic_sample = is_cyclic && (samples_len != 2);
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
/* Add one to the length because of 'BKE_curve_forward_diff_bezier'. */
dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * (samples_len + 1), __func__);
BLI_addtail(r_dispbase, dl);
@@ -371,7 +371,7 @@ static void curve_to_displist(const Curve *cu,
}
else if (nu->type == CU_NURBS) {
const int len = (resolution * SEGMENTSU(nu));
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
dl->parts = 1;
@@ -384,7 +384,7 @@ static void curve_to_displist(const Curve *cu,
}
else if (nu->type == CU_POLY) {
const int len = nu->pntsu;
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
dl->parts = 1;
@@ -475,7 +475,7 @@ void BKE_displist_fill(const ListBase *dispbase,
const int triangles_len = BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal_proj);
if (totvert != 0 && triangles_len != 0) {
- DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dlnew = MEM_cnew<DispList>(__func__);
dlnew->type = DL_INDEX3;
dlnew->flag = (dl_flag_accum & (DL_BACK_CURVE | DL_FRONT_CURVE));
dlnew->rt = (dl_rt_accum & CU_SMOOTH);
@@ -530,7 +530,7 @@ static void bevels_to_filledpoly(const Curve *cu, ListBase *dispbase)
if (dl->type == DL_SURF) {
if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U) == 0) {
if ((cu->flag & CU_BACK) && (dl->flag & DL_BACK_CURVE)) {
- DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dlnew = MEM_cnew<DispList>(__func__);
BLI_addtail(&front, dlnew);
dlnew->verts = (float *)MEM_mallocN(sizeof(float[3]) * dl->parts, __func__);
dlnew->nr = dl->parts;
@@ -549,7 +549,7 @@ static void bevels_to_filledpoly(const Curve *cu, ListBase *dispbase)
}
}
if ((cu->flag & CU_FRONT) && (dl->flag & DL_FRONT_CURVE)) {
- DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dlnew = MEM_cnew<DispList>(__func__);
BLI_addtail(&back, dlnew);
dlnew->verts = (float *)MEM_mallocN(sizeof(float[3]) * dl->parts, __func__);
dlnew->nr = dl->parts;
@@ -665,7 +665,7 @@ void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob)
BKE_displist_free(&(ob->runtime.curve_cache->disp));
}
else {
- ob->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache), __func__);
+ ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__);
}
BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp);
@@ -904,7 +904,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
int totvert;
float(*vertex_coords)[3] = BKE_mesh_vert_coords_alloc(mesh, &totvert);
if (mti->dependsOnNormals != nullptr && mti->dependsOnNormals(md)) {
- BKE_mesh_ensure_normals(mesh);
+ BKE_mesh_vertex_normals_ensure(mesh);
}
mti->deformVerts(md, &mectx_deform, mesh, vertex_coords, totvert);
BKE_mesh_vert_coords_apply(mesh, vertex_coords);
@@ -912,7 +912,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
}
else {
if (mti->dependsOnNormals != nullptr && mti->dependsOnNormals(md)) {
- BKE_mesh_ensure_normals(mesh);
+ BKE_mesh_vertex_normals_ensure(mesh);
}
Mesh *output_mesh = mti->modifyMesh(md, &mectx_apply, mesh);
if (mesh != output_mesh) {
@@ -924,7 +924,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
if (geometry_set.has_mesh()) {
Mesh *final_mesh = geometry_set.get_mesh_for_write();
- BKE_mesh_calc_normals(final_mesh);
+ BKE_mesh_ensure_normals_for_display(final_mesh);
BLI_strncpy(final_mesh->id.name, cu->id.name, sizeof(final_mesh->id.name));
*((short *)final_mesh->id.name) = ID_ME;
@@ -996,7 +996,7 @@ static void evaluate_surface_object(Depsgraph *depsgraph,
if (nu->pntsv == 1) {
const int len = SEGMENTSU(nu) * resolu;
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
@@ -1019,7 +1019,7 @@ static void evaluate_surface_object(Depsgraph *depsgraph,
else {
const int len = (nu->pntsu * resolu) * (nu->pntsv * resolv);
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
@@ -1122,7 +1122,7 @@ static void fillBevelCap(const Nurb *nu,
const float *prev_fp,
ListBase *dispbase)
{
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * dlb->nr, __func__);
memcpy(dl->verts, prev_fp, sizeof(float[3]) * dlb->nr);
@@ -1321,7 +1321,7 @@ static GeometrySet evaluate_curve_type_object(Depsgraph *depsgraph,
/* exception handling; curve without bevel or extrude, with width correction */
if (BLI_listbase_is_empty(&dlbev)) {
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), "makeDispListbev");
+ DispList *dl = MEM_cnew<DispList>("makeDispListbev");
dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * bl->nr, "dlverts");
BLI_addtail(r_dispbase, dl);
@@ -1371,7 +1371,7 @@ static GeometrySet evaluate_curve_type_object(Depsgraph *depsgraph,
LISTBASE_FOREACH (DispList *, dlb, &dlbev) {
/* for each part of the bevel use a separate displblock */
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = data = (float *)MEM_mallocN(sizeof(float[3]) * dlb->nr * steps, __func__);
BLI_addtail(r_dispbase, dl);
@@ -1495,7 +1495,7 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
BKE_object_free_derived_caches(ob);
cow_curve.curve_eval = nullptr;
- ob->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache), __func__);
+ ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__);
ListBase *dispbase = &ob->runtime.curve_cache->disp;
if (ob->type == OB_SURF) {
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index ce92a34de47..64e0427a810 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -1789,6 +1789,7 @@ typedef struct DynamicPaintModifierApplyData {
Object *ob;
MVert *mvert;
+ const float (*vert_normals)[3];
const MLoop *mloop;
const MPoly *mpoly;
@@ -1806,14 +1807,11 @@ static void dynamic_paint_apply_surface_displace_cb(void *__restrict userdata,
const DynamicPaintSurface *surface = data->surface;
MVert *mvert = data->mvert;
- float normal[3];
const float *value = (float *)surface->data->type_data;
const float val = value[i] * surface->disp_factor;
- normal_short_to_float_v3(normal, mvert[i].no);
-
/* same as 'mvert[i].co[0] -= normal[0] * val' etc. */
- madd_v3_v3fl(mvert[i].co, normal, -val);
+ madd_v3_v3fl(mvert[i].co, data->vert_normals[i], -val);
}
/* apply displacing vertex surface to the derived mesh */
@@ -1832,6 +1830,7 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh
DynamicPaintModifierApplyData data = {
.surface = surface,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(result),
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -1898,10 +1897,8 @@ static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata,
PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
MVert *mvert = data->mvert;
- float normal[3];
- normal_short_to_float_v3(normal, mvert[i].no);
- madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
+ madd_v3_v3fl(mvert[i].co, data->vert_normals[i], wPoint[i].height);
}
/*
@@ -2030,6 +2027,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
DynamicPaintModifierApplyData data = {
.surface = surface,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(result),
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -4287,6 +4285,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
mesh = BKE_mesh_copy_for_eval(brush_mesh, false);
mvert = mesh->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
mloop = mesh->mloop;
numOfVerts = mesh->totvert;
@@ -4301,7 +4300,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
/* for proximity project calculate average normal */
if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
float nor[3];
- normal_short_to_float_v3(nor, mvert[ii].no);
+ copy_v3_v3(nor, vert_normals[ii]);
mul_mat3_m4_v3(brushOb->obmat, nor);
normalize_v3(nor);
@@ -5909,6 +5908,7 @@ typedef struct DynamicPaintGenerateBakeData {
Object *ob;
const MVert *mvert;
+ const float (*vert_normals)[3];
const Vec3f *canvas_verts;
const bool do_velocity_data;
@@ -5928,7 +5928,6 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
Object *ob = data->ob;
- const MVert *mvert = data->mvert;
const Vec3f *canvas_verts = data->canvas_verts;
const bool do_velocity_data = data->do_velocity_data;
@@ -5962,9 +5961,9 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
}
/* Calculate current pixel surface normal */
- normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
- normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
- normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
+ copy_v3_v3(n1, data->vert_normals[tPoint->v1]);
+ copy_v3_v3(n2, data->vert_normals[tPoint->v2]);
+ copy_v3_v3(n3, data->vert_normals[tPoint->v3]);
interp_v3_v3v3v3(
temp_nor, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
@@ -6006,7 +6005,7 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
}
/* normal */
- normal_short_to_float_v3(temp_nor, mvert[index].no);
+ copy_v3_v3(temp_nor, data->vert_normals[index]);
if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
/* Prepare surface normal directional scale to easily convert
* brush intersection amount between global and local space */
@@ -6145,6 +6144,7 @@ static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface,
.surface = surface,
.ob = ob,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(mesh),
.canvas_verts = canvas_verts,
.do_velocity_data = do_velocity_data,
.new_bdata = new_bdata,
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 805d3cdb5e3..0774a1a3d88 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -39,6 +39,8 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_object.h"
+#include "DEG_depsgraph_query.h"
+
BMEditMesh *BKE_editmesh_create(BMesh *bm)
{
BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__);
@@ -51,9 +53,6 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__);
*em_copy = *em;
- em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
- em_copy->bb_cage = NULL;
-
em_copy->bm = BM_mesh_copy(em->bm);
/* The tessellation is NOT calculated on the copy here,
@@ -194,22 +193,8 @@ void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em,
});
}
-void BKE_editmesh_free_derived_caches(BMEditMesh *em)
-{
- if (em->mesh_eval_cage) {
- BKE_id_free(NULL, em->mesh_eval_cage);
- }
- if (em->mesh_eval_final && em->mesh_eval_final != em->mesh_eval_cage) {
- BKE_id_free(NULL, em->mesh_eval_final);
- }
- em->mesh_eval_cage = em->mesh_eval_final = NULL;
-
- MEM_SAFE_FREE(em->bb_cage);
-}
-
void BKE_editmesh_free_data(BMEditMesh *em)
{
- BKE_editmesh_free_derived_caches(em);
if (em->looptris) {
MEM_freeN(em->looptris);
@@ -229,8 +214,7 @@ struct CageUserData {
static void cage_mapped_verts_callback(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
struct CageUserData *data = userData;
@@ -284,13 +268,15 @@ const float (*BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph
*r_is_alloc = false;
Mesh *me = ob->data;
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval);
if ((me->runtime.edit_data != NULL) && (me->runtime.edit_data->vertexCos != NULL)) {
/* Deformed, and we have deformed coords already. */
coords = me->runtime.edit_data->vertexCos;
}
- else if ((em->mesh_eval_final != NULL) &&
- (em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
+ else if ((editmesh_eval_final != NULL) &&
+ (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
/* If this is an edit-mesh type, leave NULL as we can use the vertex coords. */
}
else {
@@ -335,18 +321,18 @@ void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me)
}
}
-BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em)
+BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *UNUSED(em))
{
- if (em->bb_cage == NULL) {
+ if (object->runtime.editmesh_bb_cage == NULL) {
float min[3], max[3];
INIT_MINMAX(min, max);
- if (em->mesh_eval_cage) {
- BKE_mesh_wrapper_minmax(em->mesh_eval_cage, min, max);
+ if (object->runtime.editmesh_eval_cage) {
+ BKE_mesh_wrapper_minmax(object->runtime.editmesh_eval_cage, min, max);
}
- em->bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");
- BKE_boundbox_init_from_minmax(em->bb_cage, min, max);
+ object->runtime.editmesh_bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");
+ BKE_boundbox_init_from_minmax(object->runtime.editmesh_bb_cage, min, max);
}
- return em->bb_cage;
+ return object->runtime.editmesh_bb_cage;
}
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 8229228976c..bbf9e9edfd2 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -59,6 +59,7 @@
#include "BKE_fluid.h"
#include "BKE_global.h"
#include "BKE_layer.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -715,9 +716,10 @@ bool get_effector_data(EffectorCache *eff,
else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) {
/* TODO: hair and points object support */
const Mesh *me_eval = BKE_object_get_evaluated_mesh(eff->ob);
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me_eval);
if (me_eval != NULL) {
copy_v3_v3(efd->loc, me_eval->mvert[*efd->index].co);
- normal_short_to_float_v3(efd->nor, me_eval->mvert[*efd->index].no);
+ copy_v3_v3(efd->nor, vert_normals[*efd->index]);
mul_m4_v3(eff->ob->obmat, efd->loc);
mul_mat3_m4_v3(eff->ob->obmat, efd->nor);
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 5bbfc0913a1..f7a547543af 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -412,7 +412,7 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
char *path = NULL;
if (!adt && C) {
- path = BKE_animdata_driver_path_hack(C, &tptr, prop, NULL);
+ path = RNA_path_from_ID_to_property(&tptr, prop);
adt = BKE_animdata_from_id(tptr.owner_id);
step--;
}
@@ -463,7 +463,7 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
}
if (step) {
- char *tpath = BKE_animdata_driver_path_hack(C, &tptr, prop, path);
+ char *tpath = path ? path : RNA_path_from_ID_to_property(&tptr, prop);
if (tpath && tpath != path) {
MEM_freeN(path);
path = tpath;
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
index 5496519e53b..ce30f80ba65 100644
--- a/source/blender/blenkernel/intern/fcurve_driver.c
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -29,6 +29,7 @@
#include "BLI_alloca.h"
#include "BLI_expr_pylike_eval.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
@@ -864,6 +865,12 @@ void driver_variable_name_validate(DriverVar *dvar)
}
}
+void driver_variable_unique_name(DriverVar *dvar)
+{
+ ListBase variables = BLI_listbase_from_link((Link *)dvar);
+ BLI_uniquename(&variables, dvar, dvar->name, '_', offsetof(DriverVar, name), sizeof(dvar->name));
+}
+
DriverVar *driver_add_new_variable(ChannelDriver *driver)
{
DriverVar *dvar;
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 39122b33683..0c9e352da12 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -1030,7 +1030,6 @@ static void obstacles_from_mesh(Object *coll_ob,
CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
}
- BKE_mesh_ensure_normals(me);
mvert = me->mvert;
mloop = me->mloop;
looptri = BKE_mesh_runtime_looptri_ensure(me);
@@ -1053,9 +1052,11 @@ static void obstacles_from_mesh(Object *coll_ob,
}
}
- /* Transform mesh vertices to domain grid space for fast lookups */
+ /* Transform mesh vertices to domain grid space for fast lookups.
+ * This is valid because the mesh is copied above. */
+ BKE_mesh_vertex_normals_ensure(me);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(me);
for (i = 0; i < numverts; i++) {
- float n[3];
float co[3];
/* Vertex position. */
@@ -1063,11 +1064,9 @@ static void obstacles_from_mesh(Object *coll_ob,
manta_pos_to_cell(fds, mvert[i].co);
/* Vertex normal. */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(coll_ob->obmat, n);
- mul_mat3_m4_v3(fds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
+ mul_mat3_m4_v3(coll_ob->obmat, vert_normals[i]);
+ mul_mat3_m4_v3(fds->imat, vert_normals[i]);
+ normalize_v3(vert_normals[i]);
/* Vertex velocity. */
add_v3fl_v3fl_v3i(co, mvert[i].co, fds->shift);
@@ -1826,6 +1825,7 @@ static void update_distances(int index,
static void sample_mesh(FluidFlowSettings *ffs,
const MVert *mvert,
+ const float (*vert_normals)[3],
const MLoop *mloop,
const MLoopTri *mlooptri,
const MLoopUV *mloopuv,
@@ -1906,7 +1906,7 @@ static void sample_mesh(FluidFlowSettings *ffs,
tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
float weights[3];
int v1, v2, v3, f_index = nearest.index;
- float n1[3], n2[3], n3[3], hit_normal[3];
+ float hit_normal[3];
/* Calculate barycentric weights for nearest point. */
v1 = mloop[mlooptri[f_index].tri[0]].v;
@@ -1969,10 +1969,8 @@ static void sample_mesh(FluidFlowSettings *ffs,
/* Apply normal directional velocity. */
if (ffs->vel_normal) {
/* Interpolate vertex normal vectors to get nearest point normal. */
- normal_short_to_float_v3(n1, mvert[v1].no);
- normal_short_to_float_v3(n2, mvert[v2].no);
- normal_short_to_float_v3(n3, mvert[v3].no);
- interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
+ interp_v3_v3v3v3(
+ hit_normal, vert_normals[v1], vert_normals[v2], vert_normals[v3], weights);
normalize_v3(hit_normal);
/* Apply normal directional velocity. */
@@ -2022,6 +2020,7 @@ typedef struct EmitFromDMData {
FluidFlowSettings *ffs;
const MVert *mvert;
+ const float (*vert_normals)[3];
const MLoop *mloop;
const MLoopTri *mlooptri;
const MLoopUV *mloopuv;
@@ -2056,6 +2055,7 @@ static void emit_from_mesh_task_cb(void *__restrict userdata,
(data->ffs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW)) {
sample_mesh(data->ffs,
data->mvert,
+ data->vert_normals,
data->mloop,
data->mlooptri,
data->mloopuv,
@@ -2117,7 +2117,6 @@ static void emit_from_mesh(
CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
}
- BKE_mesh_ensure_normals(me);
mvert = me->mvert;
mloop = me->mloop;
mlooptri = BKE_mesh_runtime_looptri_ensure(me);
@@ -2140,20 +2139,19 @@ static void emit_from_mesh(
}
}
- /* Transform mesh vertices to domain grid space for fast lookups */
+ /* Transform mesh vertices to domain grid space for fast lookups.
+ * This is valid because the mesh is copied above. */
+ BKE_mesh_vertex_normals_ensure(me);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(me);
for (i = 0; i < numverts; i++) {
- float n[3];
-
/* Vertex position. */
mul_m4_v3(flow_ob->obmat, mvert[i].co);
manta_pos_to_cell(fds, mvert[i].co);
/* Vertex normal. */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(flow_ob->obmat, n);
- mul_mat3_m4_v3(fds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
+ mul_mat3_m4_v3(flow_ob->obmat, vert_normals[i]);
+ mul_mat3_m4_v3(fds->imat, vert_normals[i]);
+ normalize_v3(vert_normals[i]);
/* Vertex velocity. */
if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
@@ -2193,6 +2191,7 @@ static void emit_from_mesh(
.fds = fds,
.ffs = ffs,
.mvert = mvert,
+ .vert_normals = vert_normals,
.mloop = mloop,
.mlooptri = mlooptri,
.mloopuv = mloopuv,
@@ -3265,8 +3264,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
MVert *mverts;
MPoly *mpolys;
MLoop *mloops;
- short *normals, *no_s;
- float no[3];
float min[3];
float max[3];
float size[3];
@@ -3285,26 +3282,23 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
const char mp_flag = mp_example.flag;
int i;
- int num_verts, num_normals, num_faces;
+ int num_verts, num_faces;
if (!fds->fluid) {
return NULL;
}
num_verts = manta_liquid_get_num_verts(fds->fluid);
- num_normals = manta_liquid_get_num_normals(fds->fluid);
num_faces = manta_liquid_get_num_triangles(fds->fluid);
# ifdef DEBUG_PRINT
/* Debugging: Print number of vertices, normals, and faces. */
- printf("num_verts: %d, num_normals: %d, num_faces: %d\n", num_verts, num_normals, num_faces);
+ printf("num_verts: %d, num_faces: %d\n", num_verts, num_faces);
# endif
if (!num_verts || !num_faces) {
return NULL;
}
- /* Normals are per vertex, so these must match. */
- BLI_assert(num_verts == num_normals);
me = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 3, num_faces);
if (!me) {
@@ -3334,9 +3328,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
co_offset[1] = (fds->p0[1] + fds->p1[1]) / 2.0f;
co_offset[2] = (fds->p0[2] + fds->p1[2]) / 2.0f;
- /* Normals. */
- normals = MEM_callocN(sizeof(short[3]) * num_normals, "Fluidmesh_tmp_normals");
-
/* Velocities. */
/* If needed, vertex velocities will be read too. */
bool use_speedvectors = fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS;
@@ -3350,7 +3341,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
}
/* Loop for vertices and normals. */
- for (i = 0, no_s = normals; i < num_verts && i < num_normals; i++, mverts++, no_s += 3) {
+ for (i = 0; i < num_verts; i++, mverts++) {
/* Vertices (data is normalized cube around domain origin). */
mverts->co[0] = manta_liquid_get_vertex_x_at(fds->fluid, i);
@@ -3376,12 +3367,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
mverts->co[2]);
# endif
- /* Normals (data is normalized cube around domain origin). */
- no[0] = manta_liquid_get_normal_x_at(fds->fluid, i);
- no[1] = manta_liquid_get_normal_y_at(fds->fluid, i);
- no[2] = manta_liquid_get_normal_z_at(fds->fluid, i);
-
- normal_float_to_short_v3(no_s, no);
# ifdef DEBUG_PRINT
/* Debugging: Print coordinates of normals. */
printf("no_s[0]: %d, no_s[1]: %d, no_s[2]: %d\n", no_s[0], no_s[1], no_s[2]);
@@ -3425,11 +3410,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
# endif
}
- BKE_mesh_ensure_normals(me);
BKE_mesh_calc_edges(me, false, false);
- BKE_mesh_vert_normals_apply(me, (short(*)[3])normals);
-
- MEM_freeN(normals);
return me;
}
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index 1e24b29038d..16edbc36f9c 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_task.hh"
+
#include "DNA_ID_enums.h"
#include "DNA_curve_types.h"
@@ -389,6 +391,98 @@ static const CurveEval *get_curve_from_component_for_read(const GeometryComponen
namespace blender::bke {
/* -------------------------------------------------------------------- */
+/** \name Curve Normals Access
+ * \{ */
+
+static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals)
+{
+ Span<int> offsets = spline.control_point_offsets();
+ Span<float3> evaluated_normals = spline.evaluated_normals();
+ for (const int i : IndexRange(spline.size())) {
+ normals[i] = evaluated_normals[offsets[i]];
+ }
+}
+
+static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals)
+{
+ normals.copy_from(spline.evaluated_normals());
+}
+
+/**
+ * Because NURBS control points are not necessarily on the path, the normal at the control points
+ * is not well defined, so create a temporary poly spline to find the normals. This requires extra
+ * copying currently, but may be more efficient in the future if attributes have some form of CoW.
+ */
+static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals)
+{
+ PolySpline poly_spline;
+ poly_spline.resize(spline.size());
+ poly_spline.positions().copy_from(spline.positions());
+ poly_spline.tilts().copy_from(spline.tilts());
+ normals.copy_from(poly_spline.evaluated_normals());
+}
+
+static Array<float3> curve_normal_point_domain(const CurveEval &curve)
+{
+ Span<SplinePtr> splines = curve.splines();
+ Array<int> offsets = curve.control_point_offsets();
+ const int total_size = offsets.last();
+ Array<float3> normals(total_size);
+
+ threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ const Spline &spline = *splines[i];
+ MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())};
+ switch (splines[i]->type()) {
+ case Spline::Type::Bezier:
+ calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals);
+ break;
+ case Spline::Type::Poly:
+ calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals);
+ break;
+ case Spline::Type::NURBS:
+ calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals);
+ break;
+ }
+ }
+ });
+ return normals;
+}
+
+VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain)
+{
+ const CurveEval *curve = component.get_for_read();
+ if (curve == nullptr) {
+ return nullptr;
+ }
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ const Span<SplinePtr> splines = curve->splines();
+
+ /* Use a reference to evaluated normals if possible to avoid an allocation and a copy.
+ * This is only possible when there is only one poly spline. */
+ if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) {
+ const PolySpline &spline = static_cast<PolySpline &>(*splines.first());
+ return VArray<float3>::ForSpan(spline.evaluated_normals());
+ }
+
+ Array<float3> normals = curve_normal_point_domain(*curve);
+ return VArray<float3>::ForContainer(std::move(normals));
+ }
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ Array<float3> point_normals = curve_normal_point_domain(*curve);
+ VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals));
+ return component.attribute_try_adapt_domain<float3>(
+ std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ }
+
+ return nullptr;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Builtin Spline Attributes
*
* Attributes with a value for every spline, stored contiguously or in every spline separately.
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 62d66f13e9f..b411c793298 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -17,6 +17,7 @@
#include <mutex>
#include "BLI_float4x4.hh"
+#include "BLI_index_mask.hh"
#include "BLI_map.hh"
#include "BLI_rand.hh"
#include "BLI_set.hh"
@@ -26,12 +27,17 @@
#include "DNA_collection_types.h"
+#include "BKE_attribute_access.hh"
+#include "BKE_attribute_math.hh"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
#include "attribute_access_intern.hh"
+#include "FN_cpp_type_make.hh"
+
using blender::float4x4;
+using blender::IndexMask;
using blender::Map;
using blender::MutableSpan;
using blender::Set;
@@ -39,6 +45,8 @@ using blender::Span;
using blender::VectorSet;
using blender::fn::GSpan;
+MAKE_CPP_TYPE(InstanceReference, InstanceReference, CPPTypeFlags::None)
+
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
* \{ */
@@ -128,6 +136,62 @@ blender::Span<InstanceReference> InstancesComponent::references() const
return references_;
}
+template<typename T>
+static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask)
+{
+ BLI_assert(src.data() != dst.data());
+ using namespace blender;
+ threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ dst[i] = src[mask[i]];
+ }
+ });
+}
+
+void InstancesComponent::remove_instances(const IndexMask mask)
+{
+ using namespace blender;
+ if (mask.is_range() && mask.as_range().start() == 0) {
+ /* Deleting from the end of the array can be much faster since no data has to be shifted. */
+ this->resize(mask.size());
+ this->remove_unused_references();
+ return;
+ }
+
+ Vector<int> new_handles(mask.size());
+ copy_data_based_on_mask<int>(this->instance_reference_handles(), new_handles, mask);
+ instance_reference_handles_ = std::move(new_handles);
+ Vector<float4x4> new_transforms(mask.size());
+ copy_data_based_on_mask<float4x4>(this->instance_transforms(), new_transforms, mask);
+ instance_transforms_ = std::move(new_transforms);
+
+ const bke::CustomDataAttributes &src_attributes = attributes_;
+
+ bke::CustomDataAttributes dst_attributes;
+ dst_attributes.reallocate(mask.size());
+
+ src_attributes.foreach_attribute(
+ [&](const bke::AttributeIDRef &id, const AttributeMetaData &meta_data) {
+ if (!id.should_be_kept()) {
+ return true;
+ }
+
+ GSpan src = *src_attributes.get_for_read(id);
+ dst_attributes.create(id, meta_data.data_type);
+ fn::GMutableSpan dst = *dst_attributes.get_for_write(id);
+
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask);
+ });
+ return true;
+ },
+ ATTR_DOMAIN_INSTANCE);
+
+ attributes_ = std::move(dst_attributes);
+ this->remove_unused_references();
+}
+
void InstancesComponent::remove_unused_references()
{
using namespace blender;
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index cc15e6d7b84..2509448d8aa 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -15,6 +15,7 @@
*/
#include "BLI_listbase.h"
+#include "BLI_task.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -123,6 +124,61 @@ void MeshComponent::ensure_owns_direct_data()
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Mesh Normals Field Input
+ * \{ */
+
+namespace blender::bke {
+
+VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
+ const Mesh &mesh,
+ const IndexMask mask,
+ const AttributeDomain domain)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_FACE: {
+ return VArray<float3>::ForSpan(
+ {(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly});
+ }
+ case ATTR_DOMAIN_POINT: {
+ return VArray<float3>::ForSpan(
+ {(float3 *)BKE_mesh_vertex_normals_ensure(&mesh), mesh.totvert});
+ }
+ case ATTR_DOMAIN_EDGE: {
+ /* In this case, start with vertex normals and convert to the edge domain, since the
+ * conversion from edges to vertices is very simple. Use "manual" domain interpolation
+ * instead of the GeometryComponent API to avoid calculating unnecessary values and to
+ * allow normalizing the result more simply. */
+ Span<float3> vert_normals{(float3 *)BKE_mesh_vertex_normals_ensure(&mesh), mesh.totvert};
+ Array<float3> edge_normals(mask.min_array_size());
+ Span<MEdge> edges{mesh.medge, mesh.totedge};
+ for (const int i : mask) {
+ const MEdge &edge = edges[i];
+ edge_normals[i] = math::normalize(
+ math::interpolate(vert_normals[edge.v1], vert_normals[edge.v2], 0.5f));
+ }
+
+ return VArray<float3>::ForContainer(std::move(edge_normals));
+ }
+ case ATTR_DOMAIN_CORNER: {
+ /* The normals on corners are just the mesh's face normals, so start with the face normal
+ * array and copy the face normal for each of its corners. In this case using the mesh
+ * component's generic domain interpolation is fine, the data will still be normalized,
+ * since the face normal is just copied to every corner. */
+ return mesh_component.attribute_try_adapt_domain(
+ VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly}),
+ ATTR_DOMAIN_FACE,
+ ATTR_DOMAIN_CORNER);
+ }
+ default:
+ return {};
+ }
+}
+
+} // namespace blender::bke
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Attribute Access
* \{ */
@@ -211,89 +267,54 @@ static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray
/**
* Each corner's value is simply a copy of the value at its vertex.
- *
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
*/
-template<typename T>
-static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh,
- const VArray<T> &old_values,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totloop);
-
- for (const int loop_index : IndexRange(mesh.totloop)) {
- const int vertex_index = mesh.mloop[loop_index].v;
- r_values[loop_index] = old_values[vertex_index];
- }
-}
-
static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray &varray)
{
GVArray new_varray;
attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
- Array<T> values(mesh.totloop);
- adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ new_varray = VArray<T>::ForFunc(mesh.totloop,
+ [mesh, varray = varray.typed<T>()](const int64_t loop_index) {
+ const int vertex_index = mesh.mloop[loop_index].v;
+ return varray[vertex_index];
+ });
});
return new_varray;
}
-/**
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
- */
-template<typename T>
-static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
- const VArray<T> &old_values,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totpoly);
- attribute_math::DefaultMixer<T> mixer(r_values);
-
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const T value = old_values[loop_index];
- mixer.mix_in(poly_index, value);
- }
- }
-
- mixer.finalize();
-}
-
-/* A face is selected if all of its corners were selected. */
-template<>
-void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
- const VArray<bool> &old_values,
- MutableSpan<bool> r_values)
-{
- BLI_assert(r_values.size() == mesh.totpoly);
-
- r_values.fill(true);
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- if (!old_values[loop_index]) {
- r_values[poly_index] = false;
- break;
- }
- }
- }
-}
-
static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray &varray)
{
GVArray new_varray;
attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- Array<T> values(mesh.totpoly);
- adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ if constexpr (std::is_same_v<T, bool>) {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<bool>()](const int face_index) {
+ /* A face is selected if all of its corners were selected. */
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ if (!varray[loop_index]) {
+ return false;
+ }
+ }
+ return true;
+ });
+ }
+ else {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ T return_value;
+ attribute_math::DefaultMixer<T> mixer({&return_value, 1});
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const T value = varray[loop_index];
+ mixer.mix_in(0, value);
+ }
+ mixer.finalize();
+ return return_value;
+ });
+ }
}
});
return new_varray;
@@ -351,11 +372,13 @@ void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
}
/* Deselect loose edges without corners that are still selected from the 'true' default. */
- for (const int edge_index : IndexRange(mesh.totedge)) {
- if (loose_edges[edge_index]) {
- r_values[edge_index] = false;
+ threading::parallel_for(IndexRange(mesh.totedge), 2048, [&](const IndexRange range) {
+ for (const int edge_index : range) {
+ if (loose_edges[edge_index]) {
+ r_values[edge_index] = false;
+ }
}
- }
+ });
}
static GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray)
@@ -436,11 +459,13 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
{
BLI_assert(r_values.size() == mesh.totloop);
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop);
- poly_corner_values.fill(old_values[poly_index]);
- }
+ threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange range) {
+ for (const int poly_index : range) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop);
+ poly_corner_values.fill(old_values[poly_index]);
+ }
+ });
}
static GVArray adapt_mesh_domain_face_to_corner(const Mesh &mesh, const GVArray &varray)
@@ -511,111 +536,72 @@ static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &v
return new_varray;
}
-/**
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
- */
-template<typename T>
-static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
- const VArray<T> &old_values,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totpoly);
- attribute_math::DefaultMixer<T> mixer(r_values);
-
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- MLoop &loop = mesh.mloop[loop_index];
- const int point_index = loop.v;
- mixer.mix_in(poly_index, old_values[point_index]);
- }
- }
- mixer.finalize();
-}
-
-/* A face is selected if all of its vertices were selected too. */
-template<>
-void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
- const VArray<bool> &old_values,
- MutableSpan<bool> r_values)
-{
- BLI_assert(r_values.size() == mesh.totpoly);
-
- r_values.fill(true);
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- MLoop &loop = mesh.mloop[loop_index];
- const int vert_index = loop.v;
- if (!old_values[vert_index]) {
- r_values[poly_index] = false;
- break;
- }
- }
- }
-}
-
static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray)
{
GVArray new_varray;
attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- Array<T> values(mesh.totpoly);
- adapt_mesh_domain_point_to_face_impl<T>(mesh, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ if constexpr (std::is_same_v<T, bool>) {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<bool>()](const int face_index) {
+ /* A face is selected if all of its vertices were selected. */
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ if (!varray[loop.v]) {
+ return false;
+ }
+ }
+ return true;
+ });
+ }
+ else {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ T return_value;
+ attribute_math::DefaultMixer<T> mixer({&return_value, 1});
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ const T value = varray[loop.v];
+ mixer.mix_in(0, value);
+ }
+ mixer.finalize();
+ return return_value;
+ });
+ }
}
});
return new_varray;
}
-/**
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
- */
-template<typename T>
-static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
- const VArray<T> &old_values,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totedge);
- attribute_math::DefaultMixer<T> mixer(r_values);
-
- for (const int edge_index : IndexRange(mesh.totedge)) {
- const MEdge &edge = mesh.medge[edge_index];
- mixer.mix_in(edge_index, old_values[edge.v1]);
- mixer.mix_in(edge_index, old_values[edge.v2]);
- }
-
- mixer.finalize();
-}
-
-/* An edge is selected if both of its vertices were selected. */
-template<>
-void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
- const VArray<bool> &old_values,
- MutableSpan<bool> r_values)
-{
- BLI_assert(r_values.size() == mesh.totedge);
-
- for (const int edge_index : IndexRange(mesh.totedge)) {
- const MEdge &edge = mesh.medge[edge_index];
- r_values[edge_index] = old_values[edge.v1] && old_values[edge.v2];
- }
-}
-
static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &varray)
{
GVArray new_varray;
attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- Array<T> values(mesh.totedge);
- adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ if constexpr (std::is_same_v<T, bool>) {
+ /* An edge is selected if both of its vertices were selected. */
+ new_varray = VArray<bool>::ForFunc(
+ mesh.totedge, [mesh, varray = varray.typed<bool>()](const int edge_index) {
+ const MEdge &edge = mesh.medge[edge_index];
+ return varray[edge.v1] && varray[edge.v2];
+ });
+ }
+ else {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totedge, [mesh, varray = varray.typed<T>()](const int edge_index) {
+ T return_value;
+ attribute_math::DefaultMixer<T> mixer({&return_value, 1});
+ const MEdge &edge = mesh.medge[edge_index];
+ mixer.mix_in(0, varray[edge.v1]);
+ mixer.mix_in(0, varray[edge.v2]);
+ mixer.finalize();
+ return return_value;
+ });
+ }
}
});
return new_varray;
@@ -732,61 +718,41 @@ static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray &
return new_varray;
}
-/**
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
- */
-template<typename T>
-static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
- const VArray<T> &old_values,
- MutableSpan<T> r_values)
-{
- BLI_assert(r_values.size() == mesh.totpoly);
- attribute_math::DefaultMixer<T> mixer(r_values);
-
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- mixer.mix_in(poly_index, old_values[loop.e]);
- }
- }
-
- mixer.finalize();
-}
-
-/* A face is selected if all of its edges are selected. */
-template<>
-void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
- const VArray<bool> &old_values,
- MutableSpan<bool> r_values)
-{
- BLI_assert(r_values.size() == mesh.totpoly);
-
- r_values.fill(true);
- for (const int poly_index : IndexRange(mesh.totpoly)) {
- const MPoly &poly = mesh.mpoly[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- const int edge_index = loop.e;
- if (!old_values[edge_index]) {
- r_values[poly_index] = false;
- break;
- }
- }
- }
-}
-
static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray)
{
GVArray new_varray;
attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- Array<T> values(mesh.totpoly);
- adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ if constexpr (std::is_same_v<T, bool>) {
+ /* A face is selected if all of its edges are selected. */
+ new_varray = VArray<bool>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ if (!varray[loop.e]) {
+ return false;
+ }
+ }
+ return true;
+ });
+ }
+ else {
+ new_varray = VArray<T>::ForFunc(
+ mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ T return_value;
+ attribute_math::DefaultMixer<T> mixer({&return_value, 1});
+ const MPoly &poly = mesh.mpoly[face_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ const T value = varray[loop.e];
+ mixer.mix_in(0, value);
+ }
+ mixer.finalize();
+ return return_value;
+ });
+ }
}
});
return new_varray;
@@ -1155,25 +1121,10 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
{
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
+ if (mesh == nullptr || mesh->totpoly == 0) {
return {};
}
-
- /* Use existing normals if possible. */
- if (!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL) &&
- CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
- const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
-
- return VArray<float3>::ForSpan(Span<float3>((const float3 *)data, mesh->totpoly));
- }
-
- Array<float3> normals(mesh->totpoly);
- for (const int i : IndexRange(mesh->totpoly)) {
- const MPoly *poly = &mesh->mpoly[i];
- BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]);
- }
-
- return VArray<float3>::ForContainer(std::move(normals));
+ return VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly});
}
WriteAttributeLookup try_get_for_write(GeometryComponent &UNUSED(component)) const final
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index ef5609ec9a8..c1e386c626b 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -17,6 +17,8 @@
#include "BLI_map.hh"
#include "BLI_task.hh"
+#include "BLT_translation.h"
+
#include "BKE_attribute.h"
#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.hh"
@@ -183,25 +185,27 @@ Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
return components;
}
-void GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const
+bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const
{
+ bool have_minmax = false;
const PointCloud *pointcloud = this->get_pointcloud_for_read();
if (pointcloud != nullptr) {
- BKE_pointcloud_minmax(pointcloud, *r_min, *r_max);
+ have_minmax |= BKE_pointcloud_minmax(pointcloud, *r_min, *r_max);
}
const Mesh *mesh = this->get_mesh_for_read();
if (mesh != nullptr) {
- BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max);
+ have_minmax |= BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max);
}
const Volume *volume = this->get_volume_for_read();
if (volume != nullptr) {
- BKE_volume_min_max(volume, *r_min, *r_max);
+ have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max);
}
const CurveEval *curve = this->get_curve_for_read();
if (curve != nullptr) {
/* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */
- curve->bounds_min_max(*r_min, *r_max, true);
+ have_minmax |= curve->bounds_min_max(*r_min, *r_max, true);
}
+ return have_minmax;
}
std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
@@ -566,6 +570,48 @@ void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Mesh and Curve Normals Field Input
+ * \{ */
+
+namespace blender::bke {
+
+GVArray NormalFieldInput::get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const
+{
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ if (const Mesh *mesh = mesh_component.get_for_read()) {
+ return mesh_normals_varray(mesh_component, *mesh, mask, domain);
+ }
+ }
+ else if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return curve_normals_varray(curve_component, domain);
+ }
+ return {};
+}
+
+std::string NormalFieldInput::socket_inspection_name() const
+{
+ return TIP_("Normal");
+}
+
+uint64_t NormalFieldInput::hash() const
+{
+ return 213980475983;
+}
+
+bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const
+{
+ return dynamic_cast<const NormalFieldInput *>(&other) != nullptr;
+}
+
+} // namespace blender::bke
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name C API
* \{ */
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 4d84d5d899d..42d2211c360 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -69,9 +69,18 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
}
/* Otherwise, construct a new geometry set with the component based on the object type. */
- GeometrySet geometry_set;
if (object.type == OB_MESH) {
+ GeometrySet geometry_set;
add_final_mesh_as_geometry_component(object, geometry_set);
+ return geometry_set;
+ }
+ if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
+ GeometrySet geometry_set;
+ Collection &collection = *object.instance_collection;
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ const int handle = instances.add_reference(collection);
+ instances.add_instance(handle, float4x4::identity());
+ return geometry_set;
}
/* TODO: Cover the case of point clouds without modifiers-- they may not be covered by the
@@ -80,7 +89,7 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
/* TODO: Add volume support. */
/* Return by value since there is not always an existing geometry set owned elsewhere to use. */
- return geometry_set;
+ return {};
}
static void geometry_set_collect_recursive_collection_instance(
@@ -98,13 +107,6 @@ static void geometry_set_collect_recursive_object(const Object &object,
{
GeometrySet instance_geometry_set = object_get_evaluated_geometry_set(object);
geometry_set_collect_recursive(instance_geometry_set, transform, r_sets);
-
- if (object.type == OB_EMPTY) {
- const Collection *collection_instance = object.instance_collection;
- if (collection_instance != nullptr) {
- geometry_set_collect_recursive_collection_instance(*collection_instance, transform, r_sets);
- }
- }
}
static void geometry_set_collect_recursive_collection(const Collection &collection,
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index b5190f598c6..9abdbceec61 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -33,10 +33,10 @@
#include "BLI_array_utils.h"
#include "BLI_blenlib.h"
-#include "BLI_float3.hh"
#include "BLI_ghash.h"
#include "BLI_hash.h"
#include "BLI_heap.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
#include "BLI_polyfill_2d.h"
#include "BLI_span.hh"
@@ -60,6 +60,7 @@
#include "BKE_gpencil_geom.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
@@ -145,7 +146,7 @@ void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps)
static void boundbox_gpencil(Object *ob)
{
if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
+ ob->runtime.bb = MEM_cnew<BoundBox>("GPencil boundbox");
}
BoundBox *bb = ob->runtime.bb;
@@ -182,7 +183,7 @@ BoundBox *BKE_gpencil_boundbox_get(Object *ob)
* to keep both values synchronized. */
if (!ELEM(ob_orig, nullptr, ob)) {
if (ob_orig->runtime.bb == nullptr) {
- ob_orig->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
+ ob_orig->runtime.bb = MEM_cnew<BoundBox>("GPencil boundbox");
}
for (int i = 0; i < 8; i++) {
copy_v3_v3(ob_orig->runtime.bb->vec[i], ob->runtime.bb->vec[i]);
@@ -364,7 +365,7 @@ static void stroke_defvert_create_nr_list(MDeformVert *dv_list,
}
}
if (!found) {
- ld = (LinkData *)MEM_callocN(sizeof(LinkData), "def_nr_item");
+ ld = MEM_cnew<LinkData>("def_nr_item");
ld->data = POINTER_FROM_INT(dw->def_nr);
BLI_addtail(result, ld);
tw++;
@@ -2350,6 +2351,7 @@ static void gpencil_generate_edgeloops(Object *ob,
if (me->totedge == 0) {
return;
}
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me);
/* Arrays for all edge vertices (forward and backward) that form a edge loop.
* This is reused for each edge-loop to create gpencil stroke. */
@@ -2364,13 +2366,13 @@ static void gpencil_generate_edgeloops(Object *ob,
MEdge *ed = &me->medge[i];
gped = &gp_edges[i];
MVert *mv1 = &me->mvert[ed->v1];
- normal_short_to_float_v3(gped->n1, mv1->no);
+ copy_v3_v3(gped->n1, vert_normals[ed->v1]);
gped->v1 = ed->v1;
copy_v3_v3(gped->v1_co, mv1->co);
MVert *mv2 = &me->mvert[ed->v2];
- normal_short_to_float_v3(gped->n2, mv2->no);
+ copy_v3_v3(gped->n2, vert_normals[ed->v2]);
gped->v2 = ed->v2;
copy_v3_v3(gped->v2_co, mv2->co);
@@ -2439,7 +2441,7 @@ static void gpencil_generate_edgeloops(Object *ob,
/* Add segment. */
bGPDspoint *pt = &gps_stroke->points[i];
- normal_short_to_float_v3(fpt, mv->no);
+ copy_v3_v3(fpt, vert_normals[vertex_index]);
mul_v3_v3fl(fpt, fpt, offset);
add_v3_v3v3(&pt->x, mv->co, fpt);
mul_m4_v3(matrix, &pt->x);
@@ -3482,7 +3484,7 @@ struct tSampleEdge {
/* Helper: creates a tSamplePoint from a bGPDspoint and (optionally) a MDeformVert. */
static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const MDeformVert *dvert)
{
- tSamplePoint *new_pt = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__);
+ tSamplePoint *new_pt = MEM_cnew<tSamplePoint>(__func__);
copy_v3_v3(&new_pt->x, &pt->x);
new_pt->pressure = pt->pressure;
new_pt->strength = pt->strength;
@@ -3505,7 +3507,7 @@ static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const
* the edge. */
static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamplePoint *to)
{
- tSampleEdge *new_edge = (tSampleEdge *)MEM_callocN(sizeof(tSampleEdge), __func__);
+ tSampleEdge *new_edge = MEM_cnew<tSampleEdge>(__func__);
new_edge->from = from;
new_edge->to = to;
new_edge->length_sq = len_squared_v3v3(&from->x, &to->x);
@@ -3561,7 +3563,7 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
tSamplePoint *sp_next = se->to;
/* Subdivide the edge. */
- tSamplePoint *new_sp = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__);
+ tSamplePoint *new_sp = MEM_cnew<tSamplePoint>(__func__);
interp_v3_v3v3(&new_sp->x, &sp->x, &sp_next->x, 0.5f);
new_sp->pressure = interpf(sp->pressure, sp_next->pressure, 0.5f);
new_sp->strength = interpf(sp->strength, sp_next->strength, 0.5f);
@@ -3687,7 +3689,7 @@ struct tPerimeterPoint {
static tPerimeterPoint *new_perimeter_point(const float pt[3])
{
- tPerimeterPoint *new_pt = (tPerimeterPoint *)MEM_callocN(sizeof(tPerimeterPoint), __func__);
+ tPerimeterPoint *new_pt = MEM_cnew<tPerimeterPoint>(__func__);
copy_v3_v3(&new_pt->x, pt);
return new_pt;
}
@@ -3856,8 +3858,8 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
float defaultpixsize = 1000.0f / gpd->pixfactor;
float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f;
- ListBase *perimeter_right_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
- ListBase *perimeter_left_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
+ ListBase *perimeter_right_side = MEM_cnew<ListBase>(__func__);
+ ListBase *perimeter_left_side = MEM_cnew<ListBase>(__func__);
int num_perimeter_points = 0;
bGPDspoint *first = &gps->points[0];
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 62604286b43..74db151261f 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -79,10 +79,6 @@ static GpencilVirtualModifierData virtualModifierCommonData;
* each loop over all the geometry being evaluated.
*/
-/**
- * Init grease pencil cache deform data.
- * \param ob: Grease pencil object
- */
void BKE_gpencil_cache_data_init(Depsgraph *depsgraph, Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
@@ -131,10 +127,6 @@ void BKE_gpencil_cache_data_init(Depsgraph *depsgraph, Object *ob)
}
}
-/**
- * Clear grease pencil cache deform data.
- * \param ob: Grease pencil object
- */
void BKE_gpencil_cache_data_clear(Object *ob)
{
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.cc
index f2a5146422e..b7ba159f631 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.cc
@@ -18,6 +18,9 @@
* \ingroup bke
*/
+#include <cmath>
+#include <cstring>
+
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
@@ -26,7 +29,8 @@
#include "DNA_object_types.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_base.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_rand.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -49,6 +53,8 @@
#include "BLO_read_write.h"
+using blender::float3;
+
static const char *HAIR_ATTR_POSITION = "position";
static const char *HAIR_ATTR_RADIUS = "radius";
@@ -67,10 +73,10 @@ static void hair_init_data(ID *id)
CustomData_reset(&hair->cdata);
CustomData_add_layer_named(
- &hair->pdata, CD_PROP_FLOAT3, CD_CALLOC, NULL, hair->totpoint, HAIR_ATTR_POSITION);
+ &hair->pdata, CD_PROP_FLOAT3, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_POSITION);
CustomData_add_layer_named(
- &hair->pdata, CD_PROP_FLOAT, CD_CALLOC, NULL, hair->totpoint, HAIR_ATTR_RADIUS);
- CustomData_add_layer(&hair->cdata, CD_HAIRCURVE, CD_CALLOC, NULL, hair->totcurve);
+ &hair->pdata, CD_PROP_FLOAT, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_RADIUS);
+ CustomData_add_layer(&hair->cdata, CD_HAIRCURVE, CD_CALLOC, nullptr, hair->totcurve);
BKE_hair_update_customdata_pointers(hair);
hair_random(hair);
@@ -80,14 +86,14 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co
{
Hair *hair_dst = (Hair *)id_dst;
const Hair *hair_src = (const Hair *)id_src;
- hair_dst->mat = MEM_dupallocN(hair_src->mat);
+ hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, alloc_type, hair_dst->totpoint);
CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, alloc_type, hair_dst->totcurve);
BKE_hair_update_customdata_pointers(hair_dst);
- hair_dst->batch_cache = NULL;
+ hair_dst->batch_cache = nullptr;
}
static void hair_free_data(ID *id)
@@ -115,8 +121,8 @@ static void hair_blend_write(BlendWriter *writer, ID *id, const void *id_address
{
Hair *hair = (Hair *)id;
- CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *clayers = NULL, clayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *clayers = nullptr, clayers_buff[CD_TEMP_CHUNK_SIZE];
CustomData_blend_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
CustomData_blend_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
@@ -174,33 +180,33 @@ static void hair_blend_read_expand(BlendExpander *expander, ID *id)
}
IDTypeInfo IDType_ID_HA = {
- .id_code = ID_HA,
- .id_filter = FILTER_ID_HA,
- .main_listbase_index = INDEX_ID_HA,
- .struct_size = sizeof(Hair),
- .name = "Hair",
- .name_plural = "hairs",
- .translation_context = BLT_I18NCONTEXT_ID_HAIR,
- .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
- .asset_type_info = NULL,
-
- .init_data = hair_init_data,
- .copy_data = hair_copy_data,
- .free_data = hair_free_data,
- .make_local = NULL,
- .foreach_id = hair_foreach_id,
- .foreach_cache = NULL,
- .foreach_path = NULL,
- .owner_get = NULL,
-
- .blend_write = hair_blend_write,
- .blend_read_data = hair_blend_read_data,
- .blend_read_lib = hair_blend_read_lib,
- .blend_read_expand = hair_blend_read_expand,
-
- .blend_read_undo_preserve = NULL,
-
- .lib_override_apply_post = NULL,
+ /*id_code */ ID_HA,
+ /*id_filter */ FILTER_ID_HA,
+ /*main_listbase_index */ INDEX_ID_HA,
+ /*struct_size */ sizeof(Hair),
+ /*name */ "Hair",
+ /*name_plural */ "hairs",
+ /*translation_context */ BLT_I18NCONTEXT_ID_HAIR,
+ /*flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /*asset_type_info */ nullptr,
+
+ /*init_data */ hair_init_data,
+ /*copy_data */ hair_copy_data,
+ /*free_data */ hair_free_data,
+ /*make_local */ nullptr,
+ /*foreach_id */ hair_foreach_id,
+ /*foreach_cache */ nullptr,
+ /*foreach_path */ nullptr,
+ /*owner_get */ nullptr,
+
+ /*blend_write */ hair_blend_write,
+ /*blend_read_data */ hair_blend_read_data,
+ /*blend_read_lib */ hair_blend_read_lib,
+ /*blend_read_expand */ hair_blend_read_expand,
+
+ /*blend_read_undo_preserve */ nullptr,
+
+ /*lib_override_apply_post */ nullptr,
};
static void hair_random(Hair *hair)
@@ -250,7 +256,7 @@ static void hair_random(Hair *hair)
void *BKE_hair_add(Main *bmain, const char *name)
{
- Hair *hair = BKE_id_new(bmain, ID_HA, name);
+ Hair *hair = static_cast<Hair *>(BKE_id_new(bmain, ID_HA, name));
return hair;
}
@@ -258,14 +264,14 @@ void *BKE_hair_add(Main *bmain, const char *name)
BoundBox *BKE_hair_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_HAIR);
- Hair *hair = ob->data;
+ Hair *hair = static_cast<Hair *>(ob->data);
- if (ob->runtime.bb != NULL && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
+ if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
return ob->runtime.bb;
}
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "hair boundbox");
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
float min[3], max[3];
INIT_MINMAX(min, max);
@@ -289,10 +295,12 @@ BoundBox *BKE_hair_boundbox_get(Object *ob)
void BKE_hair_update_customdata_pointers(Hair *hair)
{
- hair->co = CustomData_get_layer_named(&hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
- hair->radius = CustomData_get_layer_named(&hair->pdata, CD_PROP_FLOAT, HAIR_ATTR_RADIUS);
- hair->curves = CustomData_get_layer(&hair->cdata, CD_HAIRCURVE);
- hair->mapping = CustomData_get_layer(&hair->cdata, CD_HAIRMAPPING);
+ hair->co = (float(*)[3])CustomData_get_layer_named(
+ &hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
+ hair->radius = (float *)CustomData_get_layer_named(
+ &hair->pdata, CD_PROP_FLOAT, HAIR_ATTR_RADIUS);
+ hair->curves = (HairCurve *)CustomData_get_layer(&hair->cdata, CD_HAIRCURVE);
+ hair->mapping = (HairMaping *)CustomData_get_layer(&hair->cdata, CD_HAIRMAPPING);
}
bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer)
@@ -304,10 +312,10 @@ bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer)
Hair *BKE_hair_new_for_eval(const Hair *hair_src, int totpoint, int totcurve)
{
- Hair *hair_dst = BKE_id_new_nomain(ID_HA, NULL);
+ Hair *hair_dst = static_cast<Hair *>(BKE_id_new_nomain(ID_HA, nullptr));
STRNCPY(hair_dst->id.name, hair_src->id.name);
- hair_dst->mat = MEM_dupallocN(hair_src->mat);
+ hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
hair_dst->totcol = hair_src->totcol;
hair_dst->totpoint = totpoint;
@@ -327,7 +335,7 @@ Hair *BKE_hair_copy_for_eval(Hair *hair_src, bool reference)
flags |= LIB_ID_COPY_CD_REFERENCE;
}
- Hair *result = (Hair *)BKE_id_copy_ex(NULL, &hair_src->id, NULL, flags);
+ Hair *result = (Hair *)BKE_id_copy_ex(nullptr, &hair_src->id, nullptr, flags);
return result;
}
@@ -351,7 +359,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
/* Evaluate modifiers. */
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(static_cast<ModifierType>(md->type));
if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
@@ -370,7 +378,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
BKE_hair_update_customdata_pointers(hair);
/* Created deformed coordinates array on demand. */
- mti->deformVerts(md, &mectx, NULL, hair->co, hair->totpoint);
+ mti->deformVerts(md, &mectx, nullptr, hair->co, hair->totpoint);
}
else if (mti->modifyHair) {
/* Ensure we are not modifying the input. */
@@ -383,7 +391,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
if (hair_next && hair_next != hair) {
/* If the modifier returned a new hair, release the old one. */
if (hair != hair_input) {
- BKE_id_free(NULL, hair);
+ BKE_id_free(nullptr, hair);
}
hair = hair_next;
}
@@ -399,7 +407,7 @@ void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Obje
BKE_object_free_derived_caches(object);
/* Evaluate modifiers. */
- Hair *hair = object->data;
+ Hair *hair = static_cast<Hair *>(object->data);
Hair *hair_eval = hair_evaluate_modifiers(depsgraph, scene, object, hair);
/* Assign evaluated object. */
@@ -409,8 +417,8 @@ void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Obje
/* Draw Cache */
-void (*BKE_hair_batch_cache_dirty_tag_cb)(Hair *hair, int mode) = NULL;
-void (*BKE_hair_batch_cache_free_cb)(Hair *hair) = NULL;
+void (*BKE_hair_batch_cache_dirty_tag_cb)(Hair *hair, int mode) = nullptr;
+void (*BKE_hair_batch_cache_free_cb)(Hair *hair) = nullptr;
void BKE_hair_batch_cache_dirty_tag(Hair *hair, int mode)
{
diff --git a/source/blender/blenkernel/intern/idprop_create.cc b/source/blender/blenkernel/intern/idprop_create.cc
new file mode 100644
index 00000000000..12f2fdc6a63
--- /dev/null
+++ b/source/blender/blenkernel/intern/idprop_create.cc
@@ -0,0 +1,140 @@
+/*
+ * 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 <type_traits>
+
+#include "DNA_ID.h"
+
+#include "BKE_idprop.hh"
+
+namespace blender::bke::idprop {
+
+/* -------------------------------------------------------------------- */
+/** \name Create Functions
+ * \{ */
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name, int32_t value)
+{
+ IDPropertyTemplate prop_template{0};
+ prop_template.i = value;
+ IDProperty *property = IDP_New(IDP_INT, &prop_template, prop_name.c_str());
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name, float value)
+{
+ IDPropertyTemplate prop_template{0};
+ prop_template.f = value;
+ IDProperty *property = IDP_New(IDP_FLOAT, &prop_template, prop_name.c_str());
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name, double value)
+{
+ IDPropertyTemplate prop_template{0};
+ prop_template.d = value;
+ IDProperty *property = IDP_New(IDP_DOUBLE, &prop_template, prop_name.c_str());
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name,
+ const StringRefNull value)
+{
+ IDProperty *property = IDP_NewString(value.c_str(), prop_name.c_str(), value.size() + 1);
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+static std::unique_ptr<IDProperty, IDPropertyDeleter> array_create(const StringRefNull prop_name,
+ eIDPropertyType subtype,
+ size_t array_len)
+{
+ IDPropertyTemplate prop_template{0};
+ prop_template.array.len = array_len;
+ prop_template.array.type = subtype;
+ IDProperty *property = IDP_New(IDP_ARRAY, &prop_template, prop_name.c_str());
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+static void array_values_set(IDProperty *property,
+ const void *values,
+ size_t values_len,
+ size_t value_size)
+{
+ BLI_assert(values);
+ BLI_assert(property->len == values_len);
+ memcpy(IDP_Array(property), values, values_len * value_size);
+}
+
+/**
+ * Create a IDProperty array of `id_property_subtype` and fill it with the given values.
+ */
+template<
+ /** C-Primitive type of the array. Can be int32_t, float, double. */
+ typename PrimitiveType,
+ /** Subtype of the ID_ARRAY. Must match PrimitiveType. */
+ eIDPropertyType id_property_subtype>
+std::unique_ptr<IDProperty, IDPropertyDeleter> create_array(StringRefNull prop_name,
+ Span<PrimitiveType> values)
+{
+ static_assert(std::is_same_v<PrimitiveType, int32_t> || std::is_same_v<PrimitiveType, float_t> ||
+ std::is_same_v<PrimitiveType, double>,
+ "Allowed values for PrimitiveType are int32_t, float and double.");
+ static_assert(!std::is_same_v<PrimitiveType, int32_t> || id_property_subtype == IDP_INT,
+ "PrimitiveType and id_property_type do not match (int32_t).");
+ static_assert(!std::is_same_v<PrimitiveType, float> || id_property_subtype == IDP_FLOAT,
+ "PrimitiveType and id_property_type do not match (float).");
+ static_assert(!std::is_same_v<PrimitiveType, double> || id_property_subtype == IDP_DOUBLE,
+ "PrimitiveType and id_property_type do not match (double).");
+
+ const int64_t values_len = values.size();
+ BLI_assert(values_len > 0);
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = array_create(
+ prop_name.c_str(), id_property_subtype, values_len);
+ array_values_set(
+ property.get(), static_cast<const void *>(values.data()), values_len, sizeof(PrimitiveType));
+ return property;
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name,
+ Span<int32_t> values)
+{
+ return create_array<int32_t, IDP_INT>(prop_name, values);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name,
+ Span<float> values)
+{
+ return create_array<float, IDP_FLOAT>(prop_name, values);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name,
+ Span<double> values)
+{
+ return create_array<double, IDP_DOUBLE>(prop_name, values);
+}
+
+std::unique_ptr<IDProperty, IDPropertyDeleter> create_group(const StringRefNull prop_name)
+{
+ IDPropertyTemplate prop_template{0};
+ IDProperty *property = IDP_New(IDP_GROUP, &prop_template, prop_name.c_str());
+ return std::unique_ptr<IDProperty, IDPropertyDeleter>(property);
+}
+
+/* \} */
+
+} // namespace blender::bke::idprop
diff --git a/source/blender/blenkernel/intern/idprop_serialize.cc b/source/blender/blenkernel/intern/idprop_serialize.cc
new file mode 100644
index 00000000000..08a7f13b806
--- /dev/null
+++ b/source/blender/blenkernel/intern/idprop_serialize.cc
@@ -0,0 +1,844 @@
+/*
+ * 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 <optional>
+
+#include "DNA_ID.h"
+
+#include "BKE_idprop.hh"
+
+#include "BLI_listbase.h"
+
+namespace blender::bke::idprop {
+using namespace blender::io::serialize;
+
+/* Forward declarations */
+class IDPropertySerializer;
+struct DictionaryEntryParser;
+static IDProperty *idprop_from_value(const DictionaryValue &value);
+static const IDPropertySerializer &serializer_for(eIDPropertyType property_type);
+static const IDPropertySerializer &serializer_for(StringRef idprop_typename);
+
+/* -------------------------------------------------------------------- */
+/** \name ID property serialization.
+ * \{ */
+
+/* Definitions */
+static constexpr StringRef IDP_KEY_NAME("name");
+static constexpr StringRef IDP_KEY_TYPE("type");
+static constexpr StringRef IDP_KEY_SUBTYPE("subtype");
+static constexpr StringRef IDP_KEY_VALUE("value");
+
+static constexpr StringRef IDP_PROPERTY_TYPENAME_STRING("IDP_STRING");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_INT("IDP_INT");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_FLOAT("IDP_FLOAT");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_DOUBLE("IDP_DOUBLE");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_ARRAY("IDP_ARRAY");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_GROUP("IDP_GROUP");
+static constexpr StringRef IDP_PROPERTY_TYPENAME_UNKNOWN("IDP_UNKNOWN");
+
+/**
+ * \brief Base class for (de)serializing IDProperties.
+ *
+ * Has a subclass for supported IDProperties and one for unsupported IDProperties.
+ */
+class IDPropertySerializer {
+ public:
+ constexpr IDPropertySerializer() = default;
+
+ /**
+ * \brief return the type name for (de)serializing.
+ * Type name is stored in the `type` or `subtype` attribute of the serialized id_property.
+ */
+ virtual std::string type_name() const = 0;
+
+ /**
+ * \brief return the IDPropertyType for (de)serializing.
+ */
+ virtual std::optional<eIDPropertyType> property_type() const = 0;
+
+ /**
+ * \brief create dictionary containing the given id_property.
+ */
+ virtual std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const = 0;
+
+ /**
+ * \brief convert the entry to an id property.
+ */
+ virtual std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const = 0;
+
+ /**
+ * \brief Can the serializer be used?
+ *
+ * IDP_ID and IDP_IDPARRAY aren't supported for serialization.
+ */
+ virtual bool supports_serializing() const
+ {
+ return true;
+ }
+
+ protected:
+ /**
+ * \brief Create a new DictionaryValue instance.
+ *
+ * Only fill the dictionary with common attributes (name, type).
+ */
+ std::shared_ptr<DictionaryValue> create_dictionary(const struct IDProperty *id_property) const
+ {
+ std::shared_ptr<DictionaryValue> result = std::make_shared<DictionaryValue>();
+ DictionaryValue::Items &attributes = result->elements();
+ attributes.append_as(std::pair(IDP_KEY_NAME, new StringValue(id_property->name)));
+ attributes.append_as(std::pair(IDP_KEY_TYPE, new StringValue(type_name())));
+ return result;
+ }
+};
+
+/**
+ * \brief Helper class for parsing DictionaryValues.
+ */
+struct DictionaryEntryParser {
+ const DictionaryValue::Lookup lookup;
+
+ public:
+ explicit DictionaryEntryParser(const DictionaryValue &value) : lookup(value.create_lookup())
+ {
+ }
+
+ std::optional<eIDPropertyType> get_type() const
+ {
+ return get_id_property_type(IDP_KEY_TYPE);
+ }
+
+ std::optional<eIDPropertyType> get_subtype() const
+ {
+ return get_id_property_type(IDP_KEY_SUBTYPE);
+ }
+
+ std::optional<std::string> get_name() const
+ {
+ return get_string(IDP_KEY_NAME);
+ }
+
+ std::optional<std::string> get_string_value() const
+ {
+ return get_string(IDP_KEY_VALUE);
+ }
+
+ std::optional<int32_t> get_int_value() const
+ {
+ return get_int(IDP_KEY_VALUE);
+ }
+
+ std::optional<float> get_float_value() const
+ {
+ return get_float(IDP_KEY_VALUE);
+ }
+
+ std::optional<double> get_double_value() const
+ {
+ return get_double(IDP_KEY_VALUE);
+ }
+
+ const ArrayValue *get_array_value() const
+ {
+ return get_array(IDP_KEY_VALUE);
+ }
+
+ std::optional<Vector<int32_t>> get_array_int_value() const
+ {
+ return get_array_primitive<int32_t, IntValue>(IDP_KEY_VALUE);
+ }
+
+ std::optional<Vector<float>> get_array_float_value() const
+ {
+ return get_array_primitive<float, DoubleValue>(IDP_KEY_VALUE);
+ }
+
+ std::optional<Vector<double>> get_array_double_value() const
+ {
+ return get_array_primitive<double, DoubleValue>(IDP_KEY_VALUE);
+ }
+
+ private:
+ std::optional<std::string> get_string(StringRef key) const
+ {
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
+ if (value_ptr == nullptr) {
+ return std::nullopt;
+ }
+ const DictionaryValue::LookupValue &value = *value_ptr;
+
+ if (value->type() != eValueType::String) {
+ return std::nullopt;
+ }
+
+ return value->as_string_value()->value();
+ }
+
+ const ArrayValue *get_array(StringRef key) const
+ {
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
+ if (value_ptr == nullptr) {
+ return nullptr;
+ }
+ const DictionaryValue::LookupValue &value = *value_ptr;
+
+ if (value->type() != eValueType::Array) {
+ return nullptr;
+ }
+
+ return value->as_array_value();
+ }
+
+ std::optional<int32_t> get_int(StringRef key) const
+ {
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
+ if (value_ptr == nullptr) {
+ return std::nullopt;
+ }
+ const DictionaryValue::LookupValue &value = *value_ptr;
+
+ if (value->type() != eValueType::Int) {
+ return std::nullopt;
+ }
+
+ return value->as_int_value()->value();
+ }
+
+ std::optional<double> get_double(StringRef key) const
+ {
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
+ if (value_ptr == nullptr) {
+ return std::nullopt;
+ }
+ const DictionaryValue::LookupValue &value = *value_ptr;
+
+ if (value->type() != eValueType::Double) {
+ return std::nullopt;
+ }
+
+ return value->as_double_value()->value();
+ }
+
+ std::optional<float> get_float(StringRef key) const
+ {
+ return static_cast<std::optional<float>>(get_double(key));
+ }
+
+ template<typename PrimitiveType, typename ValueType>
+ std::optional<Vector<PrimitiveType>> get_array_primitive(StringRef key) const
+ {
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(key);
+ if (value_ptr == nullptr) {
+ return std::nullopt;
+ }
+ const DictionaryValue::LookupValue &value = *value_ptr;
+
+ if (value->type() != eValueType::Array) {
+ return std::nullopt;
+ }
+
+ Vector<PrimitiveType> result;
+ const ArrayValue::Items &elements = value->as_array_value()->elements();
+ for (const ArrayValue::Item &element : elements) {
+ const ValueType *value_type = static_cast<const ValueType *>(element.get());
+ PrimitiveType primitive_value = value_type->value();
+ result.append_as(primitive_value);
+ }
+
+ return result;
+ }
+
+ std::optional<eIDPropertyType> get_id_property_type(StringRef key) const
+ {
+ std::optional<std::string> string_value = get_string(key);
+ if (!string_value.has_value()) {
+ return std::nullopt;
+ }
+ const IDPropertySerializer &serializer = serializer_for(*string_value);
+ return serializer.property_type();
+ }
+};
+
+/** \brief IDPSerializer for IDP_STRING. */
+class IDPStringSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPStringSerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_STRING;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_STRING;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ attributes.append_as(std::pair(IDP_KEY_VALUE, new StringValue(IDP_String(id_property))));
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_STRING);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<std::string> string_value = entry_reader.get_string_value();
+ if (!string_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), string_value->c_str());
+ }
+};
+
+/** \brief IDPSerializer for IDP_INT. */
+class IDPIntSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPIntSerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_INT;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_INT;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ attributes.append_as(std::pair(IDP_KEY_VALUE, new IntValue(IDP_Int(id_property))));
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_INT);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<int32_t> extracted_value = entry_reader.get_int_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+};
+
+/** \brief IDPSerializer for IDP_FLOAT. */
+class IDPFloatSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPFloatSerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_FLOAT;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_FLOAT;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ attributes.append_as(std::pair(IDP_KEY_VALUE, new DoubleValue(IDP_Float(id_property))));
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_FLOAT);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<float> extracted_value = entry_reader.get_float_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+};
+
+/** \brief IDPSerializer for IDP_DOUBLE. */
+class IDPDoubleSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPDoubleSerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_DOUBLE;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_DOUBLE;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ attributes.append_as(std::pair(IDP_KEY_VALUE, new DoubleValue(IDP_Double(id_property))));
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_DOUBLE);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<double> extracted_value = entry_reader.get_double_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+};
+
+/** \brief IDPSerializer for IDP_ARRAY. */
+class IDPArraySerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPArraySerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_ARRAY;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_ARRAY;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ const IDPropertySerializer &subtype_serializer = serializer_for(
+ static_cast<eIDPropertyType>(id_property->subtype));
+ attributes.append_as(
+ std::pair(IDP_KEY_SUBTYPE, new StringValue(subtype_serializer.type_name())));
+
+ std::shared_ptr<ArrayValue> array = std::make_shared<ArrayValue>();
+ switch (static_cast<eIDPropertyType>(id_property->subtype)) {
+ case IDP_INT: {
+ int32_t *values = static_cast<int32_t *>(IDP_Array(id_property));
+ add_values<int32_t, IntValue>(array.get(), Span<int32_t>(values, id_property->len));
+ break;
+ }
+
+ case IDP_FLOAT: {
+ float *values = static_cast<float *>(IDP_Array(id_property));
+ add_values<float, DoubleValue>(array.get(), Span<float>(values, id_property->len));
+ break;
+ }
+
+ case IDP_DOUBLE: {
+ double *values = static_cast<double *>(IDP_Array(id_property));
+ add_values<double, DoubleValue>(array.get(), Span<double>(values, id_property->len));
+ break;
+ }
+
+ case IDP_GROUP: {
+ IDProperty *values = static_cast<IDProperty *>(IDP_Array(id_property));
+ add_values(array.get(), Span<IDProperty>(values, id_property->len));
+ break;
+ }
+
+ default: {
+ /* IDP_ARRAY only supports IDP_INT, IDP_FLOAT, IDP_DOUBLE and IDP_GROUP. */
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+ attributes.append_as(std::pair(IDP_KEY_VALUE, std::move(array)));
+
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
+ std::optional<eIDPropertyType> property_subtype = entry_reader.get_subtype();
+ if (!property_subtype.has_value()) {
+ return nullptr;
+ }
+
+ switch (*property_subtype) {
+ case IDP_INT:
+ return idprop_array_int_from_value(entry_reader);
+
+ case IDP_FLOAT:
+ return idprop_array_float_from_value(entry_reader);
+
+ case IDP_DOUBLE:
+ return idprop_array_double_from_value(entry_reader);
+
+ default:
+ break;
+ }
+ return nullptr;
+ }
+
+ private:
+ /** Add the given values to array. */
+ template</* C-primitive type of the values to add. Possible types are `float`, `int32_t` or
+ * `double`. */
+ typename PrimitiveType,
+ /* Type of value that can store the PrimitiveType in the Array. */
+ typename ValueType>
+ void add_values(ArrayValue *array, Span<PrimitiveType> values) const
+ {
+ ArrayValue::Items &items = array->elements();
+ for (PrimitiveType value : values) {
+ items.append_as(std::make_shared<ValueType>(value));
+ }
+ }
+
+ void add_values(ArrayValue *array, Span<IDProperty> values) const
+ {
+ ArrayValue::Items &items = array->elements();
+ for (const IDProperty &id_property : values) {
+ const IDPropertySerializer &value_serializer = serializer_for(
+ static_cast<eIDPropertyType>(id_property.type));
+ if (!value_serializer.supports_serializing()) {
+ continue;
+ }
+ std::shared_ptr<DictionaryValue> value = value_serializer.idprop_to_dictionary(&id_property);
+ items.append_as(value);
+ }
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_int_from_value(
+ DictionaryEntryParser &entry_reader) const
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
+ BLI_assert(*(entry_reader.get_subtype()) == IDP_INT);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<Vector<int32_t>> extracted_value = entry_reader.get_array_int_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_float_from_value(
+ DictionaryEntryParser &entry_reader) const
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
+ BLI_assert(*(entry_reader.get_subtype()) == IDP_FLOAT);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<Vector<float>> extracted_value = entry_reader.get_array_float_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_double_from_value(
+ DictionaryEntryParser &entry_reader) const
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY);
+ BLI_assert(*(entry_reader.get_subtype()) == IDP_DOUBLE);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+ std::optional<Vector<double>> extracted_value = entry_reader.get_array_double_value();
+ if (!extracted_value.has_value()) {
+ return nullptr;
+ }
+ return create(name->c_str(), *extracted_value);
+ }
+};
+
+/** \brief IDPSerializer for IDP_GROUP. */
+class IDPGroupSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPGroupSerializer() = default;
+
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_GROUP;
+ }
+
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return IDP_GROUP;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *id_property) const override
+ {
+ std::shared_ptr<DictionaryValue> result = create_dictionary(id_property);
+ DictionaryValue::Items &attributes = result->elements();
+ std::shared_ptr<ArrayValue> array = std::make_shared<ArrayValue>();
+ ArrayValue::Items &elements = array->elements();
+
+ LISTBASE_FOREACH (IDProperty *, sub_property, &id_property->data.group) {
+
+ const IDPropertySerializer &sub_property_serializer = serializer_for(
+ static_cast<eIDPropertyType>(sub_property->type));
+ elements.append_as(sub_property_serializer.idprop_to_dictionary(sub_property));
+ }
+
+ attributes.append_as(std::pair(IDP_KEY_VALUE, array));
+ return result;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &entry_reader) const override
+ {
+ BLI_assert(*(entry_reader.get_type()) == IDP_GROUP);
+ std::optional<std::string> name = entry_reader.get_name();
+ if (!name.has_value()) {
+ return nullptr;
+ }
+
+ const ArrayValue *array = entry_reader.get_array_value();
+ if (array == nullptr) {
+ return nullptr;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> result = create_group(name->c_str());
+ for (const ArrayValue::Item &element : array->elements()) {
+ if (element->type() != eValueType::Dictionary) {
+ continue;
+ }
+ const DictionaryValue *subobject = element->as_dictionary_value();
+ IDProperty *subproperty = idprop_from_value(*subobject);
+ IDP_AddToGroup(result.get(), subproperty);
+ }
+
+ return result;
+ }
+};
+
+/**
+ * \brief Dummy serializer for unknown and unsupported types.
+ */
+class IDPUnknownSerializer : public IDPropertySerializer {
+ public:
+ constexpr IDPUnknownSerializer() = default;
+ std::string type_name() const override
+ {
+ return IDP_PROPERTY_TYPENAME_UNKNOWN;
+ }
+ std::optional<eIDPropertyType> property_type() const override
+ {
+ return std::nullopt;
+ }
+
+ std::shared_ptr<DictionaryValue> idprop_to_dictionary(
+ const struct IDProperty *UNUSED(id_property)) const override
+ {
+ BLI_assert_unreachable();
+ return nullptr;
+ }
+
+ bool supports_serializing() const override
+ {
+ return false;
+ }
+
+ std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop(
+ DictionaryEntryParser &UNUSED(entry_reader)) const override
+ {
+ return nullptr;
+ }
+};
+
+/* Serializers are constructed statically to remove construction/destruction. */
+static constexpr IDPStringSerializer IDP_SERIALIZER_STRING;
+static constexpr IDPIntSerializer IDP_SERIALIZER_INT;
+static constexpr IDPFloatSerializer IDP_SERIALIZER_FLOAT;
+static constexpr IDPDoubleSerializer IDP_SERIALIZER_DOUBLE;
+static constexpr IDPArraySerializer IDP_SERIALIZER_ARRAY;
+static constexpr IDPGroupSerializer IDP_SERIALIZER_GROUP;
+static constexpr IDPUnknownSerializer IDP_SERIALIZER_UNKNOWN;
+
+/** \brief get the serializer for the given property type. */
+static const IDPropertySerializer &serializer_for(eIDPropertyType property_type)
+{
+ switch (property_type) {
+ case IDP_STRING:
+ return IDP_SERIALIZER_STRING;
+
+ case IDP_INT:
+ return IDP_SERIALIZER_INT;
+
+ case IDP_FLOAT:
+ return IDP_SERIALIZER_FLOAT;
+
+ case IDP_DOUBLE:
+ return IDP_SERIALIZER_DOUBLE;
+
+ case IDP_ARRAY:
+ return IDP_SERIALIZER_ARRAY;
+
+ case IDP_GROUP:
+ return IDP_SERIALIZER_GROUP;
+
+ default:
+ BLI_assert_msg(false, "Trying to convert an unsupported/unknown property type to a string");
+ return IDP_SERIALIZER_UNKNOWN;
+ }
+}
+
+/** \brief get serializer for the given typename. */
+static const IDPropertySerializer &serializer_for(StringRef idprop_typename)
+{
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_STRING) {
+ return IDP_SERIALIZER_STRING;
+ }
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_INT) {
+ return IDP_SERIALIZER_INT;
+ }
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_FLOAT) {
+ return IDP_SERIALIZER_FLOAT;
+ }
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_DOUBLE) {
+ return IDP_SERIALIZER_DOUBLE;
+ }
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_ARRAY) {
+ return IDP_SERIALIZER_ARRAY;
+ }
+ if (idprop_typename == IDP_PROPERTY_TYPENAME_GROUP) {
+ return IDP_SERIALIZER_GROUP;
+ }
+ return IDP_SERIALIZER_UNKNOWN;
+}
+
+/* \} */
+
+/* -------------------------------------------------------------------- */
+/** \name IDProperty to Value
+ * \{ */
+std::unique_ptr<ArrayValue> convert_to_serialize_values(const struct IDProperty *properties)
+{
+ BLI_assert(properties != nullptr);
+ std::unique_ptr<ArrayValue> result = std::make_unique<ArrayValue>();
+ ArrayValue::Items &elements = result->elements();
+ const struct IDProperty *current_property = properties;
+ while (current_property != nullptr) {
+ const IDPropertySerializer &serializer = serializer_for(
+ static_cast<eIDPropertyType>(current_property->type));
+ if (serializer.supports_serializing()) {
+ elements.append_as(serializer.idprop_to_dictionary(current_property));
+ }
+ current_property = current_property->next;
+ }
+
+ return result;
+}
+
+/* \} */
+
+/* -------------------------------------------------------------------- */
+/** \name IDProperty from Value
+ * \{ */
+
+static IDProperty *idprop_from_value(const DictionaryValue &value)
+{
+ DictionaryEntryParser entry_reader(value);
+ std::optional<eIDPropertyType> property_type = entry_reader.get_type();
+ if (!property_type.has_value()) {
+ return nullptr;
+ }
+
+ const IDPropertySerializer &serializer = serializer_for(*property_type);
+ return serializer.entry_to_idprop(entry_reader).release();
+}
+
+static IDProperty *idprop_from_value(const ArrayValue &value)
+{
+ IDProperty *result = nullptr;
+ IDProperty *previous_added = nullptr;
+
+ const ArrayValue::Items &elements = value.elements();
+ for (const ArrayValue::Item &element : elements) {
+ if (element->type() != eValueType::Dictionary) {
+ continue;
+ }
+ const DictionaryValue *object_value = element->as_dictionary_value();
+ IDProperty *last_created = idprop_from_value(*object_value);
+ if (last_created == nullptr) {
+ continue;
+ }
+
+ if (result == nullptr) {
+ result = last_created;
+ }
+
+ if (previous_added) {
+ previous_added->next = last_created;
+ }
+ last_created->prev = previous_added;
+ previous_added = last_created;
+ }
+
+ return result;
+}
+
+IDProperty *convert_from_serialize_value(const Value &value)
+{
+ if (value.type() != eValueType::Array) {
+ return nullptr;
+ }
+
+ return idprop_from_value(*value.as_array_value());
+}
+
+/* \} */
+
+} // namespace blender::bke::idprop
diff --git a/source/blender/blenkernel/intern/idprop_serialize_test.cc b/source/blender/blenkernel/intern/idprop_serialize_test.cc
new file mode 100644
index 00000000000..eeee3fc2aea
--- /dev/null
+++ b/source/blender/blenkernel/intern/idprop_serialize_test.cc
@@ -0,0 +1,448 @@
+/*
+ * 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 "DNA_ID.h"
+
+#include "BKE_idprop.hh"
+
+namespace blender::bke::idprop::tests {
+
+using namespace blender::io::serialize;
+
+static void check_container_value(ArrayValue *value)
+{
+ ASSERT_NE(value, nullptr);
+ ASSERT_EQ(value->type(), eValueType::Array);
+ const ArrayValue::Items elements = value->elements();
+ EXPECT_FALSE(elements.is_empty());
+ EXPECT_EQ(elements.size(), 1);
+
+ const ArrayValue::Item &item = value->elements()[0];
+ ASSERT_EQ(item->type(), eValueType::Dictionary);
+}
+
+static void check_object_attribute(const DictionaryValue::Lookup &lookup,
+ const std::string expected_key,
+ const std::string expected_value)
+{
+ EXPECT_TRUE(lookup.contains(expected_key));
+ const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
+ ASSERT_EQ(element->type(), eValueType::String);
+ EXPECT_EQ(element->as_string_value()->value(), expected_value);
+}
+
+static void check_object_attribute(const DictionaryValue::Lookup &lookup,
+ const std::string expected_key,
+ const int32_t expected_value)
+{
+ EXPECT_TRUE(lookup.contains(expected_key));
+ const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
+ ASSERT_EQ(element->type(), eValueType::Int);
+ EXPECT_EQ(element->as_int_value()->value(), expected_value);
+}
+
+static void check_object_attribute(const DictionaryValue::Lookup &lookup,
+ const std::string expected_key,
+ const float expected_value)
+{
+ EXPECT_TRUE(lookup.contains(expected_key));
+ const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
+ ASSERT_EQ(element->type(), eValueType::Double);
+ EXPECT_EQ(element->as_double_value()->value(), expected_value);
+}
+
+static void check_object_attribute(const DictionaryValue::Lookup &lookup,
+ const std::string expected_key,
+ const double expected_value)
+{
+ EXPECT_TRUE(lookup.contains(expected_key));
+ const std::shared_ptr<Value> &element = *lookup.lookup_ptr(expected_key);
+ ASSERT_EQ(element->type(), eValueType::Double);
+ EXPECT_EQ(element->as_double_value()->value(), expected_value);
+}
+
+static void test_string_to_value(const StringRefNull prop_name, const StringRefNull prop_content)
+{
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
+
+ std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
+ check_container_value(value.get());
+ const ArrayValue::Item &item = value->elements()[0];
+ const DictionaryValue *object = item->as_dictionary_value();
+ const DictionaryValue::Lookup lookup = object->create_lookup();
+
+ EXPECT_EQ(lookup.size(), 3);
+ check_object_attribute(lookup, "name", prop_name);
+ check_object_attribute(lookup, "type", "IDP_STRING");
+ check_object_attribute(lookup, "value", prop_content);
+}
+
+TEST(idprop, convert_idp_string_to_value)
+{
+ test_string_to_value("mykey", "mycontent");
+}
+
+static void test_int_to_value(const StringRefNull prop_name, int32_t prop_content)
+{
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
+
+ std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
+ check_container_value(value.get());
+ const ArrayValue::Item &item = value->elements()[0];
+ const DictionaryValue *object = item->as_dictionary_value();
+ const DictionaryValue::Lookup lookup = object->create_lookup();
+
+ EXPECT_EQ(lookup.size(), 3);
+ check_object_attribute(lookup, "name", prop_name);
+ check_object_attribute(lookup, "type", "IDP_INT");
+ check_object_attribute(lookup, "value", prop_content);
+}
+
+TEST(idprop, convert_idp_int_to_value)
+{
+ test_int_to_value("mykey", 0);
+}
+
+static void test_float_to_value(const StringRefNull prop_name, float prop_content)
+{
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
+
+ std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
+ check_container_value(value.get());
+ const ArrayValue::Item &item = value->elements()[0];
+ const DictionaryValue *object = item->as_dictionary_value();
+ const DictionaryValue::Lookup lookup = object->create_lookup();
+
+ EXPECT_EQ(lookup.size(), 3);
+ check_object_attribute(lookup, "name", prop_name);
+ check_object_attribute(lookup, "type", "IDP_FLOAT");
+ check_object_attribute(lookup, "value", prop_content);
+}
+
+TEST(idprop, convert_idp_float_to_value)
+{
+ test_float_to_value("mykey", 0.2f);
+}
+
+static void test_double_to_value(const StringRefNull prop_name, double prop_content)
+{
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
+
+ std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
+ check_container_value(value.get());
+ const ArrayValue::Item &item = value->elements()[0];
+ const DictionaryValue *object = item->as_dictionary_value();
+ const DictionaryValue::Lookup lookup = object->create_lookup();
+
+ EXPECT_EQ(lookup.size(), 3);
+ check_object_attribute(lookup, "name", prop_name);
+ check_object_attribute(lookup, "type", "IDP_DOUBLE");
+ check_object_attribute(lookup, "value", prop_content);
+}
+
+TEST(idprop, convert_idp_double_to_value)
+{
+ test_double_to_value("mykey", 0.2);
+}
+
+template<typename PrimitiveType, typename ValueType>
+static void test_array_to_value(const StringRefNull prop_name, Vector<PrimitiveType> prop_content)
+{
+ std::unique_ptr<IDProperty, IDPropertyDeleter> property = create(prop_name, prop_content);
+ std::unique_ptr<ArrayValue> value = convert_to_serialize_values(property.get());
+
+ check_container_value(value.get());
+ const ArrayValue::Item &item = value->elements()[0];
+ const DictionaryValue *object = item->as_dictionary_value();
+ const DictionaryValue::Lookup lookup = object->create_lookup();
+
+ EXPECT_EQ(lookup.size(), 4);
+ check_object_attribute(lookup, "name", prop_name);
+ check_object_attribute(lookup, "type", "IDP_ARRAY");
+
+ const std::shared_ptr<Value> &element = *lookup.lookup_ptr("value");
+ const ArrayValue *subvalues = element->as_array_value();
+ ASSERT_NE(subvalues, nullptr);
+ const ArrayValue::Items &subitems = subvalues->elements();
+ ASSERT_EQ(subitems.size(), prop_content.size());
+
+ for (size_t i = 0; i < prop_content.size(); i++) {
+ EXPECT_EQ(static_cast<ValueType *>(subitems[i].get())->value(), prop_content[i]);
+ }
+}
+
+TEST(idprop, convert_idp_int_array_to_value)
+{
+ test_array_to_value<int32_t, IntValue>("my_integer_array",
+ {-16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16});
+}
+
+TEST(idprop, convert_idp_float_array_to_value)
+{
+ test_array_to_value<float, DoubleValue>(
+ "my_float_array", {-16.8f, -8.4f, -4.2f, -2.1f, -1.0f, 0.0f, 1.0f, 2.1f, 4.2f, 8.4f, 16.8f});
+}
+
+TEST(idprop, convert_idp_double_array_to_value)
+{
+ test_array_to_value<double, DoubleValue>(
+ "my_double_array", {-16.8, -8.4, -4.2, -2.1, -1.0, 0.0, 1.0, 2.1, 4.2, 8.4, 16.8});
+}
+
+static std::unique_ptr<Value> parse_json(StringRef input)
+{
+ std::stringstream is(input);
+ JsonFormatter json;
+ std::unique_ptr<Value> value = json.deserialize(is);
+ return value;
+}
+
+static std::string to_json(const Value &value)
+{
+ std::stringstream out;
+ JsonFormatter json;
+ json.serialize(out, value);
+ return out.str();
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ StringRef expected_value)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_STRING);
+ EXPECT_EQ(id_property->name, expected_name);
+ EXPECT_EQ(IDP_String(id_property), expected_value);
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ int32_t expected_value)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_INT);
+ EXPECT_EQ(id_property->name, expected_name);
+ EXPECT_EQ(IDP_Int(id_property), expected_value);
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ float expected_value)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_FLOAT);
+ EXPECT_EQ(id_property->name, expected_name);
+ EXPECT_EQ(IDP_Float(id_property), expected_value);
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ double expected_value)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_DOUBLE);
+ EXPECT_EQ(id_property->name, expected_name);
+ EXPECT_EQ(IDP_Double(id_property), expected_value);
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ const Vector<int32_t> &values)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_ARRAY);
+ EXPECT_EQ(id_property->subtype, IDP_INT);
+ EXPECT_EQ(id_property->len, values.size());
+ EXPECT_EQ(id_property->name, expected_name);
+ int32_t *idprop_values = static_cast<int32_t *>(IDP_Array(id_property));
+ for (int i = 0; i < values.size(); i++) {
+ EXPECT_EQ(idprop_values[i], values[i]);
+ }
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ const Vector<float> &values)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_ARRAY);
+ EXPECT_EQ(id_property->subtype, IDP_FLOAT);
+ EXPECT_EQ(id_property->len, values.size());
+ EXPECT_EQ(id_property->name, expected_name);
+ float *idprop_values = static_cast<float *>(IDP_Array(id_property));
+ for (int i = 0; i < values.size(); i++) {
+ EXPECT_EQ(idprop_values[i], values[i]);
+ }
+}
+
+static void test_idprop(const IDProperty *id_property,
+ StringRef expected_name,
+ const Vector<double> &values)
+{
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_ARRAY);
+ EXPECT_EQ(id_property->subtype, IDP_DOUBLE);
+ EXPECT_EQ(id_property->len, values.size());
+ EXPECT_EQ(id_property->name, expected_name);
+ double *idprop_values = static_cast<double *>(IDP_Array(id_property));
+ for (int i = 0; i < values.size(); i++) {
+ EXPECT_EQ(idprop_values[i], values[i]);
+ }
+}
+
+template<typename Type>
+static void test_convert_idprop_from_value(StringRef input,
+ StringRef expected_name,
+ Type expected_value)
+{
+ std::unique_ptr<Value> value = parse_json(input);
+ IDProperty *id_property = convert_from_serialize_value(*value);
+ test_idprop(id_property, expected_name, expected_value);
+ IDP_FreeProperty(id_property);
+}
+
+TEST(idprop, convert_idp_string_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyStringName","type":"IDP_STRING","value":"MyString"}])",
+ "MyStringName",
+ "MyString");
+}
+
+TEST(idprop, convert_idp_int_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyIntegerName","type":"IDP_INT","value":42}])", "MyIntegerName", 42);
+}
+
+TEST(idprop, convert_idp_float_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyFloatName","type":"IDP_FLOAT","value":42.24}])", "MyFloatName", 42.24f);
+}
+
+TEST(idprop, convert_idp_double_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyDoubleName","type":"IDP_DOUBLE","value":42.24}])", "MyDoubleName", 42.24);
+}
+
+TEST(idprop, convert_idp_array_int_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_INT","value":[42, 24, 35]}])",
+ "MyArrayName",
+ Vector<int32_t>{42, 24, 35});
+}
+
+TEST(idprop, convert_idp_array_float_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_FLOAT","value":[42.0, 24.4, 35.2]}])",
+ "MyArrayName",
+ Vector<float>{42.0f, 24.4f, 35.2f});
+}
+
+TEST(idprop, convert_idp_array_double_from_value)
+{
+ test_convert_idprop_from_value(
+ R"([{"name":"MyArrayName","type":"IDP_ARRAY","subtype":"IDP_DOUBLE","value":[42.43,24.5,35.8]}])",
+ "MyArrayName",
+ Vector<double>{42.43, 24.5, 35.8});
+}
+
+TEST(idprop, convert_idp_multiple_from_value)
+{
+ static const std::string input_json =
+ R"([{"name":"MyIntegerName","type":"IDP_INT","value":42},{"name":"MyStringName","type":"IDP_STRING","value":"MyString"},{"name":"MyFloatName","type":"IDP_FLOAT","value":42.24},{"name":"MyDoubleName","type":"IDP_DOUBLE","value":42.24}])";
+ std::unique_ptr<Value> value = parse_json(input_json);
+
+ IDProperty *id_property = convert_from_serialize_value(*value);
+ IDProperty *id_property_1 = id_property;
+ ASSERT_NE(id_property_1, nullptr);
+ IDProperty *id_property_2 = id_property_1->next;
+ ASSERT_NE(id_property_2, nullptr);
+ IDProperty *id_property_3 = id_property_2->next;
+ ASSERT_NE(id_property_3, nullptr);
+ IDProperty *id_property_4 = id_property_3->next;
+ ASSERT_NE(id_property_4, nullptr);
+
+ EXPECT_EQ(id_property_1->prev, nullptr);
+ EXPECT_EQ(id_property_2->prev, id_property_1);
+ EXPECT_EQ(id_property_3->prev, id_property_2);
+ EXPECT_EQ(id_property_4->prev, id_property_3);
+ EXPECT_EQ(id_property_4->next, nullptr);
+
+ test_idprop(id_property_1, "MyIntegerName", 42);
+ test_idprop(id_property_2, "MyStringName", "MyString");
+ test_idprop(id_property_3, "MyFloatName", 42.24f);
+ test_idprop(id_property_4, "MyDoubleName", 42.24);
+
+ IDP_FreeProperty(id_property_1);
+ IDP_FreeProperty(id_property_2);
+ IDP_FreeProperty(id_property_3);
+ IDP_FreeProperty(id_property_4);
+}
+
+TEST(idprop, convert_idp_multiple_roundtrip)
+{
+ static const std::string input_json =
+ R"([{"name":"MyIntegerName","type":"IDP_INT","value":42},{"name":"MyStringName","type":"IDP_STRING","value":"MyString"},{"name":"MyFloatName","type":"IDP_FLOAT","value":42.2400016784668},{"name":"MyDoubleName","type":"IDP_DOUBLE","value":42.24}])";
+ std::unique_ptr<Value> value = parse_json(input_json);
+
+ IDProperty *id_property = convert_from_serialize_value(*value);
+ IDProperty *id_property_1 = id_property;
+ ASSERT_NE(id_property_1, nullptr);
+ IDProperty *id_property_2 = id_property_1->next;
+ ASSERT_NE(id_property_2, nullptr);
+ IDProperty *id_property_3 = id_property_2->next;
+ ASSERT_NE(id_property_3, nullptr);
+ IDProperty *id_property_4 = id_property_3->next;
+ ASSERT_NE(id_property_4, nullptr);
+
+ std::unique_ptr<Value> value_from_id_properties = convert_to_serialize_values(id_property);
+ std::string output_json = to_json(*value_from_id_properties);
+ EXPECT_EQ(input_json, output_json);
+
+ IDP_FreeProperty(id_property_1);
+ IDP_FreeProperty(id_property_2);
+ IDP_FreeProperty(id_property_3);
+ IDP_FreeProperty(id_property_4);
+}
+
+TEST(idprop, convert_idp_group_from_value)
+{
+ static const std::string input_json =
+ R"([{"name":"AssetMetaData.properties","type":"IDP_GROUP","value":[{"name":"dimensions","type":"IDP_ARRAY","subtype":"IDP_FLOAT","value":[2.0,2.0,2.0]}]}])";
+ std::unique_ptr<Value> value = parse_json(input_json);
+
+ IDProperty *id_property = convert_from_serialize_value(*value);
+ ASSERT_NE(id_property, nullptr);
+ EXPECT_EQ(id_property->type, IDP_GROUP);
+ EXPECT_EQ(BLI_listbase_count(&id_property->data.group), 1);
+
+ test_idprop(static_cast<IDProperty *>(id_property->data.group.first),
+ "dimensions",
+ Vector<float>{2.0f, 2.0f, 2.0f});
+
+ IDP_FreeProperty(id_property);
+}
+
+} // namespace blender::bke::idprop::tests
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 2c0ba2694e5..040257fe976 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -21,6 +21,7 @@
* \ingroup bke
*/
+#include <ctype.h>
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
@@ -84,6 +85,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -97,6 +99,7 @@
#include "SEQ_utils.h" /* SEQ_get_topmost_sequence() */
+#include "GPU_material.h"
#include "GPU_texture.h"
#include "BLI_sys_types.h" /* for intptr_t support */
@@ -118,7 +121,7 @@ static void image_init(Image *ima, short source, short type);
static void image_free_packedfiles(Image *ima);
static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src);
-/* Reset runtime image fields when datablock is being initialized. */
+/* Reset runtime image fields when data-block is being initialized. */
static void image_runtime_reset(struct Image *image)
{
memset(&image->runtime, 0, sizeof(image->runtime));
@@ -126,7 +129,7 @@ static void image_runtime_reset(struct Image *image)
BLI_mutex_init(image->runtime.cache_mutex);
}
-/* Reset runtime image fields when datablock is being copied. */
+/* Reset runtime image fields when data-block is being copied. */
static void image_runtime_reset_on_copy(struct Image *image)
{
image->runtime.cache_mutex = MEM_mallocN(sizeof(ThreadMutex), "image runtime cache_mutex");
@@ -284,7 +287,33 @@ static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
return;
}
- if (BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath)) {
+ /* If this is a tiled image, and we're asked to resolve the tokens in the virtual
+ * filepath, use the first tile to generate a concrete path for use during processing. */
+ bool result = false;
+ if (ima->source == IMA_SRC_TILED && (flag & BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN) != 0) {
+ char temp_path[FILE_MAX], orig_file[FILE_MAXFILE];
+ BLI_strncpy(temp_path, ima->filepath, sizeof(temp_path));
+ BLI_split_file_part(temp_path, orig_file, sizeof(orig_file));
+
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = BKE_image_get_tile_strformat(temp_path, &tile_format);
+ BKE_image_set_filepath_from_tile_number(
+ temp_path, udim_pattern, tile_format, ((ImageTile *)ima->tiles.first)->tile_number);
+ MEM_SAFE_FREE(udim_pattern);
+
+ result = BKE_bpath_foreach_path_fixed_process(bpath_data, temp_path);
+ if (result) {
+ /* Put the filepath back together using the new directory and the original file name. */
+ char new_dir[FILE_MAXDIR];
+ BLI_split_dir_part(temp_path, new_dir, sizeof(new_dir));
+ BLI_join_dirfile(ima->filepath, sizeof(ima->filepath), new_dir, orig_file);
+ }
+ }
+ else {
+ result = BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath);
+ }
+
+ if (result) {
if (flag & BKE_BPATH_FOREACH_PATH_RELOAD_EDITED) {
if (!BKE_image_has_packedfile(ima) &&
/* Image may have been painted onto (and not saved, T44543). */
@@ -900,9 +929,13 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
/* exists? */
file = BLI_open(str, O_BINARY | O_RDONLY, 0);
if (file == -1) {
- return NULL;
+ if (!BKE_image_tile_filepath_exists(str)) {
+ return NULL;
+ }
+ }
+ else {
+ close(file);
}
- close(file);
ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE);
STRNCPY(ima->filepath, filepath);
@@ -2076,9 +2109,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';
@@ -2426,7 +2460,7 @@ void BKE_image_stamp_buf(Scene *scene,
/* and draw the text. */
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.file, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.file, sizeof(stamp_data.file));
/* the extra pixel for background. */
y -= BUFF_MARGIN_Y * 2;
@@ -2449,7 +2483,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.date, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.date, sizeof(stamp_data.date));
/* the extra pixel for background. */
y -= BUFF_MARGIN_Y * 2;
@@ -2472,7 +2506,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.rendertime, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.rendertime, sizeof(stamp_data.rendertime));
/* the extra pixel for background. */
y -= BUFF_MARGIN_Y * 2;
@@ -2495,7 +2529,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.memory, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.memory, sizeof(stamp_data.memory));
/* the extra pixel for background. */
y -= BUFF_MARGIN_Y * 2;
@@ -2518,7 +2552,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.hostname, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.hostname, sizeof(stamp_data.hostname));
/* the extra pixel for background. */
y -= BUFF_MARGIN_Y * 2;
@@ -2542,7 +2576,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs + (h - h_fixed), 0.0);
- BLF_draw_buffer(mono, stamp_data.note, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.note, sizeof(stamp_data.note));
}
BLF_disable(mono, BLF_WORD_WRAP);
@@ -2566,7 +2600,7 @@ void BKE_image_stamp_buf(Scene *scene,
/* and pad the text. */
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.marker, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.marker, sizeof(stamp_data.marker));
/* space width. */
x += w + pad;
@@ -2589,7 +2623,7 @@ void BKE_image_stamp_buf(Scene *scene,
/* and pad the text. */
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.time, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.time, sizeof(stamp_data.time));
/* space width. */
x += w + pad;
@@ -2611,7 +2645,7 @@ void BKE_image_stamp_buf(Scene *scene,
/* and pad the text. */
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.frame, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.frame, sizeof(stamp_data.frame));
/* space width. */
x += w + pad;
@@ -2631,7 +2665,7 @@ void BKE_image_stamp_buf(Scene *scene,
x + w + BUFF_MARGIN_X,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.camera, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.camera, sizeof(stamp_data.camera));
/* space width. */
x += w + pad;
@@ -2651,7 +2685,7 @@ void BKE_image_stamp_buf(Scene *scene,
x + w + BUFF_MARGIN_X,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.cameralens, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.cameralens, sizeof(stamp_data.cameralens));
}
if (TEXT_SIZE_CHECK(stamp_data.scene, w, h)) {
@@ -2673,7 +2707,7 @@ void BKE_image_stamp_buf(Scene *scene,
/* and pad the text. */
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.scene, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.scene, sizeof(stamp_data.scene));
}
if (TEXT_SIZE_CHECK(stamp_data.strip, w, h)) {
@@ -2695,7 +2729,7 @@ void BKE_image_stamp_buf(Scene *scene,
y + h + BUFF_MARGIN_Y);
BLF_position(mono, x, y + y_ofs, 0.0);
- BLF_draw_buffer(mono, stamp_data.strip, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(mono, stamp_data.strip, sizeof(stamp_data.strip));
}
/* cleanup the buffer. */
@@ -3376,6 +3410,23 @@ static void image_walk_ntree_all_users(
}
}
+static void image_walk_gpu_materials(
+ ID *id,
+ ListBase *gpu_materials,
+ void *customdata,
+ void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata))
+{
+ LISTBASE_FOREACH (LinkData *, link, gpu_materials) {
+ GPUMaterial *gpu_material = (GPUMaterial *)link->data;
+ ListBase textures = GPU_material_textures(gpu_material);
+ LISTBASE_FOREACH (GPUMaterialTexture *, gpu_material_texture, &textures) {
+ if (gpu_material_texture->iuser_available) {
+ callback(gpu_material_texture->ima, id, &gpu_material_texture->iuser, customdata);
+ }
+ }
+ }
+}
+
static void image_walk_id_all_users(
ID *id,
bool skip_nested_nodes,
@@ -3395,6 +3446,7 @@ static void image_walk_id_all_users(
if (ma->nodetree && ma->use_nodes && !skip_nested_nodes) {
image_walk_ntree_all_users(ma->nodetree, &ma->id, customdata, callback);
}
+ image_walk_gpu_materials(id, &ma->gpumaterial, customdata, callback);
break;
}
case ID_LA: {
@@ -3409,6 +3461,7 @@ static void image_walk_id_all_users(
if (world->nodetree && world->use_nodes && !skip_nested_nodes) {
image_walk_ntree_all_users(world->nodetree, &world->id, customdata, callback);
}
+ image_walk_gpu_materials(id, &world->gpumaterial, customdata, callback);
break;
}
case ID_TE: {
@@ -3514,7 +3567,7 @@ static void image_tag_frame_recalc(Image *ima, ID *iuser_id, ImageUser *iuser, v
iuser->flag |= IMA_NEED_FRAME_RECALC;
if (iuser_id) {
- /* Must copy image user changes to CoW datablock. */
+ /* Must copy image user changes to CoW data-block. */
DEG_id_tag_update(iuser_id, ID_RECALC_COPY_ON_WRITE);
}
}
@@ -3529,7 +3582,7 @@ static void image_tag_reload(Image *ima, ID *iuser_id, ImageUser *iuser, void *c
image_update_views_format(ima, iuser);
}
if (iuser_id) {
- /* Must copy image user changes to CoW datablock. */
+ /* Must copy image user changes to CoW data-block. */
DEG_id_tag_update(iuser_id, ID_RECALC_COPY_ON_WRITE);
}
}
@@ -3691,6 +3744,43 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
BKE_image_free_buffers(ima);
}
+ if (ima->source == IMA_SRC_TILED) {
+ ListBase new_tiles = {NULL, NULL};
+ int new_start, new_range;
+
+ char filepath[FILE_MAX];
+ BLI_strncpy(filepath, ima->filepath, sizeof(filepath));
+ BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
+ bool result = BKE_image_get_tile_info(filepath, &new_tiles, &new_start, &new_range);
+ if (result) {
+ /* Because the prior and new list of tiles are both sparse sequences, we need to be sure
+ * to account for how the two sets might or might not overlap. To be complete, we start
+ * the refresh process by clearing all existing tiles, stopping when there's only 1 tile
+ * left. */
+ while (BKE_image_remove_tile(ima, ima->tiles.last)) {
+ ;
+ }
+
+ int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number;
+ bool needs_final_cleanup = true;
+
+ /* Add in all the new tiles. */
+ LISTBASE_FOREACH (LinkData *, new_tile, &new_tiles) {
+ int new_tile_number = POINTER_AS_INT(new_tile->data);
+ BKE_image_add_tile(ima, new_tile_number, NULL);
+ if (new_tile_number == remaining_tile_number) {
+ needs_final_cleanup = false;
+ }
+ }
+
+ /* Final cleanup if the prior remaining tile was never encountered in the new list. */
+ if (needs_final_cleanup) {
+ BKE_image_remove_tile(ima, BKE_image_get_tile(ima, remaining_tile_number));
+ }
+ }
+ BLI_freelistN(&new_tiles);
+ }
+
if (iuser) {
image_tag_reload(ima, NULL, iuser, ima);
}
@@ -3712,16 +3802,8 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
BLI_mutex_unlock(ima->runtime.cache_mutex);
- /* don't use notifiers because they are not 100% sure to succeeded
- * this also makes sure all scenes are accounted for. */
- {
- Scene *scene;
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (scene->nodetree) {
- nodeUpdateID(scene->nodetree, &ima->id);
- }
- }
- }
+ BKE_ntree_update_tag_id_changed(bmain, &ima->id);
+ BKE_ntree_update_main(bmain, NULL);
}
/* return renderpass for a given pass index and active view */
@@ -3782,6 +3864,57 @@ void BKE_image_get_tile_label(Image *ima, ImageTile *tile, char *label, int len_
}
}
+bool BKE_image_get_tile_info(char *filepath,
+ ListBase *udim_tiles,
+ int *udim_start,
+ int *udim_range)
+{
+ char filename[FILE_MAXFILE], dirname[FILE_MAXDIR];
+ BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
+
+ BKE_image_ensure_tile_token(filename);
+
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = BKE_image_get_tile_strformat(filename, &tile_format);
+
+ bool is_udim = true;
+ int min_udim = IMA_UDIM_MAX + 1;
+ int max_udim = 0;
+ int id;
+
+ struct direntry *dir;
+ uint totfile = BLI_filelist_dir_contents(dirname, &dir);
+ for (int i = 0; i < totfile; i++) {
+ if (!(dir[i].type & S_IFREG)) {
+ continue;
+ }
+
+ if (!BKE_image_get_tile_number_from_filepath(dir[i].relname, udim_pattern, tile_format, &id)) {
+ continue;
+ }
+
+ if (id < 1001 || id > IMA_UDIM_MAX) {
+ is_udim = false;
+ break;
+ }
+
+ BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id)));
+ min_udim = min_ii(min_udim, id);
+ max_udim = max_ii(max_udim, id);
+ }
+ BLI_filelist_free(dir, totfile);
+ MEM_SAFE_FREE(udim_pattern);
+
+ if (is_udim && min_udim <= IMA_UDIM_MAX) {
+ BLI_join_dirfile(filepath, FILE_MAX, dirname, filename);
+
+ *udim_start = min_udim;
+ *udim_range = max_udim - min_udim + 1;
+ return true;
+ }
+ return false;
+}
+
ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label)
{
if (ima->source != IMA_SRC_TILED) {
@@ -3941,6 +4074,184 @@ bool BKE_image_fill_tile(struct Image *ima,
return false;
}
+void BKE_image_ensure_tile_token(char *filename)
+{
+ BLI_assert_msg(BLI_path_slash_find(filename) == NULL,
+ "Only the file-name component should be used!");
+
+ /* Is there a '<' character in the filename? Assume tokens already present. */
+ if (strstr(filename, "<") != NULL) {
+ return;
+ }
+
+ /* Is there a sequence of digits in the filename? */
+ ushort digits;
+ char head[FILE_MAX], tail[FILE_MAX];
+ BLI_path_sequence_decode(filename, head, tail, &digits);
+ if (digits == 4) {
+ sprintf(filename, "%s<UDIM>%s", head, tail);
+ return;
+ }
+
+ /* Is there a sequence like u##_v#### in the filename? */
+ uint cur = 0;
+ uint name_end = strlen(filename);
+ uint u_digits = 0;
+ uint v_digits = 0;
+ uint u_start = (uint)-1;
+ bool u_found = false;
+ bool v_found = false;
+ bool sep_found = false;
+ while (cur < name_end) {
+ if (filename[cur] == 'u') {
+ u_found = true;
+ u_digits = 0;
+ u_start = cur;
+ }
+ else if (filename[cur] == 'v') {
+ v_found = true;
+ v_digits = 0;
+ }
+ else if (u_found && !v_found) {
+ if (isdigit(filename[cur]) && u_digits < 2) {
+ u_digits++;
+ }
+ else if (filename[cur] == '_') {
+ sep_found = true;
+ }
+ else {
+ u_found = false;
+ }
+ }
+ else if (u_found && u_digits > 0 && v_found) {
+ if (isdigit(filename[cur])) {
+ if (v_digits < 4) {
+ v_digits++;
+ }
+ else {
+ u_found = false;
+ v_found = false;
+ }
+ }
+ else if (v_digits > 0) {
+ break;
+ }
+ }
+
+ cur++;
+ }
+
+ if (u_found && sep_found && v_found && (u_digits + v_digits > 1)) {
+ const char *token = "<UVTILE>";
+ const size_t token_length = strlen(token);
+ memmove(filename + u_start + token_length, filename + cur, name_end - cur);
+ memcpy(filename + u_start, token, token_length);
+ filename[u_start + token_length + (name_end - cur)] = '\0';
+ }
+}
+
+bool BKE_image_tile_filepath_exists(const char *filepath)
+{
+ BLI_assert(!BLI_path_is_rel(filepath));
+
+ char dirname[FILE_MAXDIR];
+ BLI_split_dir_part(filepath, dirname, sizeof(dirname));
+
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format);
+
+ bool found = false;
+ struct direntry *dir;
+ uint totfile = BLI_filelist_dir_contents(dirname, &dir);
+ for (int i = 0; i < totfile; i++) {
+ if (!(dir[i].type & S_IFREG)) {
+ continue;
+ }
+
+ int id;
+ if (!BKE_image_get_tile_number_from_filepath(dir[i].path, udim_pattern, tile_format, &id)) {
+ continue;
+ }
+
+ if (id < 1001 || id > IMA_UDIM_MAX) {
+ continue;
+ }
+
+ found = true;
+ break;
+ }
+ BLI_filelist_free(dir, totfile);
+ MEM_SAFE_FREE(udim_pattern);
+
+ return found;
+}
+
+char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format)
+{
+ if (filepath == NULL || r_tile_format == NULL) {
+ return NULL;
+ }
+
+ if (strstr(filepath, "<UDIM>") != NULL) {
+ *r_tile_format = UDIM_TILE_FORMAT_UDIM;
+ return BLI_str_replaceN(filepath, "<UDIM>", "%d");
+ }
+ if (strstr(filepath, "<UVTILE>") != NULL) {
+ *r_tile_format = UDIM_TILE_FORMAT_UVTILE;
+ return BLI_str_replaceN(filepath, "<UVTILE>", "u%d_v%d");
+ }
+
+ *r_tile_format = UDIM_TILE_FORMAT_NONE;
+ return NULL;
+}
+
+bool BKE_image_get_tile_number_from_filepath(const char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int *r_tile_number)
+{
+ if (filepath == NULL || pattern == NULL || r_tile_number == NULL) {
+ return false;
+ }
+
+ int u, v;
+ bool result = false;
+
+ if (tile_format == UDIM_TILE_FORMAT_UDIM) {
+ if (sscanf(filepath, pattern, &u) == 1) {
+ *r_tile_number = u;
+ result = true;
+ }
+ }
+ else if (tile_format == UDIM_TILE_FORMAT_UVTILE) {
+ if (sscanf(filepath, pattern, &u, &v) == 2) {
+ *r_tile_number = 1001 + (u - 1) + ((v - 1) * 10);
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void BKE_image_set_filepath_from_tile_number(char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int tile_number)
+{
+ if (filepath == NULL || pattern == NULL) {
+ return;
+ }
+
+ if (tile_format == UDIM_TILE_FORMAT_UDIM) {
+ sprintf(filepath, pattern, tile_number);
+ }
+ else if (tile_format == UDIM_TILE_FORMAT_UVTILE) {
+ int u = ((tile_number - 1001) % 10);
+ int v = ((tile_number - 1001) / 10);
+ sprintf(filepath, pattern, u + 1, v + 1);
+ }
+}
+
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesn't use the index! */
RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
@@ -5476,7 +5787,7 @@ static void image_user_id_has_animation(Image *ima,
bool BKE_image_user_id_has_animation(ID *id)
{
/* For the dependency graph, this does not consider nested node
- * trees as these are handled as their own datablock. */
+ * trees as these are handled as their own data-block. */
bool has_animation = false;
bool skip_nested_nodes = true;
image_walk_id_all_users(id, skip_nested_nodes, &has_animation, image_user_id_has_animation);
@@ -5513,6 +5824,11 @@ void BKE_image_user_id_eval_animation(Depsgraph *depsgraph, ID *id)
void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
{
+ BKE_image_user_file_path_ex(iuser, ima, filepath, true);
+}
+
+void BKE_image_user_file_path_ex(ImageUser *iuser, Image *ima, char *filepath, bool resolve_udim)
+{
if (BKE_image_is_multiview(ima)) {
ImageView *iv = BLI_findlink(&ima->views, iuser->view);
if (iv->filepath[0]) {
@@ -5533,13 +5849,17 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
int index;
if (ima->source == IMA_SRC_SEQUENCE) {
index = iuser ? iuser->framenr : ima->lastframe;
+ BLI_path_sequence_decode(filepath, head, tail, &numlen);
+ BLI_path_sequence_encode(filepath, head, tail, numlen, index);
}
- else {
+ else if (resolve_udim) {
index = image_get_tile_number_from_iuser(ima, iuser);
- }
- BLI_path_sequence_decode(filepath, head, tail, &numlen);
- BLI_path_sequence_encode(filepath, head, tail, numlen, index);
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format);
+ BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, index);
+ MEM_SAFE_FREE(udim_pattern);
+ }
}
BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc
index 3b64790f7b8..5fe6cb93435 100644
--- a/source/blender/blenkernel/intern/image_gpu.cc
+++ b/source/blender/blenkernel/intern/image_gpu.cc
@@ -169,7 +169,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
if (ibuf) {
- PackTile *packtile = (PackTile *)MEM_callocN(sizeof(PackTile), __func__);
+ PackTile *packtile = MEM_cnew<PackTile>(__func__);
packtile->tile = tile;
packtile->boxpack.w = ibuf->x;
packtile->boxpack.h = ibuf->y;
diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c
index f93ede517a9..329bc7b498b 100644
--- a/source/blender/blenkernel/intern/image_save.c
+++ b/source/blender/blenkernel/intern/image_save.c
@@ -30,6 +30,8 @@
#include "DNA_image_types.h"
+#include "MEM_guardedalloc.h"
+
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -402,15 +404,17 @@ bool BKE_image_save(
bool colorspace_changed = false;
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = NULL;
+
if (ima->source == IMA_SRC_TILED) {
- /* Verify filepath for tiles images. */
- ImageTile *first_tile = ima->tiles.first;
- if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != first_tile->tile_number) {
+ /* Verify filepath for tiled images contains a valid UDIM marker. */
+ udim_pattern = BKE_image_get_tile_strformat(opts->filepath, &tile_format);
+ if (tile_format == UDIM_TILE_FORMAT_NONE) {
BKE_reportf(reports,
RPT_ERROR,
- "When saving a tiled image, the path '%s' must contain the UDIM tile number %d",
- opts->filepath,
- first_tile->tile_number);
+ "When saving a tiled image, the path '%s' must contain a valid UDIM marker",
+ opts->filepath);
return false;
}
@@ -420,36 +424,29 @@ bool BKE_image_save(
}
}
- /* Save image - or, for tiled images, the first tile. */
- bool ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
-
- if (ok && ima->source == IMA_SRC_TILED) {
+ /* Save images */
+ bool ok = false;
+ if (ima->source != IMA_SRC_TILED) {
+ ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
+ }
+ else {
char filepath[FILE_MAX];
BLI_strncpy(filepath, opts->filepath, sizeof(filepath));
- char head[FILE_MAX], tail[FILE_MAX];
- unsigned short numlen;
- BLI_path_sequence_decode(filepath, head, tail, &numlen);
-
- /* Save all other tiles. */
- int index;
- LISTBASE_FOREACH_INDEX (ImageTile *, tile, &ima->tiles, index) {
- /* First tile was already saved before the loop. */
- if (index == 0) {
- continue;
- }
+ /* Save all the tiles. */
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ BKE_image_set_filepath_from_tile_number(
+ opts->filepath, udim_pattern, tile_format, tile->tile_number);
+ iuser->tile = tile->tile_number;
+ ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
if (!ok) {
- continue;
+ break;
}
-
- /* Build filepath of the tile. */
- BLI_path_sequence_encode(opts->filepath, head, tail, numlen, tile->tile_number);
-
- iuser->tile = tile->tile_number;
- ok = ok && image_save_single(reports, ima, iuser, opts, &colorspace_changed);
}
+ BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath));
+ MEM_freeN(udim_pattern);
}
if (colorspace_changed) {
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index ff199794ab3..0df493e28c0 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -2230,13 +2230,20 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__);
free_polynors = true;
}
- BKE_mesh_calc_normals_poly_and_vertex(
- me.mvert, me.totvert, me.mloop, me.totloop, me.mpoly, me.totpoly, r_polynors, r_vertnors);
+
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ if (r_vertnors) {
+ memcpy(r_vertnors, vert_normals, sizeof(float[3]) * me.totvert);
+ }
+
+ const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
+ memcpy(r_polynors, face_normals, sizeof(float[3]) * me.totpoly);
if (r_loopnors) {
short(*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */
BKE_mesh_normals_loop_split(me.mvert,
+ vert_normals,
me.totvert,
me.medge,
me.totedge,
@@ -2244,7 +2251,7 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
r_loopnors,
me.totloop,
me.mpoly,
- r_polynors,
+ face_normals,
me.totpoly,
(me.flag & ME_AUTOSMOOTH) != 0,
me.smoothresh,
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index af0d91d29fc..2f5c5d0a0d5 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -466,7 +466,7 @@ void outside_lattice(Lattice *lt)
bp->hide = 1;
bp->f1 &= ~SELECT;
- /* u extrema */
+ /* U extrema. */
bp1 = latt_bp(lt, 0, v, w);
bp2 = latt_bp(lt, lt->pntsu - 1, v, w);
@@ -475,7 +475,7 @@ void outside_lattice(Lattice *lt)
bp->vec[1] = (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
bp->vec[2] = (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
- /* v extrema */
+ /* V extrema. */
bp1 = latt_bp(lt, u, 0, w);
bp2 = latt_bp(lt, u, lt->pntsv - 1, w);
@@ -484,7 +484,7 @@ void outside_lattice(Lattice *lt)
bp->vec[1] += (1.0f - fac1) * bp1->vec[1] + fac1 * bp2->vec[1];
bp->vec[2] += (1.0f - fac1) * bp1->vec[2] + fac1 * bp2->vec[2];
- /* w extrema */
+ /* W extrema. */
bp1 = latt_bp(lt, u, v, 0);
bp2 = latt_bp(lt, u, v, lt->pntsw - 1);
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 1484d35f28a..a59dd6f2e0e 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -343,7 +343,7 @@ ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollecti
/* Base */
-static void view_layer_bases_hash_create(ViewLayer *view_layer)
+static void view_layer_bases_hash_create(ViewLayer *view_layer, const bool do_base_duplicates_fix)
{
static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER;
@@ -353,15 +353,29 @@ static void view_layer_bases_hash_create(ViewLayer *view_layer)
if (view_layer->object_bases_hash == NULL) {
GHash *hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+ LISTBASE_FOREACH_MUTABLE (Base *, base, &view_layer->object_bases) {
if (base->object) {
- /* Some processes, like ID remapping, may lead to having several bases with the same
- * object. So just take the first one here, and ignore all others
- * (#BKE_layer_collection_sync will clean this up anyway). */
void **val_pp;
if (!BLI_ghash_ensure_p(hash, base->object, &val_pp)) {
*val_pp = base;
}
+ /* The same object has several bases.
+ *
+ * In normal cases this is a serious bug, but this is a common situation when remapping
+ * an object into another one already present in the same View Layer. While ideally we
+ * would process this case separately, for performances reasons it makes more sense to
+ * tackle it here. */
+ else if (do_base_duplicates_fix) {
+ if (view_layer->basact == base) {
+ view_layer->basact = NULL;
+ }
+ BLI_freelinkN(&view_layer->object_bases, base);
+ }
+ else {
+ CLOG_FATAL(&LOG,
+ "Object '%s' has more than one entry in view layer's object bases listbase",
+ base->object->id.name + 2);
+ }
}
}
@@ -376,7 +390,7 @@ static void view_layer_bases_hash_create(ViewLayer *view_layer)
Base *BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
{
if (!view_layer->object_bases_hash) {
- view_layer_bases_hash_create(view_layer);
+ view_layer_bases_hash_create(view_layer, false);
}
return BLI_ghash_lookup(view_layer->object_bases_hash, ob);
@@ -1182,6 +1196,23 @@ static bool view_layer_objects_base_cache_validate(ViewLayer *UNUSED(view_layer)
}
#endif
+void BKE_layer_collection_doversion_2_80(const Scene *scene, ViewLayer *view_layer)
+{
+ LayerCollection *first_layer_collection = view_layer->layer_collections.first;
+ if (BLI_listbase_count_at_most(&view_layer->layer_collections, 2) > 1 ||
+ first_layer_collection->collection != scene->master_collection) {
+ /* In some cases (from older files) we do have a master collection, but no matching layer,
+ * instead all the children of the master collection have their layer collections in the
+ * viewlayer's list. This is not a valid situation, add a layer for the master collection and
+ * add all existing first-level layers as children of that new master layer. */
+ ListBase layer_collections = view_layer->layer_collections;
+ BLI_listbase_clear(&view_layer->layer_collections);
+ LayerCollection *master_layer_collection = layer_collection_add(&view_layer->layer_collections,
+ scene->master_collection);
+ master_layer_collection->layer_collections = layer_collections;
+ }
+}
+
void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
{
if (no_resync) {
@@ -1193,18 +1224,32 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
return;
}
- /* In some cases (from older files) we do have a master collection, yet no matching layer. Create
- * the master one here, so that the rest of the code can work as expected. */
if (BLI_listbase_is_empty(&view_layer->layer_collections)) {
+ /* In some cases (from older files, or when creating a new ViewLayer from
+ * #BKE_view_layer_add), we do have a master collection, yet no matching layer. Create the
+ * master one here, so that the rest of the code can work as expected. */
layer_collection_add(&view_layer->layer_collections, scene->master_collection);
}
+#ifndef NDEBUG
+ {
+ BLI_assert_msg(BLI_listbase_count_at_most(&view_layer->layer_collections, 2) == 1,
+ "ViewLayer's first level of children layer collections should always have "
+ "exactly one item");
+
+ LayerCollection *first_layer_collection = view_layer->layer_collections.first;
+ BLI_assert_msg(first_layer_collection->collection == scene->master_collection,
+ "ViewLayer's first layer collection should always be the one for the scene's "
+ "master collection");
+ }
+#endif
+
/* Free cache. */
MEM_SAFE_FREE(view_layer->object_bases_array);
/* Create object to base hash if it does not exist yet. */
if (!view_layer->object_bases_hash) {
- view_layer_bases_hash_create(view_layer);
+ view_layer_bases_hash_create(view_layer, false);
}
/* Clear visible and selectable flags to be reset. */
@@ -1317,6 +1362,11 @@ void BKE_main_collection_sync_remap(const Main *bmain)
if (view_layer->object_bases_hash) {
BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
view_layer->object_bases_hash = NULL;
+
+ /* Directly re-create the mapping here, so that we can also deal with duplicates in
+ * `view_layer->object_bases` list of bases properly. This is the only place where such
+ * duplicates should be fixed, and not considered as a critical error. */
+ view_layer_bases_hash_create(view_layer, true);
}
}
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 692e27731c5..49a518607f1 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -454,38 +454,57 @@ static void lib_id_copy_ensure_local(Main *bmain, const ID *old_id, ID *new_id,
}
}
-void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
+void BKE_lib_id_make_local_generic_action_define(
+ struct Main *bmain, struct ID *id, int flags, bool *r_force_local, bool *r_force_copy)
{
- if (!ID_IS_LINKED(id)) {
- return;
- }
-
- const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
BLI_assert(force_copy == false || force_copy != force_local);
+ if (force_local || force_copy) {
+ /* Already set by caller code, nothing to do here. */
+ *r_force_local = force_local;
+ *r_force_copy = force_copy;
+ return;
+ }
+
+ const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
bool is_local = false, is_lib = false;
- /* - only lib users: do nothing (unless force_local is set)
- * - only local users: set flag
+ /* - no user (neither lib nor local): make local (happens e.g. with UI-used only data).
+ * - only lib users: do nothing (unless force_local is set)
+ * - only local users: make local
* - mixed: make copy
* In case we make a whole lib's content local,
* we always want to localize, and we skip remapping (done later).
*/
- if (!force_copy && !force_local) {
- BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
- if (lib_local || is_local) {
- if (!is_lib) {
- force_local = true;
- }
- else {
- force_copy = true;
- }
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+ if (!lib_local && !is_local && !is_lib) {
+ force_local = true;
+ }
+ else if (lib_local || is_local) {
+ if (!is_lib) {
+ force_local = true;
+ }
+ else {
+ force_copy = true;
}
}
+ *r_force_local = force_local;
+ *r_force_copy = force_copy;
+}
+
+void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
+{
+ if (!ID_IS_LINKED(id)) {
+ return;
+ }
+
+ bool force_local, force_copy;
+ BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
+
if (force_local) {
BKE_lib_id_clear_library_data(bmain, id, flags);
BKE_lib_id_expand_local(bmain, id, flags);
@@ -516,6 +535,7 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
}
}
+ const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
if (!lib_local) {
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
}
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 1922a54addb..f4dd67cac28 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -154,7 +154,10 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
}
if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(id, NULL);
+ struct IDRemapper *remapper = BKE_id_remapper_create();
+ BKE_id_remapper_add(remapper, id, NULL);
+ remap_editor_id_reference_cb(remapper);
+ BKE_id_remapper_free(remapper);
}
}
@@ -292,32 +295,40 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
* Note that we go forward here, since we want to check dependencies before users
* (e.g. meshes before objects).
* Avoids to have to loop twice. */
+ struct IDRemapper *remapper = BKE_id_remapper_create();
for (i = 0; i < base_count; i++) {
ListBase *lb = lbarray[i];
ID *id, *id_next;
+ BKE_id_remapper_clear(remapper);
for (id = lb->first; id; id = id_next) {
id_next = id->next;
/* NOTE: in case we delete a library, we also delete all its datablocks! */
if ((id->tag & tag) || (id->lib != NULL && (id->lib->id.tag & tag))) {
id->tag |= tag;
-
- /* Will tag 'never NULL' users of this ID too.
- * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect
- * (and proxy!) links, this can lead to nasty crashing here in second,
- * actual deleting loop.
- * Also, this will also flag users of deleted data that cannot be unlinked
- * (object using deleted obdata, etc.), so that they also get deleted. */
- BKE_libblock_remap_locked(bmain,
- id,
- NULL,
- (ID_REMAP_FLAG_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_NEVER_NULL_USAGE |
- ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
+ BKE_id_remapper_add(remapper, id, NULL);
}
}
+
+ if (BKE_id_remapper_is_empty(remapper)) {
+ continue;
+ }
+
+ /* Will tag 'never NULL' users of this ID too.
+ * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect
+ * (and proxy!) links, this can lead to nasty crashing here in second,
+ * actual deleting loop.
+ * Also, this will also flag users of deleted data that cannot be unlinked
+ * (object using deleted obdata, etc.), so that they also get deleted. */
+ BKE_libblock_remap_multiple_locked(bmain,
+ remapper,
+ (ID_REMAP_FLAG_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_NEVER_NULL_USAGE |
+ ID_REMAP_FORCE_INTERNAL_RUNTIME_POINTERS));
}
+ BKE_id_remapper_free(remapper);
}
+
BKE_main_unlock(bmain);
/* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones,
@@ -350,6 +361,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
void BKE_id_delete(Main *bmain, void *idv)
{
+ BLI_assert_msg((((ID *)idv)->tag & LIB_TAG_NO_MAIN) == 0,
+ "Cannot be used with IDs outside of Main");
+
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
((ID *)idv)->tag |= LIB_TAG_DOIT;
diff --git a/source/blender/blenkernel/intern/lib_id_remapper.cc b/source/blender/blenkernel/intern/lib_id_remapper.cc
new file mode 100644
index 00000000000..c1734c9826a
--- /dev/null
+++ b/source/blender/blenkernel/intern/lib_id_remapper.cc
@@ -0,0 +1,175 @@
+/*
+ * 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) 2022 by Blender Foundation.
+ */
+
+#include "DNA_ID.h"
+
+#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_map.hh"
+
+using IDTypeFilter = uint64_t;
+
+namespace blender::bke::id::remapper {
+struct IDRemapper {
+ private:
+ Map<ID *, ID *> mappings;
+ IDTypeFilter source_types = 0;
+
+ public:
+ void clear()
+ {
+ mappings.clear();
+ source_types = 0;
+ }
+
+ bool is_empty() const
+ {
+ return mappings.is_empty();
+ }
+
+ void add(ID *old_id, ID *new_id)
+ {
+ BLI_assert(old_id != nullptr);
+ BLI_assert(new_id == nullptr || (GS(old_id->name) == GS(new_id->name)));
+ mappings.add(old_id, new_id);
+ source_types |= BKE_idtype_idcode_to_idfilter(GS(old_id->name));
+ }
+
+ bool contains_mappings_for_any(IDTypeFilter filter) const
+ {
+ return (source_types & filter) != 0;
+ }
+
+ IDRemapperApplyResult apply(ID **r_id_ptr, IDRemapperApplyOptions options) const
+ {
+ BLI_assert(r_id_ptr != nullptr);
+ if (*r_id_ptr == nullptr) {
+ return ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE;
+ }
+
+ if (!mappings.contains(*r_id_ptr)) {
+ return ID_REMAP_RESULT_SOURCE_UNAVAILABLE;
+ }
+
+ if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
+ id_us_min(*r_id_ptr);
+ }
+
+ *r_id_ptr = mappings.lookup(*r_id_ptr);
+ if (*r_id_ptr == nullptr) {
+ return ID_REMAP_RESULT_SOURCE_UNASSIGNED;
+ }
+
+ if (options & ID_REMAP_APPLY_UPDATE_REFCOUNT) {
+ id_us_plus(*r_id_ptr);
+ }
+
+ if (options & ID_REMAP_APPLY_ENSURE_REAL) {
+ id_us_ensure_real(*r_id_ptr);
+ }
+ return ID_REMAP_RESULT_SOURCE_REMAPPED;
+ }
+
+ void iter(IDRemapperIterFunction func, void *user_data) const
+ {
+ for (auto item : mappings.items()) {
+ func(item.key, item.value, user_data);
+ }
+ }
+};
+
+} // namespace blender::bke::id::remapper
+
+/** \brief wrap CPP IDRemapper to a C handle. */
+static IDRemapper *wrap(blender::bke::id::remapper::IDRemapper *remapper)
+{
+ return static_cast<IDRemapper *>(static_cast<void *>(remapper));
+}
+
+/** \brief wrap C handle to a CPP IDRemapper. */
+static blender::bke::id::remapper::IDRemapper *unwrap(IDRemapper *remapper)
+{
+ return static_cast<blender::bke::id::remapper::IDRemapper *>(static_cast<void *>(remapper));
+}
+
+/** \brief wrap C handle to a CPP IDRemapper. */
+static const blender::bke::id::remapper::IDRemapper *unwrap(const IDRemapper *remapper)
+{
+ return static_cast<const blender::bke::id::remapper::IDRemapper *>(
+ static_cast<const void *>(remapper));
+}
+
+extern "C" {
+
+IDRemapper *BKE_id_remapper_create(void)
+{
+ blender::bke::id::remapper::IDRemapper *remapper =
+ MEM_new<blender::bke::id::remapper::IDRemapper>(__func__);
+ return wrap(remapper);
+}
+
+void BKE_id_remapper_free(IDRemapper *id_remapper)
+{
+ blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ MEM_delete<blender::bke::id::remapper::IDRemapper>(remapper);
+}
+
+void BKE_id_remapper_clear(struct IDRemapper *id_remapper)
+{
+ blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ remapper->clear();
+}
+
+bool BKE_id_remapper_is_empty(const struct IDRemapper *id_remapper)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ return remapper->is_empty();
+}
+
+void BKE_id_remapper_add(IDRemapper *id_remapper, ID *old_id, ID *new_id)
+{
+ blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ remapper->add(old_id, new_id);
+}
+
+bool BKE_id_remapper_has_mapping_for(const struct IDRemapper *id_remapper, uint64_t type_filter)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ return remapper->contains_mappings_for_any(type_filter);
+}
+
+IDRemapperApplyResult BKE_id_remapper_apply(const IDRemapper *id_remapper,
+ ID **r_id_ptr,
+ const IDRemapperApplyOptions options)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ return remapper->apply(r_id_ptr, options);
+}
+
+void BKE_id_remapper_iter(const struct IDRemapper *id_remapper,
+ IDRemapperIterFunction func,
+ void *user_data)
+{
+ const blender::bke::id::remapper::IDRemapper *remapper = unwrap(id_remapper);
+ remapper->iter(func, user_data);
+}
+}
diff --git a/source/blender/blenkernel/intern/lib_id_remapper_test.cc b/source/blender/blenkernel/intern/lib_id_remapper_test.cc
new file mode 100644
index 00000000000..594f64dac73
--- /dev/null
+++ b/source/blender/blenkernel/intern/lib_id_remapper_test.cc
@@ -0,0 +1,83 @@
+/*
+ * 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) 2022 by Blender Foundation.
+ */
+
+#include "testing/testing.h"
+
+#include "BKE_lib_remap.h"
+
+#include "BLI_string.h"
+
+#include "DNA_ID.h"
+
+namespace blender::bke::id::remapper::tests {
+
+TEST(lib_id_remapper, unavailable)
+{
+ ID id1;
+ ID *idp = &id1;
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNAVAILABLE);
+
+ BKE_id_remapper_free(remapper);
+}
+
+TEST(lib_id_remapper, not_mappable)
+{
+ ID *idp = nullptr;
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE);
+
+ BKE_id_remapper_free(remapper);
+}
+
+TEST(lib_id_remapper, mapped)
+{
+ ID id1;
+ ID id2;
+ ID *idp = &id1;
+ BLI_strncpy(id1.name, "OB1", sizeof(id1.name));
+ BLI_strncpy(id2.name, "OB2", sizeof(id2.name));
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ BKE_id_remapper_add(remapper, &id1, &id2);
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_REMAPPED);
+ EXPECT_EQ(idp, &id2);
+
+ BKE_id_remapper_free(remapper);
+}
+
+TEST(lib_id_remapper, unassigned)
+{
+ ID id1;
+ ID *idp = &id1;
+
+ IDRemapper *remapper = BKE_id_remapper_create();
+ BKE_id_remapper_add(remapper, &id1, nullptr);
+ IDRemapperApplyResult result = BKE_id_remapper_apply(remapper, &idp, ID_REMAP_APPLY_DEFAULT);
+ EXPECT_EQ(result, ID_REMAP_RESULT_SOURCE_UNASSIGNED);
+ EXPECT_EQ(idp, nullptr);
+
+ BKE_id_remapper_free(remapper);
+}
+
+} // namespace blender::bke::id::remapper::tests
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 52bfeb4b4d3..d1375b1e5b5 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"
@@ -281,6 +282,10 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
BLI_assert(ID_IS_LINKED(reference_id));
ID *local_id = lib_override_library_create_from(bmain, reference_id, 0);
+ /* We cannot allow automatic hierarchy resync on this ID, it is highly likely to generate a giant
+ * mess in case there are a lot of hidden, non-instantiated, non-properly organized dependencies.
+ * Ref T94650. */
+ local_id->override_library->flag |= IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY;
if (do_tagged_remap) {
Key *reference_key, *local_key = NULL;
@@ -371,7 +376,6 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
* existing linked IDs usages. */
if (success) {
for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
- ID *other_id;
reference_id = todo_id_iter->data;
ID *local_id = reference_id->newid;
@@ -389,6 +393,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
* remapped to use newly created overriding IDs, if needed. */
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ ID *other_id;
/* In case we created new overrides as 'no main', they are not accessible directly in this
* loop, but we can get to them through their reference's `newid` pointer. */
if (do_no_main && id->lib == reference_id->lib && id->newid != NULL) {
@@ -452,8 +457,60 @@ 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,
+ (void ***)&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`.
@@ -559,6 +616,42 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
}
}
+static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGroupTagData *data)
+{
+ Main *bmain = data->bmain;
+
+ /* Remove (untag) bone shape objects, they shall never need to be to directly/explicitly
+ * overridden. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & data->tag)) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ if (pchan->custom != NULL) {
+ pchan->custom->id.tag &= ~data->tag;
+ }
+ }
+ }
+ }
+
+ /* Remove (untag) collections if they do not own any tagged object (either themselves, or in
+ * their children collections). */
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ if ((collection->id.tag & data->tag) == 0) {
+ continue;
+ }
+ bool keep_tagged = false;
+ const ListBase object_bases = BKE_collection_object_cache_get(collection);
+ LISTBASE_FOREACH (Base *, base, &object_bases) {
+ if ((base->object->id.tag & data->tag) != 0) {
+ keep_tagged = true;
+ break;
+ }
+ }
+ if (!keep_tagged) {
+ collection->id.tag &= ~data->tag;
+ }
+ }
+}
+
/* This will tag at least all 'boundary' linked IDs for a potential override group.
*
* Requires existing `Main.relations`.
@@ -572,7 +665,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);
@@ -584,36 +676,36 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
id_root->tag |= data->tag;
}
- if (ELEM(GS(id_root->name), ID_OB, ID_GR)) {
- /* Tag all collections and objects. */
- lib_override_linked_group_tag_recursive(data);
+ /* Only objects and groups are currently considered as 'keys' in override hierarchies. */
+ if (!ELEM(GS(id_root->name), ID_OB, ID_GR)) {
+ return;
+ }
- /* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitly
- * override those. */
- LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & data->tag)) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
- if (pchan->custom != NULL) {
- pchan->custom->id.tag &= ~(data->tag | data->missing_tag);
- }
- }
- }
- }
+ /* Tag all collections and objects recursively. */
+ lib_override_linked_group_tag_recursive(data);
- /* For each object tagged for override, ensure we get at least one local or liboverride
- * collection to host it. Avoids getting a bunch of random object in the scene's master
- * collection when all objects' dependencies are not properly 'packed' into a single root
- * collection. */
- LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- if (ID_IS_LINKED(ob) && (ob->id.tag & data->tag) != 0) {
- Collection *instantiating_collection = NULL;
- 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. */
+ /* Do not override objects used as bone shapes, nor their collections if possible. */
+ lib_override_linked_group_tag_clear_boneshapes_objects(data);
+
+ /* For each object tagged for override, ensure we get at least one local or liboverride
+ * collection to host it. Avoids getting a bunch of random object in the scene's master
+ * collection when all objects' dependencies are not properly 'packed' into a single root
+ * collection. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ID_IS_LINKED(ob) && (ob->id.tag & data->tag) != 0) {
+ Collection *instantiating_collection = NULL;
+ 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. */
+ 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)) {
@@ -623,16 +715,17 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
(!is_resync || instantiating_collection->id.lib == id_root->lib)) {
instantiating_collection_override_candidate = instantiating_collection;
}
+ instantiating_collection = NULL;
}
+ }
- if (instantiating_collection == NULL &&
- instantiating_collection_override_candidate != NULL) {
- if (instantiating_collection_override_candidate->id.tag & LIB_TAG_MISSING) {
- instantiating_collection_override_candidate->id.tag |= data->missing_tag;
- }
- else {
- instantiating_collection_override_candidate->id.tag |= data->tag;
- }
+ if (instantiating_collection == NULL &&
+ instantiating_collection_override_candidate != NULL) {
+ if (instantiating_collection_override_candidate->id.tag & LIB_TAG_MISSING) {
+ instantiating_collection_override_candidate->id.tag |= data->missing_tag;
+ }
+ else {
+ instantiating_collection_override_candidate->id.tag |= data->tag;
}
}
}
@@ -645,6 +738,12 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
ID *id_owner = data->id_root;
BLI_assert(ID_IS_OVERRIDE_LIBRARY(id_owner));
BLI_assert(data->is_override);
+
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id_owner) &&
+ (id_owner->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY) != 0) {
+ return;
+ }
+
const uint tag = data->tag;
const uint missing_tag = data->missing_tag;
@@ -724,12 +823,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);
}
@@ -1020,14 +1121,53 @@ void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadRepor
}
}
-bool BKE_lib_override_library_resync(Main *bmain,
- Scene *scene,
- ViewLayer *view_layer,
- ID *id_root,
- Collection *override_resync_residual_storage,
- const bool do_hierarchy_enforce,
- const bool do_post_process,
- BlendFileReadReport *reports)
+static void lib_override_library_remap(Main *bmain,
+ const ID *id_root_reference,
+ GHash *linkedref_to_old_override)
+{
+ ID *id;
+ struct IDRemapper *remapper = BKE_id_remapper_create();
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+
+ if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
+ ID *id_override_new = id->newid;
+ ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
+ if (id_override_old == NULL) {
+ continue;
+ }
+
+ BKE_id_remapper_add(remapper, id_override_old, id_override_new);
+ /* Remap no-main override IDs we just created too. */
+ GHashIterator linkedref_to_old_override_iter;
+ GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) {
+ ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter);
+ if ((id_override_old_iter->tag & LIB_TAG_NO_MAIN) == 0) {
+ continue;
+ }
+
+ BKE_libblock_relink_ex(bmain,
+ id_override_old_iter,
+ id_override_old,
+ id_override_new,
+ ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ /* Remap all IDs to use the new override. */
+ BKE_libblock_remap_multiple(bmain, remapper, 0);
+ BKE_id_remapper_free(remapper);
+}
+
+static bool lib_override_library_resync(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ID *id_root,
+ Collection *override_resync_residual_storage,
+ const bool do_hierarchy_enforce,
+ const bool do_post_process,
+ BlendFileReadReport *reports)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
@@ -1050,6 +1190,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);
@@ -1140,6 +1281,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
@@ -1209,32 +1351,9 @@ bool BKE_lib_override_library_resync(Main *bmain,
}
FOREACH_MAIN_LISTBASE_END;
- /* We need to remap old to new override usages in a separate loop, after all new overrides have
+ /* We remap old to new override usages in a separate loop, after all new overrides have
* been added to Main. */
- FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
- ID *id_override_new = id->newid;
- ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
-
- if (id_override_old != NULL) {
- /* Remap all IDs to use the new override. */
- BKE_libblock_remap(bmain, id_override_old, id_override_new, 0);
- /* Remap no-main override IDs we just created too. */
- GHashIterator linkedref_to_old_override_iter;
- GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) {
- ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter);
- if (id_override_old_iter->tag & LIB_TAG_NO_MAIN) {
- BKE_libblock_relink_ex(bmain,
- id_override_old_iter,
- id_override_old,
- id_override_new,
- ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
- }
- }
- }
- }
- }
- FOREACH_MAIN_ID_END;
+ lib_override_library_remap(bmain, id_root_reference, linkedref_to_old_override);
BKE_main_collection_sync(bmain);
@@ -1396,6 +1515,26 @@ bool BKE_lib_override_library_resync(Main *bmain,
return success;
}
+bool BKE_lib_override_library_resync(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ID *id_root,
+ Collection *override_resync_residual_storage,
+ const bool do_hierarchy_enforce,
+ BlendFileReadReport *reports)
+{
+ const bool success = lib_override_library_resync(bmain,
+ scene,
+ view_layer,
+ id_root,
+ override_resync_residual_storage,
+ do_hierarchy_enforce,
+ true,
+ reports);
+
+ return success;
+}
+
/* Also tag ancestors overrides for resync.
*
* WARNING: Expects `bmain` to have valid relation data.
@@ -1414,11 +1553,13 @@ static void lib_override_resync_tagging_finalize_recurse(Main *bmain,
CLOG_ERROR(
&LOG,
"While processing indirect level %d, ID %s from lib %s of indirect level %d detected "
- "as needing resync.",
+ "as needing resync, skipping.",
library_indirect_level,
id->name,
id->lib->filepath,
id->lib->temp_index);
+ id->tag &= ~LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
+ return;
}
MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
@@ -1532,6 +1673,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)) {
@@ -1542,19 +1691,19 @@ 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};
+ if (id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY) {
+ /* This ID is not part of an override hierarchy. */
+ continue;
+ }
+
+ 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. */
@@ -1564,6 +1713,12 @@ static void lib_override_library_main_resync_on_library_indirect_level(
continue;
}
+ if (id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY) {
+ /* This ID is not part of an override hierarchy. */
+ BLI_assert((id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0);
+ continue;
+ }
+
if (id->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) {
CLOG_INFO(&LOG, 4, "ID %s (%p) was already tagged as needing resync", id->name, id->lib);
lib_override_resync_tagging_finalize_recurse(bmain, id, library_indirect_level);
@@ -1616,6 +1771,10 @@ static void lib_override_library_main_resync_on_library_indirect_level(
continue;
}
+ if (ID_IS_LINKED(id)) {
+ id->lib->tag |= LIBRARY_TAG_RESYNC_REQUIRED;
+ }
+
/* We cannot resync a scene that is currently active. */
if (id == &scene->id) {
id->tag &= ~LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
@@ -1642,7 +1801,7 @@ static void lib_override_library_main_resync_on_library_indirect_level(
do_continue = true;
CLOG_INFO(&LOG, 2, "Resyncing %s (%p)...", id->name, library);
- const bool success = BKE_lib_override_library_resync(
+ const bool success = lib_override_library_resync(
bmain, scene, view_layer, id, override_resync_residual_storage, false, false, reports);
CLOG_INFO(&LOG, 2, "\tSuccess: %d", success);
if (success) {
@@ -1772,6 +1931,16 @@ void BKE_lib_override_library_main_resync(Main *bmain,
if (BKE_collection_is_empty(override_resync_residual_storage)) {
BKE_collection_delete(bmain, override_resync_residual_storage, true);
}
+
+ LISTBASE_FOREACH (Library *, library, &bmain->libraries) {
+ if (library->tag & LIBRARY_TAG_RESYNC_REQUIRED) {
+ CLOG_INFO(&LOG,
+ 2,
+ "library '%s' contains some linked overrides that required recursive resync, "
+ "consider updating it",
+ library->filepath);
+ }
+ }
}
void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
@@ -1787,9 +1956,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) {
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 4ad0186f9b5..1f20a84098c 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -439,7 +439,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_LA:
return (ELEM(id_type_used, ID_TE));
case ID_CA:
- return ELEM(id_type_used, ID_OB);
+ return ELEM(id_type_used, ID_OB, ID_IM);
case ID_KE:
/* Warning! key->from, could be more types in future? */
return ELEM(id_type_used, ID_ME, ID_CU, ID_LT);
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 3cea0de32ee..c3ccedb9608 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -91,6 +91,97 @@ enum {
ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */
};
+static void foreach_libblock_remap_callback_skip(const ID *id_owner,
+ ID **id_ptr,
+ IDRemap *id_remap_data,
+ const int cb_flag,
+ const bool is_indirect,
+ const bool is_reference,
+ const bool is_never_null,
+ const bool is_obj,
+ const bool is_obj_editmode)
+{
+ if (is_indirect) {
+ id_remap_data->skipped_indirect++;
+ if (is_obj) {
+ Object *ob = (Object *)id_owner;
+ if (ob->data == *id_ptr && ob->proxy != NULL) {
+ /* And another 'Proudly brought to you by Proxy Hell' hack!
+ * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */
+ id_remap_data->skipped_direct++;
+ }
+ }
+ }
+ else if (is_never_null || is_obj_editmode || is_reference) {
+ id_remap_data->skipped_direct++;
+ }
+ else {
+ BLI_assert(0);
+ }
+ if (cb_flag & IDWALK_CB_USER) {
+ id_remap_data->skipped_refcounted++;
+ }
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
+ /* No need to count number of times this happens, just a flag is enough. */
+ id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
+ }
+}
+
+static void foreach_libblock_remap_callback_apply(ID *id_owner,
+ ID *id_self,
+ ID *old_id,
+ ID *new_id,
+ ID **id_ptr,
+ IDRemap *id_remap_data,
+ const int cb_flag,
+ const bool is_indirect,
+ const bool is_never_null,
+ const bool force_user_refcount,
+ const bool is_obj_proxy)
+{
+ if (!is_never_null) {
+ *id_ptr = new_id;
+ DEG_id_tag_update_ex(id_remap_data->bmain,
+ id_self,
+ ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ if (id_self != id_owner) {
+ DEG_id_tag_update_ex(id_remap_data->bmain,
+ id_owner,
+ ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+ }
+ if (cb_flag & IDWALK_CB_USER) {
+ /* NOTE: by default we don't user-count IDs which are not in the main database.
+ * This is because in certain conditions we can have data-blocks in
+ * the main which are referencing data-blocks outside of it.
+ * For example, BKE_mesh_new_from_object() called on an evaluated
+ * object will cause such situation.
+ */
+ if (force_user_refcount || (old_id->tag & LIB_TAG_NO_MAIN) == 0) {
+ id_us_min(old_id);
+ }
+ if (new_id != NULL && (force_user_refcount || (new_id->tag & LIB_TAG_NO_MAIN) == 0)) {
+ /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
+ new_id->us++;
+ }
+ }
+ else if (cb_flag & IDWALK_CB_USER_ONE) {
+ id_us_ensure_real(new_id);
+ /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET)
+ * are assumed to be set as needed, that extra user is processed in final handling. */
+ }
+ if (!is_indirect || is_obj_proxy) {
+ id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
+ }
+ /* We need to remap proxy_from pointer of remapped proxy... sigh. */
+ if (is_obj_proxy && new_id != NULL) {
+ Object *ob = (Object *)id_owner;
+ if (ob->proxy == (Object *)new_id) {
+ ob->proxy->proxy_from = ob;
+ }
+ }
+}
+
static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
{
const int cb_flag = cb_data->cb_flag;
@@ -116,125 +207,82 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
old_id = *id_p;
}
- if (*id_p && (*id_p == old_id)) {
- /* Better remap to NULL than not remapping at all,
- * then we can handle it as a regular remap-to-NULL case. */
- if ((cb_flag & IDWALK_CB_NEVER_SELF) && (new_id == id_self)) {
- new_id = NULL;
- }
+ /* Early exit when id pointer isn't set to an expected value. */
+ if (*id_p == NULL || *id_p != old_id) {
+ return IDWALK_RET_NOP;
+ }
+
+ /* Better remap to NULL than not remapping at all,
+ * then we can handle it as a regular remap-to-NULL case. */
+ if ((cb_flag & IDWALK_CB_NEVER_SELF) && (new_id == id_self)) {
+ new_id = NULL;
+ }
- const bool is_reference = (cb_flag & IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE) != 0;
- const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
- const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
- /* NOTE: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
- * on the other hand since they get reset to lib data on file open/reload it is indirect too.
- * Edit Mode is also a 'skip direct' case. */
- const bool is_obj = (GS(id_owner->name) == ID_OB);
- const bool is_obj_proxy = (is_obj &&
- (((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group));
- const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner) &&
- (id_remap_data->flag & ID_REMAP_FORCE_OBDATA_IN_EDITMODE) == 0);
- const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
- (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
- const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0;
- const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
- const bool force_user_refcount = (id_remap_data->flag & ID_REMAP_FORCE_USER_REFCOUNT) != 0;
+ const bool is_reference = (cb_flag & IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE) != 0;
+ const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
+ const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
+ /* NOTE: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
+ * on the other hand since they get reset to lib data on file open/reload it is indirect too.
+ * Edit Mode is also a 'skip direct' case. */
+ const bool is_obj = (GS(id_owner->name) == ID_OB);
+ const bool is_obj_proxy = (is_obj &&
+ (((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group));
+ const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner) &&
+ (id_remap_data->flag & ID_REMAP_FORCE_OBDATA_IN_EDITMODE) == 0);
+ const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
+ (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
+ const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0;
+ const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
+ const bool force_user_refcount = (id_remap_data->flag & ID_REMAP_FORCE_USER_REFCOUNT) != 0;
#ifdef DEBUG_PRINT
- printf(
- "In %s (lib %p): Remapping %s (%p) to %s (%p) "
- "(is_indirect: %d, skip_indirect: %d, is_reference: %d, skip_reference: %d)\n",
- id->name,
- id->lib,
- old_id->name,
- old_id,
- new_id ? new_id->name : "<NONE>",
- new_id,
- is_indirect,
- skip_indirect,
- is_reference,
- skip_reference);
+ printf(
+ "In %s (lib %p): Remapping %s (%p) to %s (%p) "
+ "(is_indirect: %d, skip_indirect: %d, is_reference: %d, skip_reference: %d)\n",
+ id->name,
+ id->lib,
+ old_id->name,
+ old_id,
+ new_id ? new_id->name : "<NONE>",
+ new_id,
+ is_indirect,
+ skip_indirect,
+ is_reference,
+ skip_reference);
#endif
- if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) &&
- (cb_flag & IDWALK_CB_NEVER_NULL)) {
- id_owner->tag |= LIB_TAG_DOIT;
- }
+ if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) {
+ id_owner->tag |= LIB_TAG_DOIT;
+ }
- /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL
- * (otherwise, we follow common NEVER_NULL flags).
- * (skipped_indirect too). */
- if ((is_never_null && skip_never_null) ||
- (is_obj_editmode && (((Object *)id_owner)->data == *id_p) && new_id != NULL) ||
- (skip_indirect && is_indirect) || (is_reference && skip_reference)) {
- if (is_indirect) {
- id_remap_data->skipped_indirect++;
- if (is_obj) {
- Object *ob = (Object *)id_owner;
- if (ob->data == *id_p && ob->proxy != NULL) {
- /* And another 'Proudly brought to you by Proxy Hell' hack!
- * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */
- id_remap_data->skipped_direct++;
- }
- }
- }
- else if (is_never_null || is_obj_editmode || is_reference) {
- id_remap_data->skipped_direct++;
- }
- else {
- BLI_assert(0);
- }
- if (cb_flag & IDWALK_CB_USER) {
- id_remap_data->skipped_refcounted++;
- }
- else if (cb_flag & IDWALK_CB_USER_ONE) {
- /* No need to count number of times this happens, just a flag is enough. */
- id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED;
- }
- }
- else {
- if (!is_never_null) {
- *id_p = new_id;
- DEG_id_tag_update_ex(id_remap_data->bmain,
- id_self,
- ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- if (id_self != id_owner) {
- DEG_id_tag_update_ex(id_remap_data->bmain,
- id_owner,
- ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
- }
- }
- if (cb_flag & IDWALK_CB_USER) {
- /* NOTE: by default we don't user-count IDs which are not in the main database.
- * This is because in certain conditions we can have data-blocks in
- * the main which are referencing data-blocks outside of it.
- * For example, BKE_mesh_new_from_object() called on an evaluated
- * object will cause such situation.
- */
- if (force_user_refcount || (old_id->tag & LIB_TAG_NO_MAIN) == 0) {
- id_us_min(old_id);
- }
- if (new_id != NULL && (force_user_refcount || (new_id->tag & LIB_TAG_NO_MAIN) == 0)) {
- /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */
- new_id->us++;
- }
- }
- else if (cb_flag & IDWALK_CB_USER_ONE) {
- id_us_ensure_real(new_id);
- /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET)
- * are assumed to be set as needed, that extra user is processed in final handling. */
- }
- if (!is_indirect || is_obj_proxy) {
- id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
- }
- /* We need to remap proxy_from pointer of remapped proxy... sigh. */
- if (is_obj_proxy && new_id != NULL) {
- Object *ob = (Object *)id_owner;
- if (ob->proxy == (Object *)new_id) {
- ob->proxy->proxy_from = ob;
- }
- }
- }
+ /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL
+ * (otherwise, we follow common NEVER_NULL flags).
+ * (skipped_indirect too). */
+ if ((is_never_null && skip_never_null) ||
+ (is_obj_editmode && (((Object *)id_owner)->data == *id_p) && new_id != NULL) ||
+ (skip_indirect && is_indirect) || (is_reference && skip_reference)) {
+ foreach_libblock_remap_callback_skip(id_owner,
+ id_p,
+ id_remap_data,
+ cb_flag,
+ is_indirect,
+ is_reference,
+ is_never_null,
+ is_obj,
+ is_obj_editmode);
+ }
+ else {
+ foreach_libblock_remap_callback_apply(id_owner,
+ id_self,
+ old_id,
+ new_id,
+ id_p,
+ id_remap_data,
+ cb_flag,
+ is_indirect,
+ is_never_null,
+ force_user_refcount,
+ is_obj_proxy);
}
return IDWALK_RET_NOP;
@@ -282,6 +330,11 @@ static void libblock_remap_data_postprocess_object_update(Main *bmain,
* to remove the NULL children from collections not used in any scene. */
BKE_collections_object_remove_nulls(bmain);
}
+ else {
+ /* Remapping may have created duplicates of CollectionObject pointing to the same object within
+ * the same collection. */
+ BKE_collections_object_remove_duplicates(bmain);
+ }
BKE_main_collection_sync_remap(bmain);
@@ -319,6 +372,7 @@ static void libblock_remap_data_postprocess_collection_update(Main *bmain,
else {
/* Temp safe fix, but a "tad" brute force... We should probably be able to use parents from
* old_collection instead? */
+ /* NOTE: Also takes care of duplicated child collections that remapping may have created. */
BKE_main_collections_parent_relations_rebuild(bmain);
}
@@ -346,7 +400,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
{
/* Update all group nodes using a node group. */
- ntreeUpdateAllUsers(bmain, new_id, 0);
+ ntreeUpdateAllUsers(bmain, new_id);
}
/**
@@ -456,11 +510,18 @@ static void libblock_remap_data(
#endif
}
-void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
+typedef struct LibblockRemapMultipleUserData {
+ Main *bmain;
+ short remap_flags;
+} LibBlockRemapMultipleUserData;
+
+static void libblock_remap_foreach_idpair_cb(ID *old_id, ID *new_id, void *user_data)
{
+ LibBlockRemapMultipleUserData *data = user_data;
+ Main *bmain = data->bmain;
+ const short remap_flags = data->remap_flags;
+
IDRemap id_remap_data;
- ID *old_id = old_idv;
- ID *new_id = new_idv;
int skipped_direct, skipped_refcounted;
BLI_assert(old_id != NULL);
@@ -473,13 +534,6 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
free_notifier_reference_cb(old_id);
}
- /* We assume editors do not hold references to their IDs... This is false in some cases
- * (Image is especially tricky here),
- * editors' code is to handle refcount (id->us) itself then. */
- if (remap_editor_id_reference_cb) {
- remap_editor_id_reference_cb(old_id, new_id);
- }
-
skipped_direct = id_remap_data.skipped_direct;
skipped_refcounted = id_remap_data.skipped_refcounted;
@@ -552,6 +606,41 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
DEG_relations_tag_update(bmain);
}
+void BKE_libblock_remap_multiple_locked(Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags)
+{
+ if (BKE_id_remapper_is_empty(mappings)) {
+ /* Early exit nothing to do. */
+ return;
+ }
+
+ LibBlockRemapMultipleUserData user_data;
+ user_data.bmain = bmain;
+ user_data.remap_flags = remap_flags;
+ BKE_id_remapper_iter(mappings, libblock_remap_foreach_idpair_cb, &user_data);
+
+ /* We assume editors do not hold references to their IDs... This is false in some cases
+ * (Image is especially tricky here),
+ * editors' code is to handle refcount (id->us) itself then. */
+ if (remap_editor_id_reference_cb) {
+ remap_editor_id_reference_cb(mappings);
+ }
+
+ /* Full rebuild of DEG! */
+ DEG_relations_tag_update(bmain);
+}
+
+void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
+{
+ struct IDRemapper *remapper = BKE_id_remapper_create();
+ ID *old_id = old_idv;
+ ID *new_id = new_idv;
+ BKE_id_remapper_add(remapper, old_id, new_id);
+ BKE_libblock_remap_multiple_locked(bmain, remapper, remap_flags);
+ BKE_id_remapper_free(remapper);
+}
+
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
{
BKE_main_lock(bmain);
@@ -561,6 +650,17 @@ void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short r
BKE_main_unlock(bmain);
}
+void BKE_libblock_remap_multiple(Main *bmain,
+ const struct IDRemapper *mappings,
+ const short remap_flags)
+{
+ BKE_main_lock(bmain);
+
+ BKE_libblock_remap_multiple_locked(bmain, mappings, remap_flags);
+
+ BKE_main_unlock(bmain);
+}
+
void BKE_libblock_unlink(Main *bmain,
void *idv,
const bool do_flag_never_null,
diff --git a/source/blender/blenkernel/intern/lib_remap_test.cc b/source/blender/blenkernel/intern/lib_remap_test.cc
new file mode 100644
index 00000000000..266ada3663d
--- /dev/null
+++ b/source/blender/blenkernel/intern/lib_remap_test.cc
@@ -0,0 +1,369 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2022 by Blender Foundation.
+ */
+#include "testing/testing.h"
+
+#include "BLI_utildefines.h"
+
+#include "CLG_log.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "RNA_define.h"
+
+#include "BKE_appdir.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+
+#include "IMB_imbuf.h"
+
+#include "ED_node.h"
+
+#include "MEM_guardedalloc.h"
+
+namespace blender::bke::tests {
+
+class TestData {
+ public:
+ Main *bmain = nullptr;
+ struct bContext *C = nullptr;
+
+ virtual void setup()
+ {
+ if (bmain == nullptr) {
+ bmain = BKE_main_new();
+ G.main = bmain;
+ }
+
+ if (C == nullptr) {
+ C = CTX_create();
+ CTX_data_main_set(C, bmain);
+ }
+ }
+
+ virtual void teardown()
+ {
+ if (bmain != nullptr) {
+ BKE_main_free(bmain);
+ bmain = nullptr;
+ G.main = nullptr;
+ }
+
+ if (C != nullptr) {
+ CTX_free(C);
+ C = nullptr;
+ }
+ }
+};
+
+class SceneTestData : public TestData {
+ public:
+ Scene *scene = nullptr;
+ void setup() override
+ {
+ TestData::setup();
+ scene = BKE_scene_add(bmain, "IDRemapScene");
+ CTX_data_scene_set(C, scene);
+ }
+};
+
+class CompositorTestData : public SceneTestData {
+ public:
+ bNodeTree *compositor_nodetree = nullptr;
+ void setup() override
+ {
+ SceneTestData::setup();
+ ED_node_composit_default(C, scene);
+ compositor_nodetree = scene->nodetree;
+ }
+};
+
+class MeshTestData : public TestData {
+ public:
+ Mesh *mesh = nullptr;
+
+ void setup() override
+ {
+ TestData::setup();
+ mesh = BKE_mesh_add(bmain, nullptr);
+ }
+};
+
+class TwoMeshesTestData : public MeshTestData {
+ public:
+ Mesh *other_mesh = nullptr;
+
+ void setup() override
+ {
+ MeshTestData::setup();
+ other_mesh = BKE_mesh_add(bmain, nullptr);
+ }
+};
+
+class MeshObjectTestData : public MeshTestData {
+ public:
+ Object *object;
+ void setup() override
+ {
+ MeshTestData::setup();
+
+ object = BKE_object_add_only_object(bmain, OB_MESH, nullptr);
+ object->data = mesh;
+ }
+};
+
+template<typename TestData> class Context {
+ public:
+ TestData test_data;
+
+ Context()
+ {
+ CLG_init();
+ BKE_idtype_init();
+ RNA_init();
+ BKE_node_system_init();
+ BKE_appdir_init();
+ IMB_init();
+
+ test_data.setup();
+ }
+
+ ~Context()
+ {
+ test_data.teardown();
+
+ BKE_node_system_exit();
+ RNA_exit();
+ IMB_exit();
+ BKE_appdir_exit();
+ CLG_exit();
+ }
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Embedded IDs
+ * \{ */
+
+TEST(lib_remap, embedded_ids_can_not_be_remapped)
+{
+ Context<CompositorTestData> context;
+ bNodeTree *other_tree = static_cast<bNodeTree *>(BKE_id_new_nomain(ID_NT, nullptr));
+
+ EXPECT_NE(context.test_data.scene, nullptr);
+ EXPECT_NE(context.test_data.compositor_nodetree, nullptr);
+ EXPECT_EQ(context.test_data.compositor_nodetree, context.test_data.scene->nodetree);
+
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.compositor_nodetree, other_tree, 0);
+
+ EXPECT_EQ(context.test_data.compositor_nodetree, context.test_data.scene->nodetree);
+ EXPECT_NE(context.test_data.scene->nodetree, other_tree);
+
+ BKE_id_free(nullptr, other_tree);
+}
+
+TEST(lib_remap, embedded_ids_can_not_be_deleted)
+{
+ Context<CompositorTestData> context;
+
+ EXPECT_NE(context.test_data.scene, nullptr);
+ EXPECT_NE(context.test_data.compositor_nodetree, nullptr);
+ EXPECT_EQ(context.test_data.compositor_nodetree, context.test_data.scene->nodetree);
+
+ BKE_libblock_remap(context.test_data.bmain,
+ context.test_data.compositor_nodetree,
+ nullptr,
+ ID_REMAP_SKIP_NEVER_NULL_USAGE);
+
+ EXPECT_EQ(context.test_data.compositor_nodetree, context.test_data.scene->nodetree);
+ EXPECT_NE(context.test_data.scene->nodetree, nullptr);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remap to self
+ * \{ */
+
+TEST(lib_remap, delete_when_remap_to_self_not_allowed)
+{
+ Context<TwoMeshesTestData> context;
+
+ EXPECT_NE(context.test_data.mesh, nullptr);
+ EXPECT_NE(context.test_data.other_mesh, nullptr);
+ context.test_data.mesh->texcomesh = context.test_data.other_mesh;
+
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.other_mesh, context.test_data.mesh, 0);
+
+ EXPECT_EQ(context.test_data.mesh->texcomesh, nullptr);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name User Reference Counting
+ * \{ */
+
+TEST(lib_remap, users_are_decreased_when_not_skipping_never_null)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+ EXPECT_EQ(context.test_data.mesh->id.us, 1);
+
+ /* This is an invalid situation, test case tests this in between value until we have a better
+ * solution. */
+ BKE_libblock_remap(context.test_data.bmain, context.test_data.mesh, nullptr, 0);
+ EXPECT_EQ(context.test_data.mesh->id.us, 0);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_NE(context.test_data.object->data, nullptr);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+}
+
+TEST(lib_remap, users_are_same_when_skipping_never_null)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+ EXPECT_EQ(context.test_data.mesh->id.us, 1);
+
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.mesh, nullptr, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.mesh->id.us, 1);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_NE(context.test_data.object->data, nullptr);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Never Null
+ * \{ */
+
+TEST(lib_remap, do_not_delete_when_cannot_unset)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.mesh, nullptr, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_NE(context.test_data.object->data, nullptr);
+}
+
+TEST(lib_remap, force_never_null_usage)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.mesh, nullptr, ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, nullptr);
+}
+
+TEST(lib_remap, never_null_usage_flag_not_requested_on_delete)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+
+ /* Never null usage isn't requested so the flag should not be set. */
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.mesh, nullptr, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_NE(context.test_data.object->data, nullptr);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+}
+
+TEST(lib_remap, never_null_usage_flag_requested_on_delete)
+{
+ Context<MeshObjectTestData> context;
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+
+ /* Never null usage is requested so the flag should be set. */
+ BKE_libblock_remap(context.test_data.bmain,
+ context.test_data.mesh,
+ nullptr,
+ ID_REMAP_SKIP_NEVER_NULL_USAGE | ID_REMAP_FLAG_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_NE(context.test_data.object->data, nullptr);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, LIB_TAG_DOIT);
+}
+
+TEST(lib_remap, never_null_usage_flag_not_requested_on_remap)
+{
+ Context<MeshObjectTestData> context;
+ Mesh *other_mesh = BKE_mesh_add(context.test_data.bmain, nullptr);
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+
+ /* Never null usage isn't requested so the flag should not be set. */
+ BKE_libblock_remap(
+ context.test_data.bmain, context.test_data.mesh, other_mesh, ID_REMAP_SKIP_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, other_mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+}
+
+TEST(lib_remap, never_null_usage_flag_requested_on_remap)
+{
+ Context<MeshObjectTestData> context;
+ Mesh *other_mesh = BKE_mesh_add(context.test_data.bmain, nullptr);
+
+ EXPECT_NE(context.test_data.object, nullptr);
+ EXPECT_EQ(context.test_data.object->data, context.test_data.mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, 0);
+
+ /* Never null usage is requested so the flag should be set. */
+ BKE_libblock_remap(context.test_data.bmain,
+ context.test_data.mesh,
+ other_mesh,
+ ID_REMAP_SKIP_NEVER_NULL_USAGE | ID_REMAP_FLAG_NEVER_NULL_USAGE);
+ EXPECT_EQ(context.test_data.object->data, other_mesh);
+ EXPECT_EQ(context.test_data.object->id.tag & LIB_TAG_DOIT, LIB_TAG_DOIT);
+}
+
+/** \} */
+
+} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index ac0dbcb715d..95f41ab4b39 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -50,6 +50,7 @@
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_texture.h"
#include "BLO_read_write.h"
@@ -2085,5 +2086,5 @@ void BKE_linestyle_default_shader(const bContext *C, FreestyleLineStyle *linesty
tosock = BLI_findlink(&output_linestyle->inputs, 0); /* Color */
nodeAddLink(ntree, input_texure, fromsock, output_linestyle, tosock);
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), ntree, NULL);
}
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 6f498c5c9e7..12bbab57cf2 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -38,6 +38,7 @@
#include "BLT_translation.h"
+#include "DNA_defaults.h"
#include "DNA_mask_types.h"
#include "BKE_animsys.h"
@@ -1308,7 +1309,7 @@ void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point,
MovieTrackingObject *ob = BKE_tracking_object_get_named(tracking, parent->parent);
if (ob) {
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
float clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
BKE_movieclip_user_set_frame(&user, ctime);
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index d6035887790..15469f910b4 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -720,8 +720,9 @@ static ID *get_evaluated_object_data_with_materials(Object *ob)
/* Meshes in edit mode need special handling. */
if (ob->type == OB_MESH && ob->mode == OB_MODE_EDIT) {
Mesh *mesh = ob->data;
- if (mesh->edit_mesh && mesh->edit_mesh->mesh_eval_final) {
- data = &mesh->edit_mesh->mesh_eval_final->id;
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
+ if (mesh->edit_mesh && editmesh_eval_final) {
+ data = &editmesh_eval_final->id;
}
}
return data;
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 05aa9111fa3..73fe279552d 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -38,11 +38,14 @@
#include "BLI_endian_switch.h"
#include "BLI_ghash.h"
#include "BLI_hash.h"
+#include "BLI_index_range.hh"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_memarena.h"
#include "BLI_string.h"
+#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -91,6 +94,10 @@ static void mesh_init_data(ID *id)
BKE_mesh_runtime_init_data(mesh);
+ /* A newly created mesh does not have normals, so tag them dirty. This will be cleared
+ * by #BKE_mesh_vertex_normals_clear_dirty or #BKE_mesh_poly_normals_ensure. */
+ BKE_mesh_normals_tag_dirty(mesh);
+
mesh->face_sets_color_seed = BLI_hash_int(PIL_check_seconds_timer_i() & UINT_MAX);
}
@@ -143,16 +150,40 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
BKE_mesh_update_customdata_pointers(mesh_dst, do_tessface);
+ mesh_dst->cd_flag = mesh_src->cd_flag;
+
mesh_dst->edit_mesh = nullptr;
mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect);
+ /* Set normal layers dirty, since they aren't included in CD_MASK_MESH and are therefore not
+ * copied to the destination mesh. Alternatively normal layers could be copied if they aren't
+ * dirty, avoiding recomputation in some cases. However, a copied mesh is often changed anyway,
+ * so that idea is not clearly better. With proper reference counting, all custom data layers
+ * could be copied as the cost would be much lower. */
+ BKE_mesh_normals_tag_dirty(mesh_dst);
+
/* TODO: Do we want to add flag to prevent this? */
if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &mesh_src->key->id, (ID **)&mesh_dst->key, flag);
/* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */
mesh_dst->key->from = &mesh_dst->id;
}
+
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh_dst);
+}
+
+void BKE_mesh_free_editmesh(struct Mesh *mesh)
+{
+ if (mesh->edit_mesh == nullptr) {
+ return;
+ }
+
+ if (mesh->edit_mesh->is_shallow_copy == false) {
+ BKE_editmesh_free_data(mesh->edit_mesh);
+ }
+ MEM_freeN(mesh->edit_mesh);
+ mesh->edit_mesh = nullptr;
}
static void mesh_free_data(ID *id)
@@ -161,13 +192,7 @@ static void mesh_free_data(ID *id)
BLI_freelistN(&mesh->vertex_group_names);
- if (mesh->edit_mesh) {
- if (mesh->edit_mesh->is_shallow_copy == false) {
- BKE_editmesh_free_data(mesh->edit_mesh);
- }
- MEM_freeN(mesh->edit_mesh);
- mesh->edit_mesh = nullptr;
- }
+ BKE_mesh_free_editmesh(mesh);
BKE_mesh_runtime_free_data(mesh);
mesh_clear_geometry(mesh);
@@ -332,6 +357,10 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
BLI_endian_switch_uint32_array(tf->col, 4);
}
}
+
+ /* We don't expect to load normals from files, since they are derived data. */
+ BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
}
static void mesh_blend_read_lib(BlendLibReader *reader, ID *id)
@@ -453,14 +482,14 @@ static int customdata_compare(
for (int i = 0; i < c1->totlayer; i++) {
l1 = &c1->layers[i];
- if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l1->anonymous_id != nullptr) {
+ if ((CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr) && l1->anonymous_id == nullptr) {
layer_count1++;
}
}
for (int i = 0; i < c2->totlayer; i++) {
l2 = &c2->layers[i];
- if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l2->anonymous_id != nullptr) {
+ if ((CD_TYPE_AS_MASK(l2->type) & cd_mask_all_attr) && l2->anonymous_id == nullptr) {
layer_count2++;
}
}
@@ -1033,6 +1062,8 @@ void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
BKE_mesh_copy_parameters(me_dst, me_src);
+ BKE_mesh_assert_normals_dirty_or_calculated(me_dst);
+
/* Copy vertex group names. */
BLI_assert(BLI_listbase_is_empty(&me_dst->vertex_group_names));
BKE_defgroup_copy_list(&me_dst->vertex_group_names, &me_src->vertex_group_names);
@@ -1080,6 +1111,18 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
mesh_tessface_clear_intern(me_dst, false);
}
+ me_dst->runtime.cd_dirty_poly = me_src->runtime.cd_dirty_poly;
+ me_dst->runtime.cd_dirty_vert = me_src->runtime.cd_dirty_vert;
+
+ /* Ensure that when no normal layers exist, they are marked dirty, because
+ * normals might not have been included in the mask of copied layers. */
+ if (!CustomData_has_layer(&me_dst->vdata, CD_NORMAL)) {
+ me_dst->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+ if (!CustomData_has_layer(&me_dst->pdata, CD_NORMAL)) {
+ me_dst->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
+ }
+
/* The destination mesh should at least have valid primary CD layers,
* even in cases where the source mesh does not. */
mesh_ensure_cdlayers_primary(me_dst, do_tessface);
@@ -1577,13 +1620,35 @@ void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri,
bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3])
{
- int i = me->totvert;
- MVert *mvert;
- for (mvert = me->mvert; i--; mvert++) {
- minmax_v3v3_v3(r_min, r_max, mvert->co);
+ using namespace blender;
+ if (me->totvert == 0) {
+ return false;
}
- return (me->totvert != 0);
+ struct Result {
+ float3 min;
+ float3 max;
+ };
+
+ const Result minmax = threading::parallel_reduce(
+ IndexRange(me->totvert),
+ 1024,
+ Result{float3(FLT_MAX), float3(-FLT_MAX)},
+ [&](IndexRange range, const Result &init) {
+ Result result = init;
+ for (const int i : range) {
+ math::min_max(float3(me->mvert[i].co), result.min, result.max);
+ }
+ return result;
+ },
+ [](const Result &a, const Result &b) {
+ return Result{math::min(a.min, b.min), math::max(a.max, b.max)};
+ });
+
+ copy_v3_v3(r_min, math::min(minmax.min, float3(r_min)));
+ copy_v3_v3(r_max, math::max(minmax.max, float3(r_max)));
+
+ return true;
}
void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys)
@@ -1857,24 +1922,10 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
BKE_mesh_normals_tag_dirty(mesh);
}
-void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3])
-{
- /* This will just return the pointer if it wasn't a referenced layer. */
- MVert *mv = (MVert *)CustomData_duplicate_referenced_layer(
- &mesh->vdata, CD_MVERT, mesh->totvert);
- mesh->mvert = mv;
- for (int i = 0; i < mesh->totvert; i++, mv++) {
- copy_v3_v3_short(mv->no, vert_normals[i]);
- }
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
-}
-
void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
{
float(*r_loopnors)[3];
- float(*polynors)[3];
short(*clnors)[2] = nullptr;
- bool free_polynors = false;
/* Note that we enforce computing clnors when the clnor space array is requested by caller here.
* However, we obviously only use the auto-smooth angle threshold
@@ -1896,26 +1947,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
/* may be nullptr */
clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
- if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
- /* This assume that layer is always up to date, not sure this is the case
- * (esp. in Edit mode?)... */
- polynors = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- free_polynors = false;
- }
- else {
- polynors = (float(*)[3])MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- polynors,
- nullptr);
- free_polynors = true;
- }
-
BKE_mesh_normals_loop_split(mesh->mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
mesh->totvert,
mesh->medge,
mesh->totedge,
@@ -1923,7 +1956,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
r_loopnors,
mesh->totloop,
mesh->mpoly,
- (const float(*)[3])polynors,
+ BKE_mesh_poly_normals_ensure(mesh),
mesh->totpoly,
use_split_normals,
split_angle,
@@ -1931,12 +1964,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
clnors,
nullptr);
- if (free_polynors) {
- MEM_freeN(polynors);
- }
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
- mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
mesh->runtime.cd_dirty_loop &= ~CD_MASK_NORMAL;
}
@@ -1964,7 +1993,7 @@ struct SplitFaceNewEdge {
/* Detect needed new vertices, and update accordingly loops' vertex indices.
* WARNING! Leaves mesh in invalid state. */
-static int split_faces_prepare_new_verts(const Mesh *mesh,
+static int split_faces_prepare_new_verts(Mesh *mesh,
MLoopNorSpaceArray *lnors_spacearr,
SplitFaceNewVert **new_verts,
MemArena *memarena)
@@ -1976,8 +2005,9 @@ static int split_faces_prepare_new_verts(const Mesh *mesh,
const int loops_len = mesh->totloop;
int verts_len = mesh->totvert;
- MVert *mvert = mesh->mvert;
MLoop *mloop = mesh->mloop;
+ BKE_mesh_vertex_normals_ensure(mesh);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__);
BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__);
@@ -2021,7 +2051,7 @@ static int split_faces_prepare_new_verts(const Mesh *mesh,
* vnor should always be defined to 'automatic normal' value computed from its polys,
* not some custom normal.
* Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
- normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
+ copy_v3_v3(vert_normals[vert_idx], (*lnor_space)->vec_lnor);
}
else {
/* Add new vert to list. */
@@ -2112,6 +2142,7 @@ static void split_faces_split_new_verts(Mesh *mesh,
{
const int verts_len = mesh->totvert - num_new_verts;
MVert *mvert = mesh->mvert;
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
/* Remember new_verts is a single linklist, so its items are in reversed order... */
MVert *new_mv = &mvert[mesh->totvert - 1];
@@ -2120,9 +2151,10 @@ static void split_faces_split_new_verts(Mesh *mesh,
BLI_assert(new_verts->new_index != new_verts->orig_index);
CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
if (new_verts->vnor) {
- normal_float_to_short_v3(new_mv->no, new_verts->vnor);
+ copy_v3_v3(vert_normals[i], new_verts->vnor);
}
}
+ BKE_mesh_vertex_normals_clear_dirty(mesh);
}
/* Perform actual split of edges. */
@@ -2210,6 +2242,7 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
/* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
BKE_lnor_spacearr_free(&lnors_spacearr);
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
#ifdef VALIDATE_MESH
BKE_mesh_validate(mesh, true, true);
#endif
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index 771d79a0445..a4a5fe2be2e 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -32,9 +32,9 @@
#include "BLI_alloca.h"
#include "BLI_array.hh"
-#include "BLI_float2.hh"
#include "BLI_float4x4.hh"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_mesh_boolean.hh"
#include "BLI_mesh_intersect.hh"
#include "BLI_span.hh"
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index e8054884f26..7d5f156040d 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -32,6 +32,7 @@
#include "DNA_scene_types.h"
#include "BLI_edgehash.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -65,6 +66,8 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+using blender::IndexRange;
+
/* Define for cases when you want extra validation of mesh
* after certain modifications.
*/
@@ -85,7 +88,6 @@ void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
MVert *mvert;
MLoop *mloop, *allloop;
MPoly *mpoly;
- const float *nors, *verts;
int a, *index;
dl = (DispList *)lb->first;
@@ -104,15 +106,8 @@ void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
me->totvert = dl->nr;
me->totpoly = dl->parts;
- a = dl->nr;
- nors = dl->nors;
- verts = dl->verts;
- while (a--) {
- copy_v3_v3(mvert->co, verts);
- normal_float_to_short_v3(mvert->no, nors);
- mvert++;
- nors += 3;
- verts += 3;
+ for (const int i : IndexRange(dl->nr)) {
+ copy_v3_v3(me->mvert[i].co, &dl->verts[3 * i]);
}
a = dl->parts;
@@ -139,7 +134,7 @@ void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
BKE_mesh_update_customdata_pointers(me, true);
- BKE_mesh_calc_normals(me);
+ BKE_mesh_normals_tag_dirty(me);
BKE_mesh_calc_edges(me, true, false);
}
@@ -589,14 +584,14 @@ struct VertLink {
static void prependPolyLineVert(ListBase *lb, uint index)
{
- VertLink *vl = (VertLink *)MEM_callocN(sizeof(VertLink), "VertLink");
+ VertLink *vl = MEM_cnew<VertLink>("VertLink");
vl->index = index;
BLI_addhead(lb, vl);
}
static void appendPolyLineVert(ListBase *lb, uint index)
{
- VertLink *vl = (VertLink *)MEM_callocN(sizeof(VertLink), "VertLink");
+ VertLink *vl = MEM_cnew<VertLink>("VertLink");
vl->index = index;
BLI_addtail(lb, vl);
}
@@ -632,7 +627,7 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
med = medge;
for (i = 0; i < medge_len; i++, med++) {
if (edge_users[i] == edge_users_test) {
- EdgeLink *edl = (EdgeLink *)MEM_callocN(sizeof(EdgeLink), "EdgeLink");
+ EdgeLink *edl = MEM_cnew<EdgeLink>("EdgeLink");
edl->edge = med;
BLI_addtail(&edges, edl);
@@ -719,7 +714,7 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
VertLink *vl;
/* create new 'nurb' within the curve */
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "MeshNurb");
+ nu = MEM_cnew<Nurb>("MeshNurb");
nu->pntsu = totpoly;
nu->pntsv = 1;
@@ -901,6 +896,20 @@ static Object *object_for_curve_to_mesh_create(const Object *object)
return temp_object;
}
+static void object_for_curve_to_mesh_free(Object *temp_object)
+{
+ /* Clear edit mode pointers that were explicitly copied to the temporary curve. */
+ ID *final_object_data = static_cast<ID *>(temp_object->data);
+ if (GS(final_object_data->name) == ID_CU) {
+ Curve &curve = *reinterpret_cast<Curve *>(final_object_data);
+ curve.editfont = nullptr;
+ curve.editnurb = nullptr;
+ }
+
+ BKE_id_free(nullptr, temp_object->data);
+ BKE_id_free(nullptr, temp_object);
+}
+
/**
* Populate `object->runtime.curve_cache` which is then used to create the mesh.
*/
@@ -917,7 +926,7 @@ static void curve_to_mesh_eval_ensure(Object &object)
* will have no modifiers. */
Object bevel_object = {{nullptr}};
if (curve.bevobj != nullptr) {
- bevel_object = *curve.bevobj;
+ memcpy(&bevel_object, curve.bevobj, sizeof(bevel_object));
BLI_listbase_clear(&bevel_object.modifiers);
BKE_object_runtime_reset(&bevel_object);
curve.bevobj = &bevel_object;
@@ -926,7 +935,7 @@ static void curve_to_mesh_eval_ensure(Object &object)
/* Same thing for taper. */
Object taper_object = {{nullptr}};
if (curve.taperobj != nullptr) {
- taper_object = *curve.taperobj;
+ memcpy(&taper_object, curve.taperobj, sizeof(taper_object));
BLI_listbase_clear(&taper_object.modifiers);
BKE_object_runtime_reset(&taper_object);
curve.taperobj = &taper_object;
@@ -1003,8 +1012,7 @@ static Mesh *mesh_new_from_curve_type_object(const Object *object)
Mesh *mesh = mesh_new_from_evaluated_curve_type_object(temp_object);
- BKE_id_free(nullptr, temp_object->data);
- BKE_id_free(nullptr, temp_object);
+ object_for_curve_to_mesh_free(temp_object);
return mesh;
}
@@ -1065,7 +1073,8 @@ static Mesh *mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph,
return nullptr;
}
- Object object_for_eval = *object;
+ Object object_for_eval;
+ memcpy(&object_for_eval, object, sizeof(object_for_eval));
if (object_for_eval.runtime.data_orig != nullptr) {
object_for_eval.data = object_for_eval.runtime.data_orig;
}
@@ -1093,8 +1102,11 @@ static Mesh *mesh_new_from_mesh_object(Depsgraph *depsgraph,
Mesh *mesh_input = (Mesh *)object->data;
/* If we are in edit mode, use evaluated mesh from edit structure, matching to what
* viewport is using for visualization. */
- if (mesh_input->edit_mesh != nullptr && mesh_input->edit_mesh->mesh_eval_final) {
- mesh_input = mesh_input->edit_mesh->mesh_eval_final;
+ if (mesh_input->edit_mesh != nullptr) {
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
+ if (editmesh_eval_final != nullptr) {
+ mesh_input = editmesh_eval_final;
+ }
}
return mesh_new_from_mesh(object, mesh_input);
}
@@ -1440,7 +1452,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
/* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
/* TODO(Sybren): the above claim came from 2.7x derived-mesh code (DM_to_mesh);
* check whether it is still true with Mesh */
- Mesh tmp = *mesh_dst;
+ Mesh tmp;
+ memcpy(&tmp, mesh_dst, sizeof(tmp));
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
bool did_shapekeys = false;
eCDAllocType alloctype = CD_DUPLICATE;
@@ -1461,8 +1474,6 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
CustomData_reset(&tmp.ldata);
CustomData_reset(&tmp.pdata);
- BKE_mesh_ensure_normals(mesh_src);
-
totvert = tmp.totvert = mesh_src->totvert;
totedge = tmp.totedge = mesh_src->totedge;
totloop = tmp.totloop = mesh_src->totloop;
@@ -1476,6 +1487,18 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
tmp.cd_flag = mesh_src->cd_flag;
tmp.runtime.deformed_only = mesh_src->runtime.deformed_only;
+ tmp.runtime.cd_dirty_poly = mesh_src->runtime.cd_dirty_poly;
+ tmp.runtime.cd_dirty_vert = mesh_src->runtime.cd_dirty_vert;
+
+ /* Ensure that when no normal layers exist, they are marked dirty, because
+ * normals might not have been included in the mask of copied layers. */
+ if (!CustomData_has_layer(&tmp.vdata, CD_NORMAL)) {
+ tmp.runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+ if (!CustomData_has_layer(&tmp.pdata, CD_NORMAL)) {
+ tmp.runtime.cd_dirty_poly |= CD_MASK_NORMAL;
+ }
+
if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) {
KeyBlock *kb;
int uid;
@@ -1599,6 +1622,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
}
BKE_id_free(nullptr, mesh_src);
}
+
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh_dst);
}
void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
diff --git a/source/blender/blenkernel/intern/mesh_debug.cc b/source/blender/blenkernel/intern/mesh_debug.cc
new file mode 100644
index 00000000000..017f96c2ece
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_debug.cc
@@ -0,0 +1,115 @@
+/*
+ * 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
+ *
+ * Evaluated mesh info printing function, to help track down differences output.
+ *
+ * Output from these functions can be evaluated as Python literals.
+ * See `bmesh_debug.c` for the equivalent #BMesh functionality.
+ */
+
+#ifndef NDEBUG
+
+# include <stdio.h>
+
+# include "MEM_guardedalloc.h"
+
+# include "DNA_mesh_types.h"
+# include "DNA_meshdata_types.h"
+# include "DNA_object_types.h"
+
+# include "BLI_utildefines.h"
+
+# include "BKE_customdata.h"
+
+# include "BKE_mesh.h"
+
+# include "BLI_dynstr.h"
+
+static void mesh_debug_info_from_cd_flag(const Mesh *me, DynStr *dynstr)
+{
+ BLI_dynstr_append(dynstr, "'cd_flag': {");
+ if (me->cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
+ BLI_dynstr_append(dynstr, "'VERT_BWEIGHT', ");
+ }
+ if (me->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
+ BLI_dynstr_append(dynstr, "'EDGE_BWEIGHT', ");
+ }
+ if (me->cd_flag & ME_CDFLAG_EDGE_CREASE) {
+ BLI_dynstr_append(dynstr, "'EDGE_CREASE', ");
+ }
+ BLI_dynstr_append(dynstr, "},\n");
+}
+
+char *BKE_mesh_debug_info(const Mesh *me)
+{
+ DynStr *dynstr = BLI_dynstr_new();
+ char *ret;
+
+ const char *indent4 = " ";
+ const char *indent8 = " ";
+
+ BLI_dynstr_append(dynstr, "{\n");
+ BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me);
+ BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me->totvert);
+ BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me->totedge);
+ BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me->totface);
+ BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me->totpoly);
+
+ BLI_dynstr_appendf(dynstr, " 'runtime.deformed_only': %d,\n", me->runtime.deformed_only);
+ BLI_dynstr_appendf(dynstr, " 'runtime.is_original': %d,\n", me->runtime.is_original);
+
+ BLI_dynstr_append(dynstr, " 'vert_layers': (\n");
+ CustomData_debug_info_from_layers(&me->vdata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'edge_layers': (\n");
+ CustomData_debug_info_from_layers(&me->edata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'loop_layers': (\n");
+ CustomData_debug_info_from_layers(&me->ldata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'poly_layers': (\n");
+ CustomData_debug_info_from_layers(&me->pdata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'tessface_layers': (\n");
+ CustomData_debug_info_from_layers(&me->fdata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, indent4);
+ mesh_debug_info_from_cd_flag(me, dynstr);
+
+ BLI_dynstr_append(dynstr, "}\n");
+
+ ret = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+ return ret;
+}
+
+void BKE_mesh_debug_print(const Mesh *me)
+{
+ char *str = BKE_mesh_debug_info(me);
+ puts(str);
+ fflush(stdout);
+ MEM_freeN(str);
+}
+
+#endif /* NDEBUG */
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
index 3b6afc1f47a..ff2ac8ecee9 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.c
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -34,14 +34,11 @@
#include "MEM_guardedalloc.h"
-void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
- void (*func)(void *userData,
- int index,
- const float co[3],
- const float no_f[3],
- const short no_s[3]),
- void *userData,
- MeshForeachFlag flag)
+void BKE_mesh_foreach_mapped_vert(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float co[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag)
{
if (mesh->edit_mesh != NULL) {
BMEditMesh *em = mesh->edit_mesh;
@@ -49,7 +46,7 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
BMIter iter;
BMVert *eve;
int i;
- if (mesh->runtime.edit_data->vertexCos != NULL) {
+ if (mesh->runtime.edit_data != NULL && mesh->runtime.edit_data->vertexCos != NULL) {
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
const float(*vertexNos)[3];
if (flag & MESH_FOREACH_USE_NORMAL) {
@@ -61,34 +58,37 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
}
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vertexNos[i] : NULL;
- func(userData, i, vertexCos[i], no, NULL);
+ func(userData, i, vertexCos[i], no);
}
}
else {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? eve->no : NULL;
- func(userData, i, eve->co, no, NULL);
+ func(userData, i, eve->co, no);
}
}
}
else {
const MVert *mv = mesh->mvert;
const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+ const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
+ BKE_mesh_vertex_normals_ensure(mesh) :
+ NULL;
if (index) {
for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : NULL;
const int orig = *index++;
if (orig == ORIGINDEX_NONE) {
continue;
}
- func(userData, orig, mv->co, NULL, no);
+ func(userData, orig, mv->co, no);
}
}
else {
for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
- func(userData, i, mv->co, NULL, no);
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : NULL;
+ func(userData, i, mv->co, no);
}
}
}
@@ -106,7 +106,7 @@ void BKE_mesh_foreach_mapped_edge(
BMIter iter;
BMEdge *eed;
int i;
- if (mesh->runtime.edit_data->vertexCos != NULL) {
+ if (mesh->runtime.edit_data != NULL && mesh->runtime.edit_data->vertexCos != NULL) {
const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
BM_mesh_elem_index_ensure(bm, BM_VERT);
@@ -164,7 +164,8 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
BMIter iter;
BMFace *efa;
- const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ const float(*vertexCos)[3] = mesh->runtime.edit_data ? mesh->runtime.edit_data->vertexCos :
+ NULL;
/* XXX: investigate using EditMesh data. */
const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
@@ -231,7 +232,7 @@ void BKE_mesh_foreach_mapped_face_center(
void *userData,
MeshForeachFlag flag)
{
- if (mesh->edit_mesh != NULL) {
+ if (mesh->edit_mesh != NULL && mesh->runtime.edit_data != NULL) {
BMEditMesh *em = mesh->edit_mesh;
BMesh *bm = em->bm;
const float(*polyCos)[3];
@@ -310,8 +311,9 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
const MPoly *mp = mesh->mpoly;
const MLoop *ml;
const MVert *mv;
- float _no_buf[3];
- float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
+ const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
+ BKE_mesh_vertex_normals_ensure(mesh) :
+ NULL;
const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
if (index) {
@@ -324,10 +326,11 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
for (int j = 0; j < mp->totloop; j++, ml++) {
mv = &mesh->mvert[ml->v];
if (mv->flag & ME_VERT_FACEDOT) {
- if (flag & MESH_FOREACH_USE_NORMAL) {
- normal_short_to_float_v3(no, mv->no);
- }
- func(userData, orig, mv->co, no);
+
+ func(userData,
+ orig,
+ mv->co,
+ (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : NULL);
}
}
}
@@ -338,10 +341,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
for (int j = 0; j < mp->totloop; j++, ml++) {
mv = &mesh->mvert[ml->v];
if (mv->flag & ME_VERT_FACEDOT) {
- if (flag & MESH_FOREACH_USE_NORMAL) {
- normal_short_to_float_v3(no, mv->no);
- }
- func(userData, i, mv->co, no);
+ func(userData, i, mv->co, (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : NULL);
}
}
}
@@ -358,8 +358,7 @@ typedef struct MappedVCosData {
static void get_vertexcos__mapFunc(void *user_data,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data;
diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c
index 0115a70a52a..134a1344f83 100644
--- a/source/blender/blenkernel/intern/mesh_merge.c
+++ b/source/blender/blenkernel/intern/mesh_merge.c
@@ -615,10 +615,18 @@ Mesh *BKE_mesh_merge_verts(Mesh *mesh,
}
/* Copy over data. #CustomData_add_layer can do this, need to look it up. */
- memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert));
- memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge));
- memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop));
- memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly));
+ if (STACK_SIZE(mvert)) {
+ memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert));
+ }
+ if (STACK_SIZE(medge)) {
+ memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge));
+ }
+ if (STACK_SIZE(mloop)) {
+ memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop));
+ }
+ if (STACK_SIZE(mpoly)) {
+ memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly));
+ }
MEM_freeN(mvert);
MEM_freeN(medge);
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index 2d4308945fc..abc0b518d92 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -236,7 +236,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
}
/* Copy custom-data to new geometry,
- * copy from its self because this data may have been created in the checks above. */
+ * copy from itself because this data may have been created in the checks above. */
CustomData_copy_data(&result->vdata, &result->vdata, 0, maxVerts, maxVerts);
CustomData_copy_data(&result->edata, &result->edata, 0, maxEdges, maxEdges);
/* loops are copied later */
@@ -410,7 +410,6 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
CustomData *ldata = &result->ldata;
short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
MLoopNorSpaceArray lnors_spacearr = {NULL};
- float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
/* The transform matrix of a normal must be
* the transpose of inverse of transform matrix of the geometry... */
@@ -420,16 +419,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
/* calculate custom normals into loop_normals, then mirror first half into second half */
- BKE_mesh_calc_normals_poly_and_vertex(result->mvert,
- result->totvert,
- result->mloop,
- totloop,
- result->mpoly,
- totpoly,
- poly_normals,
- NULL);
-
BKE_mesh_normals_loop_split(result->mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
result->totvert,
result->medge,
result->totedge,
@@ -437,7 +428,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
loop_normals,
totloop,
result->mpoly,
- poly_normals,
+ BKE_mesh_poly_normals_ensure(mesh),
totpoly,
true,
mesh->smoothresh,
@@ -463,7 +454,6 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
}
}
- MEM_freeN(poly_normals);
MEM_freeN(loop_normals);
BKE_lnor_spacearr_free(&lnors_spacearr);
}
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index da5b4ccc764..08a17060549 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -38,7 +38,9 @@
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_memarena.h"
+#include "BLI_span.hh"
#include "BLI_stack.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -50,6 +52,8 @@
#include "atomic_ops.h"
+using blender::Span;
+
// #define DEBUG_TIME
#ifdef DEBUG_TIME
@@ -109,6 +113,52 @@ void BKE_mesh_normals_tag_dirty(Mesh *mesh)
mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
}
+float (*BKE_mesh_vertex_normals_for_write(Mesh *mesh))[3]
+{
+ CustomData_duplicate_referenced_layer(&mesh->vdata, CD_NORMAL, mesh->totvert);
+ return (float(*)[3])CustomData_add_layer(
+ &mesh->vdata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totvert);
+}
+
+float (*BKE_mesh_poly_normals_for_write(Mesh *mesh))[3]
+{
+ CustomData_duplicate_referenced_layer(&mesh->pdata, CD_NORMAL, mesh->totpoly);
+ return (float(*)[3])CustomData_add_layer(
+ &mesh->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totpoly);
+}
+
+void BKE_mesh_vertex_normals_clear_dirty(Mesh *mesh)
+{
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
+}
+
+void BKE_mesh_poly_normals_clear_dirty(Mesh *mesh)
+{
+ mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
+}
+
+bool BKE_mesh_vertex_normals_are_dirty(const Mesh *mesh)
+{
+ return mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL;
+}
+
+bool BKE_mesh_poly_normals_are_dirty(const Mesh *mesh)
+{
+ return mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL;
+}
+
+void BKE_mesh_assert_normals_dirty_or_calculated(const Mesh *mesh)
+{
+ if (!(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL)) {
+ BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL) || mesh->totvert == 0);
+ }
+ if (!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL)) {
+ BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) || mesh->totpoly == 0);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -161,8 +211,6 @@ void BKE_mesh_calc_normals_poly(const MVert *mvert,
/* -------------------------------------------------------------------- */
/** \name Mesh Normal Calculation (Polygons & Vertices)
*
- * Implement #BKE_mesh_calc_normals_poly_and_vertex,
- *
* Take care making optimizations to this function as improvements to low-poly
* meshes can slow down high-poly meshes. For details on performance, see D11993.
* \{ */
@@ -253,18 +301,16 @@ static void mesh_calc_normals_poly_and_vertex_finalize_fn(
/* Following Mesh convention; we use vertex coordinate itself for normal in this case. */
normalize_v3_v3(no, mv->co);
}
-
- normal_float_to_short_v3(mv->no, no);
}
-void BKE_mesh_calc_normals_poly_and_vertex(MVert *mvert,
- const int mvert_len,
- const MLoop *mloop,
- const int UNUSED(mloop_len),
- const MPoly *mpoly,
- const int mpoly_len,
- float (*r_poly_normals)[3],
- float (*r_vert_normals)[3])
+static void mesh_calc_normals_poly_and_vertex(MVert *mvert,
+ const int mvert_len,
+ const MLoop *mloop,
+ const int UNUSED(mloop_len),
+ const MPoly *mpoly,
+ const int mpoly_len,
+ float (*r_poly_normals)[3],
+ float (*r_vert_normals)[3])
{
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -308,19 +354,90 @@ void BKE_mesh_calc_normals_poly_and_vertex(MVert *mvert,
/** \name Mesh Normal Calculation
* \{ */
-void BKE_mesh_ensure_normals(Mesh *mesh)
+const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
{
- if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- BKE_mesh_calc_normals(mesh);
+ if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) {
+ BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL) || mesh->totvert == 0);
+ return (const float(*)[3])CustomData_get_layer(&mesh->vdata, CD_NORMAL);
+ }
+
+ if (mesh->totvert == 0) {
+ return nullptr;
+ }
+
+ ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex;
+ BLI_mutex_lock(normals_mutex);
+ if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) {
+ BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL));
+ BLI_mutex_unlock(normals_mutex);
+ return (const float(*)[3])CustomData_get_layer(&mesh->vdata, CD_NORMAL);
}
- BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
+
+ Mesh &mesh_mutable = *const_cast<Mesh *>(mesh);
+
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(&mesh_mutable);
+ float(*poly_normals)[3] = BKE_mesh_poly_normals_for_write(&mesh_mutable);
+
+ mesh_calc_normals_poly_and_vertex(mesh_mutable.mvert,
+ mesh_mutable.totvert,
+ mesh_mutable.mloop,
+ mesh_mutable.totloop,
+ mesh_mutable.mpoly,
+ mesh_mutable.totpoly,
+ poly_normals,
+ vert_normals);
+
+ BKE_mesh_vertex_normals_clear_dirty(&mesh_mutable);
+ BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
+
+ BLI_mutex_unlock(normals_mutex);
+ return vert_normals;
+}
+
+const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3]
+{
+ if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
+ BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) || mesh->totpoly == 0);
+ return (const float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ }
+
+ if (mesh->totpoly == 0) {
+ return nullptr;
+ }
+
+ ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex;
+ BLI_mutex_lock(normals_mutex);
+ if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
+ BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL));
+ BLI_mutex_unlock(normals_mutex);
+ return (const float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ }
+
+ Mesh &mesh_mutable = *const_cast<Mesh *>(mesh);
+
+ float(*poly_normals)[3] = BKE_mesh_poly_normals_for_write(&mesh_mutable);
+
+ BKE_mesh_calc_normals_poly(mesh_mutable.mvert,
+ mesh_mutable.totvert,
+ mesh_mutable.mloop,
+ mesh_mutable.totloop,
+ mesh_mutable.mpoly,
+ mesh_mutable.totpoly,
+ poly_normals);
+
+ BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
+
+ BLI_mutex_unlock(normals_mutex);
+ return poly_normals;
}
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
switch ((eMeshWrapperType)mesh->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
- /* Run code below. */
+ BKE_mesh_vertex_normals_ensure(mesh);
+ BKE_mesh_poly_normals_ensure(mesh);
break;
case ME_WRAPPER_TYPE_BMESH: {
struct BMEditMesh *em = mesh->edit_mesh;
@@ -332,47 +449,6 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
return;
}
}
-
- float(*poly_nors)[3] = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0;
- const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL ||
- poly_nors == nullptr);
-
- if (do_vert_normals || do_poly_normals) {
- const bool do_add_poly_nors_cddata = (poly_nors == nullptr);
- if (do_add_poly_nors_cddata) {
- poly_nors = (float(*)[3])MEM_malloc_arrayN(
- (size_t)mesh->totpoly, sizeof(*poly_nors), __func__);
- }
-
- /* Calculate poly/vert normals. */
- if (do_vert_normals) {
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- poly_nors,
- nullptr);
- }
- else {
- BKE_mesh_calc_normals_poly(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- poly_nors);
- }
-
- if (do_add_poly_nors_cddata) {
- CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
- }
-
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
- mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
- }
}
void BKE_mesh_calc_normals(Mesh *mesh)
@@ -380,18 +456,10 @@ void BKE_mesh_calc_normals(Mesh *mesh)
#ifdef DEBUG_TIME
TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
#endif
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- nullptr,
- nullptr);
+ BKE_mesh_vertex_normals_ensure(mesh);
#ifdef DEBUG_TIME
TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_looptri(MVert *mverts,
@@ -438,8 +506,6 @@ void BKE_mesh_calc_normals_looptri(MVert *mverts,
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
normalize_v3_v3(no, mv->co);
}
-
- normal_float_to_short_v3(mv->no, no);
}
cleanup:
@@ -752,6 +818,7 @@ struct LoopSplitTaskDataCommon {
int (*edge_to_loops)[2];
int *loop_to_poly;
const float (*polynors)[3];
+ const float (*vert_normals)[3];
int numEdges;
int numLoops;
@@ -768,7 +835,6 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
const float split_angle,
const bool do_sharp_edges_tag)
{
- const MVert *mverts = data->mverts;
const MEdge *medges = data->medges;
const MLoop *mloops = data->mloops;
@@ -807,7 +873,7 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
* this way we don't have to compute those later!
*/
if (loopnors) {
- normal_short_to_float_v3(loopnors[ml_curr_index], mverts[ml_curr->v].no);
+ copy_v3_v3(loopnors[ml_curr_index], data->vert_normals[ml_curr->v]);
}
/* Check whether current edge might be smooth or sharp */
@@ -1532,6 +1598,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
}
void BKE_mesh_normals_loop_split(const MVert *mverts,
+ const float (*vert_normals)[3],
const int UNUSED(numVerts),
MEdge *medges,
const int numEdges,
@@ -1574,7 +1641,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
copy_v3_v3(r_loopnors[ml_index], polynors[mp_index]);
}
else {
- normal_short_to_float_v3(r_loopnors[ml_index], mverts[mloops[ml_index].v].no);
+ copy_v3_v3(r_loopnors[ml_index], vert_normals[mloops[ml_index].v]);
}
}
}
@@ -1632,6 +1699,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
common_data.edge_to_loops = edge_to_loops;
common_data.loop_to_poly = loop_to_poly;
common_data.polynors = polynors;
+ common_data.vert_normals = vert_normals;
common_data.numEdges = numEdges;
common_data.numLoops = numLoops;
common_data.numPolys = numPolys;
@@ -1683,6 +1751,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
* in which case they will be replaced by default loop/vertex normal.
*/
static void mesh_normals_loop_custom_set(const MVert *mverts,
+ const float (*vert_normals)[3],
const int numVerts,
MEdge *medges,
const int numEdges,
@@ -1714,6 +1783,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
/* Compute current lnor spacearr. */
BKE_mesh_normals_loop_split(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -1733,7 +1803,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
if (use_vertices) {
for (int i = 0; i < numVerts; i++) {
if (is_zero_v3(r_custom_loopnors[i])) {
- normal_short_to_float_v3(r_custom_loopnors[i], mverts[i].no);
+ copy_v3_v3(r_custom_loopnors[i], vert_normals[i]);
}
}
}
@@ -1836,6 +1906,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
/* And now, recompute our new auto lnors and lnor spacearr! */
BKE_lnor_spacearr_clear(&lnors_spacearr);
BKE_mesh_normals_loop_split(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -1917,6 +1988,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
}
void BKE_mesh_normals_loop_custom_set(const MVert *mverts,
+ const float (*vert_normals)[3],
const int numVerts,
MEdge *medges,
const int numEdges,
@@ -1929,6 +2001,7 @@ void BKE_mesh_normals_loop_custom_set(const MVert *mverts,
short (*r_clnors_data)[2])
{
mesh_normals_loop_custom_set(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -1943,6 +2016,7 @@ void BKE_mesh_normals_loop_custom_set(const MVert *mverts,
}
void BKE_mesh_normals_loop_custom_from_vertices_set(const MVert *mverts,
+ const float (*vert_normals)[3],
float (*r_custom_vertnors)[3],
const int numVerts,
MEdge *medges,
@@ -1955,6 +2029,7 @@ void BKE_mesh_normals_loop_custom_from_vertices_set(const MVert *mverts,
short (*r_clnors_data)[2])
{
mesh_normals_loop_custom_set(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -1982,22 +2057,8 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
&mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, nullptr, numloops);
}
- float(*polynors)[3] = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- bool free_polynors = false;
- if (polynors == nullptr) {
- polynors = (float(*)[3])MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__);
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- polynors,
- nullptr);
- free_polynors = true;
- }
-
mesh_normals_loop_custom_set(mesh->mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
mesh->totvert,
mesh->medge,
mesh->totedge,
@@ -2005,14 +2066,10 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
r_custom_nors,
mesh->totloop,
mesh->mpoly,
- polynors,
+ BKE_mesh_poly_normals_ensure(mesh),
mesh->totpoly,
clnors,
use_vertices);
-
- if (free_polynors) {
- MEM_freeN(polynors);
- }
}
void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3])
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 5b5378bd829..a9f61e9827b 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -594,6 +594,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
MPoly *polys_src = me_src->mpoly;
MLoop *loops_src = me_src->mloop;
float(*vcos_src)[3] = BKE_mesh_vert_coords_alloc(me_src, NULL);
+ const float(*vert_normals_src)[3] = BKE_mesh_vertex_normals_ensure(me_src);
size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
float(*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__);
@@ -605,7 +606,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
for (i = 0; i < numverts_dst; i++) {
copy_v3_v3(tmp_co, verts_dst[i].co);
- normal_short_to_float_v3(tmp_no, verts_dst[i].no);
+ copy_v3_v3(tmp_no, vert_normals_src[i]);
/* Convert the vertex to tree coordinates, if needed. */
if (space_transform) {
@@ -951,6 +952,8 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
+ const float(*vert_normals_dst)[3] = BKE_mesh_vertex_normals_ensure(me_src);
+
for (i = 0; i < numedges_dst; i++) {
/* For each dst edge, we sample some rays from it (interpolated from its vertices)
* and use their hits to interpolate from source edges. */
@@ -970,8 +973,8 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
copy_v3_v3(v1_co, verts_dst[me->v1].co);
copy_v3_v3(v2_co, verts_dst[me->v2].co);
- normal_short_to_float_v3(v1_no, verts_dst[me->v1].no);
- normal_short_to_float_v3(v2_no, verts_dst[me->v2].no);
+ copy_v3_v3(v1_no, vert_normals_dst[me->v1]);
+ copy_v3_v3(v2_no, vert_normals_dst[me->v2]);
/* We do our transform here, allows to interpolate from normals already in src space. */
if (space_transform) {
@@ -1242,6 +1245,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
const SpaceTransform *space_transform,
const float max_dist,
const float ray_radius,
+ Mesh *mesh_dst,
MVert *verts_dst,
const int numverts_dst,
MEdge *edges_dst,
@@ -1251,7 +1255,6 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
MPoly *polys_dst,
const int numpolys_dst,
CustomData *ldata_dst,
- CustomData *pdata_dst,
const bool use_split_nors_dst,
const float split_angle_dst,
const bool dirty_nors_dst,
@@ -1297,9 +1300,9 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
1) :
0);
- float(*poly_nors_src)[3] = NULL;
- float(*loop_nors_src)[3] = NULL;
- float(*poly_nors_dst)[3] = NULL;
+ const float(*poly_nors_src)[3] = NULL;
+ const float(*loop_nors_src)[3] = NULL;
+ const float(*poly_nors_dst)[3] = NULL;
float(*loop_nors_dst)[3] = NULL;
float(*poly_cents_src)[3] = NULL;
@@ -1356,23 +1359,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
const bool need_pnors_dst = need_lnors_dst || need_pnors_src;
if (need_pnors_dst) {
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- const bool do_poly_nors_dst = (poly_nors_dst == NULL);
- if (!poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(
- pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst || do_poly_nors_dst) {
- BKE_mesh_calc_normals_poly(verts_dst,
- numverts_dst,
- loops_dst,
- numloops_dst,
- polys_dst,
- numpolys_dst,
- poly_nors_dst);
- }
+ poly_nors_dst = BKE_mesh_poly_normals_ensure(mesh_dst);
}
if (need_lnors_dst) {
short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
@@ -1387,6 +1374,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
}
if (dirty_nors_dst || do_loop_nors_dst) {
BKE_mesh_normals_loop_split(verts_dst,
+ BKE_mesh_vertex_normals_ensure(mesh_dst),
numverts_dst,
edges_dst,
numedges_dst,
@@ -1394,7 +1382,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
loop_nors_dst,
numloops_dst,
polys_dst,
- (const float(*)[3])poly_nors_dst,
+ poly_nors_dst,
numpolys_dst,
use_split_nors_dst,
split_angle_dst,
@@ -1405,8 +1393,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
}
if (need_pnors_src || need_lnors_src) {
if (need_pnors_src) {
- poly_nors_src = CustomData_get_layer(&me_src->pdata, CD_NORMAL);
- BLI_assert(poly_nors_src != NULL);
+ poly_nors_src = BKE_mesh_poly_normals_ensure(me_src);
}
if (need_lnors_src) {
loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL);
@@ -1648,7 +1635,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
if (mesh_remap_bvhtree_query_nearest(
tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
float(*nor_dst)[3];
- float(*nors_src)[3];
+ const float(*nors_src)[3];
float best_nor_dot = -2.0f;
float best_sqdist_fallback = FLT_MAX;
int best_index_src = -1;
@@ -2188,41 +2175,24 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode,
const SpaceTransform *space_transform,
const float max_dist,
const float ray_radius,
+ Mesh *mesh_dst,
MVert *verts_dst,
- const int numverts_dst,
MLoop *loops_dst,
- const int numloops_dst,
MPoly *polys_dst,
const int numpolys_dst,
- CustomData *pdata_dst,
- const bool dirty_nors_dst,
Mesh *me_src,
MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
const float max_dist_sq = max_dist * max_dist;
- float(*poly_nors_dst)[3] = NULL;
+ const float(*poly_nors_dst)[3] = NULL;
float tmp_co[3], tmp_no[3];
int i;
BLI_assert(mode & MREMAP_MODE_POLY);
if (mode & (MREMAP_USE_NORMAL | MREMAP_USE_NORPROJ)) {
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- if (!poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst) {
- BKE_mesh_calc_normals_poly(verts_dst,
- numverts_dst,
- loops_dst,
- numloops_dst,
- polys_dst,
- numpolys_dst,
- poly_nors_dst);
- }
+ poly_nors_dst = BKE_mesh_poly_normals_ensure(mesh_dst);
}
BKE_mesh_remap_init(r_map, numpolys_dst);
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
index 3447185089d..50464da86e9 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
@@ -31,8 +31,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
-#include "BLI_float3.hh"
#include "BLI_index_range.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "DNA_mesh_types.h"
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index 45c84ed0862..e7e5064df7c 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -53,6 +53,8 @@ static void mesh_runtime_init_mutexes(Mesh *mesh)
{
mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
BLI_mutex_init(mesh->runtime.eval_mutex);
+ mesh->runtime.normals_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime normals_mutex");
+ BLI_mutex_init(mesh->runtime.normals_mutex);
mesh->runtime.render_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime render_mutex");
BLI_mutex_init(mesh->runtime.render_mutex);
}
@@ -67,6 +69,11 @@ static void mesh_runtime_free_mutexes(Mesh *mesh)
MEM_freeN(mesh->runtime.eval_mutex);
mesh->runtime.eval_mutex = NULL;
}
+ if (mesh->runtime.normals_mutex != NULL) {
+ BLI_mutex_end(mesh->runtime.normals_mutex);
+ MEM_freeN(mesh->runtime.normals_mutex);
+ mesh->runtime.normals_mutex = NULL;
+ }
if (mesh->runtime.render_mutex != NULL) {
BLI_mutex_end(mesh->runtime.render_mutex);
MEM_freeN(mesh->runtime.render_mutex);
@@ -291,129 +298,10 @@ void BKE_mesh_batch_cache_free(Mesh *me)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Mesh Runtime Debug Helpers
+/** \name Mesh Runtime Validation
* \{ */
-/* Evaluated mesh info printing function, to help track down differences output. */
-
#ifndef NDEBUG
-# include "BLI_dynstr.h"
-
-static void mesh_runtime_debug_info_layers(DynStr *dynstr, CustomData *cd)
-{
- int type;
-
- for (type = 0; type < CD_NUMTYPES; type++) {
- if (CustomData_has_layer(cd, type)) {
- /* NOTE: doesn't account for multiple layers. */
- const char *name = CustomData_layertype_name(type);
- const int size = CustomData_sizeof(type);
- const void *pt = CustomData_get_layer(cd, type);
- const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
- const char *structname;
- int structnum;
- CustomData_file_write_info(type, &structname, &structnum);
- BLI_dynstr_appendf(
- dynstr,
- " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
- name,
- structname,
- type,
- (const void *)pt,
- size,
- pt_size);
- }
- }
-}
-
-char *BKE_mesh_runtime_debug_info(Mesh *me_eval)
-{
- DynStr *dynstr = BLI_dynstr_new();
- char *ret;
-
- BLI_dynstr_append(dynstr, "{\n");
- BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me_eval);
-# if 0
- const char *tstr;
- switch (me_eval->type) {
- case DM_TYPE_CDDM:
- tstr = "DM_TYPE_CDDM";
- break;
- case DM_TYPE_CCGDM:
- tstr = "DM_TYPE_CCGDM";
- break;
- default:
- tstr = "UNKNOWN";
- break;
- }
- BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
-# endif
- BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me_eval->totvert);
- BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me_eval->totedge);
- BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me_eval->totface);
- BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me_eval->totpoly);
- BLI_dynstr_appendf(dynstr, " 'deformed_only': %d,\n", me_eval->runtime.deformed_only);
-
- BLI_dynstr_append(dynstr, " 'vertexLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->vdata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'edgeLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->edata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'loopLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->ldata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'polyLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->pdata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n");
- mesh_runtime_debug_info_layers(dynstr, &me_eval->fdata);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, "}\n");
-
- ret = BLI_dynstr_get_cstring(dynstr);
- BLI_dynstr_free(dynstr);
- return ret;
-}
-
-void BKE_mesh_runtime_debug_print(Mesh *me_eval)
-{
- char *str = BKE_mesh_runtime_debug_info(me_eval);
- puts(str);
- fflush(stdout);
- MEM_freeN(str);
-}
-
-void BKE_mesh_runtime_debug_print_cdlayers(CustomData *data)
-{
- int i;
- const CustomDataLayer *layer;
-
- printf("{\n");
-
- for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) {
-
- const char *name = CustomData_layertype_name(layer->type);
- const int size = CustomData_sizeof(layer->type);
- const char *structname;
- int structnum;
- CustomData_file_write_info(layer->type, &structname, &structnum);
- printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
- name,
- structname,
- layer->type,
- (const void *)layer->data,
- size,
- (int)(MEM_allocN_len(layer->data) / size));
- }
-
- printf("}\n");
-}
bool BKE_mesh_runtime_is_valid(Mesh *me_eval)
{
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index c7a1b22dad1..73cef6b925b 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.c
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -224,7 +224,8 @@ typedef struct {
MLoopUV *mloopuv; /* texture coordinates */
const MPoly *mpoly; /* indices */
const MLoop *mloop; /* indices */
- const MVert *mvert; /* vertices & normals */
+ const MVert *mvert; /* vertex coordinates */
+ const float (*vert_normals)[3];
const float (*orco)[3];
float (*tangent)[4]; /* destination */
int numTessFaces;
@@ -398,8 +399,7 @@ finally:
}
}
else {
- const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
- normal_short_to_float_v3(r_no, no);
+ copy_v3_v3(r_no, pMesh->vert_normals[pMesh->mloop[loop_index].v]);
}
}
@@ -557,6 +557,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
int tangent_names_len,
+ const float (*vert_normals)[3],
const float (*poly_normals)[3],
const float (*loop_normals)[3],
const float (*vert_orco)[3],
@@ -651,6 +652,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
#endif
mesh2tangent->mvert = mvert;
+ mesh2tangent->vert_normals = vert_normals;
mesh2tangent->mpoly = mpoly;
mesh2tangent->mloop = mloop;
mesh2tangent->looptri = looptri;
@@ -743,7 +745,8 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
calc_active_tangent,
tangent_names,
tangent_names_len,
- CustomData_get_layer(&me_eval->pdata, CD_NORMAL),
+ BKE_mesh_vertex_normals_ensure(me_eval),
+ BKE_mesh_poly_normals_ensure(me_eval),
CustomData_get_layer(&me_eval->ldata, CD_NORMAL),
CustomData_get_layer(&me_eval->vdata, CD_ORCO), /* may be NULL */
/* result */
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index ba86c0fd449..005c916b4e0 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -303,6 +303,12 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
recalc_flag.edges = do_fixes;
}
+ const float(*vert_normals)[3] = NULL;
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
+ if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
+ vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+ }
+
for (i = 0; i < totvert; i++, mv++) {
bool fix_normal = true;
@@ -317,13 +323,13 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
}
- if (mv->no[j] != 0) {
+ if (vert_normals && vert_normals[i][j] != 0.0f) {
fix_normal = false;
break;
}
}
- if (fix_normal) {
+ if (vert_normals && fix_normal) {
/* If the vertex normal accumulates to zero or isn't part of a face, the location is used.
* When the location is also zero, a zero normal warning should not be raised.
* since this is the expected behavior of normal calculation.
@@ -336,7 +342,8 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
if (!is_zero_v3(mv->co)) {
PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal", i);
if (do_fixes) {
- mv->no[2] = SHRT_MAX;
+ float *normal = (float *)vert_normals[i];
+ normal[2] = 1.0f;
fix_flag.verts = true;
}
}
@@ -1001,6 +1008,10 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata,
CustomData_MeshMasks mask = {0};
if (check_meshmask) {
mask = CD_MASK_MESH;
+ /* Normal data isn't in the mask since it is derived data,
+ * but it is valid and should not be removed. */
+ mask.vmask |= CD_MASK_NORMAL;
+ mask.pmask |= CD_MASK_NORMAL;
}
is_valid &= mesh_validate_customdata(
@@ -1098,6 +1109,8 @@ bool BKE_mesh_is_valid(Mesh *me)
bool is_valid = true;
bool changed = true;
+ BKE_mesh_assert_normals_dirty_or_calculated(me);
+
is_valid &= BKE_mesh_validate_all_customdata(
&me->vdata,
me->totvert,
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.c b/source/blender/blenkernel/intern/mesh_wrapper.c
index bc1ffeb8cf4..d1f15cf9007 100644
--- a/source/blender/blenkernel/intern/mesh_wrapper.c
+++ b/source/blender/blenkernel/intern/mesh_wrapper.c
@@ -36,6 +36,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BLI_ghash.h"
@@ -50,8 +51,14 @@
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_wrapper.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_mesh.h"
+#include "BKE_subdiv_modifier.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
const CustomData_MeshMasks *cd_mask_extra,
@@ -106,7 +113,8 @@ static void mesh_wrapper_ensure_mdata_isolated(void *userdata)
me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
switch (geom_type_orig) {
- case ME_WRAPPER_TYPE_MDATA: {
+ case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD: {
break; /* Quiet warning. */
}
case ME_WRAPPER_TYPE_BMESH: {
@@ -157,6 +165,7 @@ bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
case ME_WRAPPER_TYPE_BMESH:
return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max);
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return BKE_mesh_minmax(me, min, max);
}
BLI_assert_unreachable();
@@ -191,7 +200,8 @@ void BKE_mesh_wrapper_vert_coords_copy(const Mesh *me,
}
return;
}
- case ME_WRAPPER_TYPE_MDATA: {
+ case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD: {
BLI_assert(vert_coords_len <= me->totvert);
const MVert *mvert = me->mvert;
for (int i = 0; i < vert_coords_len; i++) {
@@ -228,7 +238,8 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me,
}
return;
}
- case ME_WRAPPER_TYPE_MDATA: {
+ case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD: {
BLI_assert(vert_coords_len == me->totvert);
const MVert *mvert = me->mvert;
for (int i = 0; i < vert_coords_len; i++) {
@@ -252,6 +263,7 @@ int BKE_mesh_wrapper_vert_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totvert;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totvert;
}
BLI_assert_unreachable();
@@ -264,6 +276,7 @@ int BKE_mesh_wrapper_edge_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totedge;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totedge;
}
BLI_assert_unreachable();
@@ -276,6 +289,7 @@ int BKE_mesh_wrapper_loop_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totloop;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totloop;
}
BLI_assert_unreachable();
@@ -288,6 +302,7 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totface;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totpoly;
}
BLI_assert_unreachable();
@@ -295,3 +310,73 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name CPU Subdivision Evaluation
+ * \{ */
+
+Mesh *BKE_mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
+{
+ ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
+ BLI_mutex_lock(mesh_eval_mutex);
+
+ if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_SUBD) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me->runtime.mesh_eval;
+ }
+
+ SubsurfModifierData *smd = BKE_object_get_last_subsurf_modifier(ob);
+ if (!smd) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ /* Initialize the settings before ensuring the descriptor as this is checked to decide whether
+ * subdivision is needed at all, and checking the descriptor status might involve checking if the
+ * data is out-of-date, which is a very expensive operation. */
+ SubdivToMeshSettings mesh_settings;
+ mesh_settings.resolution = me->runtime.subsurf_resolution;
+ mesh_settings.use_optimal_display = me->runtime.subsurf_use_optimal_display;
+
+ if (mesh_settings.resolution < 3) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ const bool apply_render = me->runtime.subsurf_apply_render;
+
+ SubdivSettings subdiv_settings;
+ BKE_subsurf_modifier_subdiv_settings_init(&subdiv_settings, smd, apply_render);
+ if (subdiv_settings.level == 0) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, but also on empty input mesh. */
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ Mesh *subdiv_mesh = BKE_subdiv_to_mesh(subdiv, &mesh_settings, me);
+
+ if (subdiv != runtime_data->subdiv) {
+ BKE_subdiv_free(subdiv);
+ }
+
+ if (subdiv_mesh != me) {
+ if (me->runtime.mesh_eval != NULL) {
+ BKE_id_free(NULL, me->runtime.mesh_eval);
+ }
+ me->runtime.mesh_eval = subdiv_mesh;
+ me->runtime.wrapper_type = ME_WRAPPER_TYPE_SUBD;
+ }
+
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me->runtime.mesh_eval;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 5ad8f143b2b..e1fd8ff45d1 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -933,7 +933,7 @@ const char *BKE_modifier_path_relbase(Main *bmain, Object *ob)
* - 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 (G.relbase_valid || ID_IS_LINKED(ob)) {
+ if ((bmain->filepath[0] != '\0') || ID_IS_LINKED(ob)) {
return ID_BLEND_PATH(bmain, &ob->id);
}
@@ -948,7 +948,8 @@ const char *BKE_modifier_path_relbase_from_global(Object *ob)
void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
{
- 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);
}
/**
@@ -969,6 +970,7 @@ static void modwrap_dependsOnNormals(Mesh *me)
}
break;
}
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
BKE_mesh_calc_normals(me);
break;
@@ -982,7 +984,6 @@ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md,
struct Mesh *me)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) {
@@ -1003,8 +1004,6 @@ void BKE_modifier_deform_verts(ModifierData *md,
int numVerts)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
-
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
modwrap_dependsOnNormals(me);
}
@@ -1019,8 +1018,6 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
int numVerts)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
-
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
BKE_mesh_calc_normals(me);
}
@@ -1039,8 +1036,11 @@ Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval,
BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
/* 'em' might not exist yet in some cases, just after loading a .blend file, see T57878. */
if (em != NULL) {
- me = (get_cage_mesh && em->mesh_eval_cage != NULL) ? em->mesh_eval_cage :
- em->mesh_eval_final;
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
+
+ me = (get_cage_mesh && editmesh_eval_cage != NULL) ? editmesh_eval_cage :
+ editmesh_eval_final;
}
}
if (me == NULL) {
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index fc2e7d0a6a3..88da789cdc4 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -70,6 +70,7 @@
#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "IMB_imbuf.h"
@@ -105,7 +106,7 @@ static void movie_clip_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s
MovieClip *movie_clip_dst = (MovieClip *)id_dst;
const MovieClip *movie_clip_src = (const MovieClip *)id_src;
- /* We never handle usercount here for own data. */
+ /* We never handle user-count here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
movie_clip_dst->anim = NULL;
@@ -952,7 +953,7 @@ static MovieClip *movieclip_alloc(Main *bmain, const char *name)
static void movieclip_load_get_size(MovieClip *clip)
{
int width, height;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, 1);
BKE_movieclip_get_size(clip, &user, &width, &height);
@@ -1177,7 +1178,7 @@ static ImBuf *get_postprocessed_cached_frame(const MovieClip *clip,
return NULL;
}
- /* postprocessing happened for other frame */
+ /* Postprocessing happened for other frame. */
if (cache->postprocessed.framenr != framenr) {
return NULL;
}
@@ -1695,17 +1696,7 @@ void BKE_movieclip_reload(Main *bmain, MovieClip *clip)
movieclip_calc_length(clip);
- /* same as for image update -- don't use notifiers because they are not 100% sure to succeeded
- * (node trees which are not currently visible wouldn't be refreshed)
- */
- {
- Scene *scene;
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (scene->nodetree) {
- nodeUpdateID(scene->nodetree, &clip->id);
- }
- }
- }
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
}
void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClipScopes *scopes)
diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h
index db419418998..a038ce5f108 100644
--- a/source/blender/blenkernel/intern/multires_reshape.h
+++ b/source/blender/blenkernel/intern/multires_reshape.h
@@ -106,6 +106,9 @@ typedef struct MultiresReshapeContext {
/* Indexed by base face index, returns first ptex face index corresponding
* to that base face. */
int *face_ptex_offset;
+
+ /* Vertex crease custom data layer, null if none is present. */
+ const float *cd_vertex_crease;
} MultiresReshapeContext;
/**
@@ -225,8 +228,8 @@ GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *resh
* 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,
+ int face_index,
+ int corner,
const float dPdu[3],
const float dPdv[3],
float r_tangent_matrix[3][3]);
@@ -266,7 +269,7 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha
/**
* Make sure custom data is allocated for the given level.
*/
-void multires_reshape_ensure_grids(struct Mesh *mesh, const int level);
+void multires_reshape_ensure_grids(struct Mesh *mesh, int level);
/* --------------------------------------------------------------------
* Functions specific to reshaping from a set of vertices in a object position.
@@ -283,7 +286,7 @@ void multires_reshape_ensure_grids(struct Mesh *mesh, const int level);
bool multires_reshape_assign_final_coords_from_vertcos(
const MultiresReshapeContext *reshape_context,
const float (*vert_coords)[3],
- const int num_vert_coords);
+ int num_vert_coords);
/* --------------------------------------------------------------------
* Functions specific to reshaping from CCG.
@@ -338,7 +341,7 @@ void multires_reshape_smooth_object_grids_with_details(
* Makes it so surface on top level looks smooth. Details are not preserved
*/
void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context,
- const enum eMultiresSubdivideModeType mode);
+ enum eMultiresSubdivideModeType mode);
/* --------------------------------------------------------------------
* Displacement, space conversion.
diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c
index 3665d01926b..839c457dd84 100644
--- a/source/blender/blenkernel/intern/multires_reshape_smooth.c
+++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c
@@ -75,6 +75,7 @@ typedef struct Vertex {
int num_grid_coords;
GridCoord *grid_coords;
+ float sharpness;
bool is_infinite_sharp;
} Vertex;
@@ -489,19 +490,33 @@ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_co
return (1 << reshape_context->reshape.level) + 1;
}
+static bool is_crease_supported(const MultiresReshapeSmoothContext *reshape_smooth_context)
+{
+ return !ELEM(reshape_smooth_context->smoothing_type,
+ MULTIRES_SUBDIVIDE_LINEAR,
+ MULTIRES_SUBDIVIDE_SIMPLE);
+}
+
/* Get crease which will be used for communication to OpenSubdiv topology.
* Note that simple subdivision treats all base edges as infinitely sharp. */
-static char get_effective_edge_crease_char(
- const MultiresReshapeSmoothContext *reshape_smooth_context, const MEdge *base_edge)
+static char get_effective_crease_char(const MultiresReshapeSmoothContext *reshape_smooth_context,
+ const MEdge *base_edge)
{
- if (ELEM(reshape_smooth_context->smoothing_type,
- MULTIRES_SUBDIVIDE_LINEAR,
- MULTIRES_SUBDIVIDE_SIMPLE)) {
+ if (!is_crease_supported(reshape_smooth_context)) {
return 255;
}
return base_edge->crease;
}
+static float get_effective_crease_float(const MultiresReshapeSmoothContext *reshape_smooth_context,
+ const float crease)
+{
+ if (!is_crease_supported(reshape_smooth_context)) {
+ return 1.0f;
+ }
+ return crease;
+}
+
static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
const MultiresReshapeContext *reshape_context,
const eMultiresSubdivideModeType mode)
@@ -566,7 +581,8 @@ static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
const int num_vertices,
const int num_edges,
const int num_loops,
- const int num_polygons)
+ const int num_polygons,
+ const int *UNUSED(subdiv_polygon_offset))
{
MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
const int max_edges = reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR ?
@@ -595,6 +611,7 @@ static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
static void foreach_single_vertex(const SubdivForeachContext *foreach_context,
const GridCoord *grid_coord,
+ const int coarse_vertex_index,
const int subdiv_vertex_index)
{
const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
@@ -607,11 +624,32 @@ static void foreach_single_vertex(const SubdivForeachContext *foreach_context,
sizeof(Vertex) * (vertex->num_grid_coords + 1));
vertex->grid_coords[vertex->num_grid_coords] = *grid_coord;
++vertex->num_grid_coords;
+
+ if (coarse_vertex_index == -1) {
+ return;
+ }
+
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+ const float *cd_vertex_crease = reshape_context->cd_vertex_crease;
+
+ if (cd_vertex_crease == NULL) {
+ return;
+ }
+
+ float crease = cd_vertex_crease[coarse_vertex_index];
+
+ if (crease == 0.0f) {
+ return;
+ }
+
+ crease = get_effective_crease_float(reshape_smooth_context, crease);
+ vertex->sharpness = BKE_subdiv_crease_to_sharpness_f(crease);
}
/* TODO(sergey): De-duplicate with similar function in multires_reshape_vertcos.c */
static void foreach_vertex(const SubdivForeachContext *foreach_context,
const PTexCoord *ptex_coord,
+ const int coarse_vertex_index,
const int subdiv_vertex_index)
{
const MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
@@ -631,12 +669,13 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context,
for (int current_corner = 0; current_corner < num_corners; ++current_corner) {
GridCoord corner_grid_coord = grid_coord;
corner_grid_coord.grid_index = start_grid_index + current_corner;
- foreach_single_vertex(foreach_context, &corner_grid_coord, subdiv_vertex_index);
+ foreach_single_vertex(
+ foreach_context, &corner_grid_coord, coarse_vertex_index, subdiv_vertex_index);
}
return;
}
- foreach_single_vertex(foreach_context, &grid_coord, subdiv_vertex_index);
+ foreach_single_vertex(foreach_context, &grid_coord, coarse_vertex_index, subdiv_vertex_index);
if (grid_coord.u == 0.0f) {
GridCoord prev_grid_coord;
@@ -644,7 +683,8 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context,
prev_grid_coord.u = grid_coord.v;
prev_grid_coord.v = 0.0f;
- foreach_single_vertex(foreach_context, &prev_grid_coord, subdiv_vertex_index);
+ foreach_single_vertex(
+ foreach_context, &prev_grid_coord, coarse_vertex_index, subdiv_vertex_index);
}
if (grid_coord.v == 0.0f) {
@@ -653,7 +693,8 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context,
next_grid_coord.u = 0.0f;
next_grid_coord.v = grid_coord.u;
- foreach_single_vertex(foreach_context, &next_grid_coord, subdiv_vertex_index);
+ foreach_single_vertex(
+ foreach_context, &next_grid_coord, coarse_vertex_index, subdiv_vertex_index);
}
}
@@ -671,7 +712,7 @@ static void foreach_vertex_inner(const struct SubdivForeachContext *foreach_cont
.u = ptex_face_u,
.v = ptex_face_v,
};
- foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
+ foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
}
static void foreach_vertex_every_corner(const struct SubdivForeachContext *foreach_context,
@@ -679,7 +720,7 @@ static void foreach_vertex_every_corner(const struct SubdivForeachContext *forea
const int ptex_face_index,
const float ptex_face_u,
const float ptex_face_v,
- const int UNUSED(coarse_vertex_index),
+ const int coarse_vertex_index,
const int UNUSED(coarse_face_index),
const int UNUSED(coarse_face_corner),
const int subdiv_vertex_index)
@@ -689,7 +730,7 @@ static void foreach_vertex_every_corner(const struct SubdivForeachContext *forea
.u = ptex_face_u,
.v = ptex_face_v,
};
- foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
+ foreach_vertex(foreach_context, &ptex_coord, coarse_vertex_index, subdiv_vertex_index);
}
static void foreach_vertex_every_edge(const struct SubdivForeachContext *foreach_context,
@@ -707,7 +748,7 @@ static void foreach_vertex_every_edge(const struct SubdivForeachContext *foreach
.u = ptex_face_u,
.v = ptex_face_v,
};
- foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
+ foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
}
static void foreach_loop(const struct SubdivForeachContext *foreach_context,
@@ -777,7 +818,7 @@ static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context,
Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
edge->v1 = subdiv_v1;
edge->v2 = subdiv_v2;
- edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease);
+ edge->sharpness = BKE_subdiv_crease_to_sharpness_char(crease);
}
static void foreach_edge(const struct SubdivForeachContext *foreach_context,
@@ -808,7 +849,7 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
/* Edges without crease are to be ignored as well. */
const Mesh *base_mesh = reshape_context->base_mesh;
const MEdge *base_edge = &base_mesh->medge[coarse_edge_index];
- const char crease = get_effective_edge_crease_char(reshape_smooth_context, base_edge);
+ const char crease = get_effective_crease_char(reshape_smooth_context, base_edge);
if (crease == 0) {
return;
}
@@ -834,8 +875,7 @@ static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshap
if (!BLI_BITMAP_TEST_BOOL(reshape_smooth_context->non_loose_base_edge_map, loop->e)) {
BLI_BITMAP_ENABLE(reshape_smooth_context->non_loose_base_edge_map, loop->e);
- const char crease = get_effective_edge_crease_char(reshape_smooth_context,
- &base_edge[loop->e]);
+ const char crease = get_effective_crease_char(reshape_smooth_context, &base_edge[loop->e]);
if (crease != 0) {
++num_used_edges;
}
@@ -978,6 +1018,15 @@ static float get_edge_sharpness(const OpenSubdiv_Converter *converter, const int
return edge->sharpness;
}
+static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, const int vertex_index)
+{
+ const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
+ BLI_assert(vertex_index < reshape_smooth_context->geometry.num_vertices);
+
+ const Vertex *vertex = &reshape_smooth_context->geometry.vertices[vertex_index];
+ return vertex->sharpness;
+}
+
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter, int vertex_index)
{
const MultiresReshapeSmoothContext *reshape_smooth_context = converter->user_data;
@@ -1014,7 +1063,7 @@ static void converter_init(const MultiresReshapeSmoothContext *reshape_smooth_co
converter->getNumVertexFaces = NULL;
converter->getVertexFaces = NULL;
converter->isInfiniteSharpVertex = is_infinite_sharp_vertex;
- converter->getVertexSharpness = NULL;
+ converter->getVertexSharpness = get_vertex_sharpness;
converter->getNumUVLayers = NULL;
converter->precalcUVLayer = NULL;
@@ -1037,7 +1086,7 @@ static void reshape_subdiv_create(MultiresReshapeSmoothContext *reshape_smooth_c
converter_init(reshape_smooth_context, &converter);
Subdiv *reshape_subdiv = BKE_subdiv_new_from_converter(settings, &converter);
- BKE_subdiv_eval_begin(reshape_subdiv);
+ BKE_subdiv_eval_begin(reshape_subdiv, SUBDIV_EVALUATOR_TYPE_CPU, NULL);
reshape_smooth_context->reshape_subdiv = reshape_subdiv;
diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c
index b7572204182..810cf328531 100644
--- a/source/blender/blenkernel/intern/multires_reshape_util.c
+++ b/source/blender/blenkernel/intern/multires_reshape_util.c
@@ -65,7 +65,7 @@ Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
SubdivSettings subdiv_settings;
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, base_mesh);
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
BKE_subdiv_free(subdiv);
return NULL;
}
@@ -135,7 +135,7 @@ static void context_init_commoon(MultiresReshapeContext *reshape_context)
static bool context_is_valid(MultiresReshapeContext *reshape_context)
{
if (reshape_context->mdisps == NULL) {
- /* Multires displacement has been removed before current changes were applies. */
+ /* Multi-resolution displacement has been removed before current changes were applies. */
return false;
}
return true;
@@ -211,6 +211,8 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape
reshape_context->top.level = mmd->totlvl;
reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
+ reshape_context->cd_vertex_crease = CustomData_get_layer(&base_mesh->vdata, CD_CREASE);
+
context_init_commoon(reshape_context);
return context_verify_or_free(reshape_context);
diff --git a/source/blender/blenkernel/intern/multires_reshape_vertcos.c b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
index ed2df1ba8c5..c009349ff1b 100644
--- a/source/blender/blenkernel/intern/multires_reshape_vertcos.c
+++ b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
@@ -114,7 +114,8 @@ static bool multires_reshape_vertcos_foreach_topology_info(
const int num_vertices,
const int UNUSED(num_edges),
const int UNUSED(num_loops),
- const int UNUSED(num_polygons))
+ const int UNUSED(num_polygons),
+ const int *UNUSED(subdiv_polygon_offset))
{
MultiresReshapeAssignVertcosContext *reshape_vertcos_context = foreach_context->user_data;
if (num_vertices != reshape_vertcos_context->num_vert_coords) {
diff --git a/source/blender/blenkernel/intern/multires_versioning.c b/source/blender/blenkernel/intern/multires_versioning.c
index 4c0d7165cd0..18708c43f26 100644
--- a/source/blender/blenkernel/intern/multires_versioning.c
+++ b/source/blender/blenkernel/intern/multires_versioning.c
@@ -61,7 +61,7 @@ static Subdiv *subdiv_for_simple_to_catmull_clark(Object *object, MultiresModifi
Subdiv *subdiv = BKE_subdiv_new_from_converter(&subdiv_settings, &converter);
BKE_subdiv_converter_free(&converter);
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
BKE_subdiv_free(subdiv);
return NULL;
}
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index a4de6730f8f..40d0c24c9af 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -65,6 +65,7 @@
#include "BKE_animsys.h"
#include "BKE_bpath.h"
#include "BKE_colortools.h"
+#include "BKE_context.h"
#include "BKE_cryptomatte.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -74,6 +75,7 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -98,10 +100,12 @@
#define NODE_DEFAULT_MAX_WIDTH 700
using blender::Array;
+using blender::Map;
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;
@@ -150,62 +154,42 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
BLI_listbase_clear(&ntree_dst->nodes);
BLI_listbase_clear(&ntree_dst->links);
- /* Since source nodes and sockets are unique pointers we can put everything in a single map. */
- GHash *new_pointers = BLI_ghash_ptr_new(__func__);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
- LISTBASE_FOREACH (const bNode *, node_src, &ntree_src->nodes) {
- bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata, true);
- BLI_ghash_insert(new_pointers, (void *)node_src, new_node);
- /* Store mapping to inputs. */
- bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first;
- const bNodeSocket *input_sock_src = (const bNodeSocket *)node_src->inputs.first;
- while (new_input_sock != nullptr) {
- BLI_ghash_insert(new_pointers, (void *)input_sock_src, new_input_sock);
- new_input_sock = new_input_sock->next;
- input_sock_src = input_sock_src->next;
- }
- /* Store mapping to outputs. */
- bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first;
- const bNodeSocket *output_sock_src = (const bNodeSocket *)node_src->outputs.first;
- while (new_output_sock != nullptr) {
- BLI_ghash_insert(new_pointers, (void *)output_sock_src, new_output_sock);
- new_output_sock = new_output_sock->next;
- output_sock_src = output_sock_src->next;
- }
+ BLI_listbase_clear(&ntree_dst->nodes);
+ LISTBASE_FOREACH (const bNode *, src_node, &ntree_src->nodes) {
+ /* Don't find a unique name for every node, since they should have valid names already. */
+ bNode *new_node = blender::bke::node_copy_with_mapping(
+ ntree_dst, *src_node, flag_subdata, false, socket_map);
+ node_map.add(src_node, new_node);
}
/* copy links */
- BLI_duplicatelist(&ntree_dst->links, &ntree_src->links);
- LISTBASE_FOREACH (bNodeLink *, link_dst, &ntree_dst->links) {
- link_dst->fromnode = (bNode *)BLI_ghash_lookup_default(
- new_pointers, link_dst->fromnode, nullptr);
- link_dst->fromsock = (bNodeSocket *)BLI_ghash_lookup_default(
- new_pointers, link_dst->fromsock, nullptr);
- link_dst->tonode = (bNode *)BLI_ghash_lookup_default(new_pointers, link_dst->tonode, nullptr);
- link_dst->tosock = (bNodeSocket *)BLI_ghash_lookup_default(
- new_pointers, link_dst->tosock, nullptr);
- /* update the link socket's pointer */
- if (link_dst->tosock) {
- link_dst->tosock->link = link_dst;
- }
+ BLI_listbase_clear(&ntree_dst->links);
+ LISTBASE_FOREACH (const bNodeLink *, src_link, &ntree_src->links) {
+ bNodeLink *dst_link = (bNodeLink *)MEM_dupallocN(src_link);
+ dst_link->fromnode = node_map.lookup(src_link->fromnode);
+ dst_link->fromsock = socket_map.lookup(src_link->fromsock);
+ dst_link->tonode = node_map.lookup(src_link->tonode);
+ dst_link->tosock = socket_map.lookup(src_link->tosock);
+ BLI_assert(dst_link->tosock);
+ dst_link->tosock->link = dst_link;
+ BLI_addtail(&ntree_dst->links, dst_link);
}
/* copy interface sockets */
- BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs);
- bNodeSocket *sock_dst, *sock_src;
- for (sock_dst = (bNodeSocket *)ntree_dst->inputs.first,
- sock_src = (bNodeSocket *)ntree_src->inputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag_subdata);
+ BLI_listbase_clear(&ntree_dst->inputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &ntree_src->inputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag_subdata);
+ BLI_addtail(&ntree_dst->inputs, dst_socket);
}
-
- BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs);
- for (sock_dst = (bNodeSocket *)ntree_dst->outputs.first,
- sock_src = (bNodeSocket *)ntree_src->outputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag_subdata);
+ BLI_listbase_clear(&ntree_dst->outputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &ntree_src->outputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag_subdata);
+ BLI_addtail(&ntree_dst->outputs, dst_socket);
}
/* copy preview hash */
@@ -225,18 +209,11 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
}
/* update node->parent pointers */
- for (bNode *node_dst = (bNode *)ntree_dst->nodes.first,
- *node_src = (bNode *)ntree_src->nodes.first;
- node_dst;
- node_dst = (bNode *)node_dst->next, node_src = (bNode *)node_src->next) {
- if (node_dst->parent) {
- node_dst->parent = (bNode *)BLI_ghash_lookup_default(
- new_pointers, node_dst->parent, nullptr);
+ LISTBASE_FOREACH (bNode *, new_node, &ntree_dst->nodes) {
+ if (new_node->parent) {
+ new_node->parent = node_map.lookup(new_node->parent);
}
}
-
- BLI_ghash_free(new_pointers, nullptr, nullptr);
-
/* node tree will generate its own interface type */
ntree_dst->interface_type = nullptr;
@@ -260,8 +237,7 @@ static void ntree_free_data(ID *id)
/* XXX hack! node trees should not store execution graphs at all.
* This should be removed when old tree types no longer require it.
* Currently the execution data for texture nodes remains in the tree
- * after execution, until the node tree is updated or freed.
- */
+ * after execution, until the node tree is updated or freed. */
if (ntree->execdata) {
switch (ntree->type) {
case NTREE_SHADER:
@@ -277,10 +253,10 @@ static void ntree_free_data(ID *id)
/* XXX not nice, but needed to free localized node groups properly */
free_localized_node_groups(ntree);
- /* unregister associated RNA types */
+ /* Unregister associated RNA types. */
ntreeInterfaceTypeFree(ntree);
- BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
+ BLI_freelistN(&ntree->links);
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
node_free_node(ntree, node);
@@ -521,7 +497,6 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so
static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
{
- /* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
@@ -532,7 +507,6 @@ static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
}
static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
{
- /* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
@@ -546,8 +520,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
{
BKE_id_blend_write(writer, &ntree->id);
- /* for link_list() speed, we write per list */
-
if (ntree->adt) {
BKE_animdata_blend_write(writer, ntree->adt);
}
@@ -571,7 +543,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
if (node->storage) {
- /* could be handlerized at some point, now only 1 exception still */
if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) &&
ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) {
BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage);
@@ -645,13 +616,13 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
if (node->type == CMP_NODE_OUTPUT_FILE) {
- /* inputs have own storage data */
+ /* Inputs have their own storage data. */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
BLO_write_struct(writer, NodeImageMultiFileSocket, sock->storage);
}
}
if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) {
- /* write extra socket info */
+ /* Write extra socket info. */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
BLO_write_struct(writer, NodeImageLayer, sock->storage);
}
@@ -715,6 +686,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
ntree->execdata = nullptr;
ntree->field_inferencing_interface = nullptr;
+ BKE_ntree_update_tag_missing_runtime_data(ntree);
BLO_read_data_address(reader, &ntree->adt);
BKE_animdata_blend_read_data(reader, ntree->adt);
@@ -747,7 +719,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
}
if (node->storage) {
- /* could be handlerized at some point */
switch (node->type) {
case SH_NODE_CURVE_VEC:
case SH_NODE_CURVE_RGB:
@@ -858,11 +829,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
/* TODO: should be dealt by new generic cache handling of IDs... */
ntree->previews = nullptr;
- if (ntree->type == NTREE_GEOMETRY) {
- /* Update field referencing for the geometry nodes modifier. */
- ntree->update |= NTREE_UPDATE_FIELD_INFERENCING;
- }
-
BLO_read_data_address(reader, &ntree->preview);
BKE_previewimg_blend_read(reader, ntree->preview);
@@ -1095,21 +1061,18 @@ static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType
return;
}
bNodeSocketTemplate *sockdef;
- /* bNodeSocket *sock; */ /* UNUSED */
if (ntype->inputs) {
sockdef = ntype->inputs;
while (sockdef->type != -1) {
- /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
-
+ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
sockdef++;
}
}
if (ntype->outputs) {
sockdef = ntype->outputs;
while (sockdef->type != -1) {
- /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
-
+ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
sockdef++;
}
}
@@ -1167,8 +1130,7 @@ static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
/* XXX Warning: context can be nullptr in case nodes are added in do_versions.
- * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment.
- */
+ * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment. */
BLI_assert(C != nullptr);
ntype->initfunc_api(C, &ptr);
}
@@ -1189,6 +1151,7 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo)
/* Deprecated integer type. */
ntree->type = ntree->typeinfo->type;
+ BKE_ntree_update_tag_all(ntree);
}
static void node_set_typeinfo(const struct bContext *C,
@@ -1239,6 +1202,7 @@ static void node_socket_set_typeinfo(bNodeTree *ntree,
ntree->init &= ~NTREE_TYPE_INIT;
}
+ BKE_ntree_update_tag_socket_type(ntree, sock);
}
/* Set specific typeinfo pointers in all node trees on register/unregister */
@@ -1382,18 +1346,6 @@ bNodeType *nodeTypeFind(const char *idname)
return nullptr;
}
-static void free_dynamic_typeinfo(bNodeType *ntype)
-{
- if (ntype->type == NODE_DYNAMIC) {
- if (ntype->inputs) {
- MEM_freeN(ntype->inputs);
- }
- if (ntype->outputs) {
- MEM_freeN(ntype->outputs);
- }
- }
-}
-
/* callback for hash value free function */
static void node_free_type(void *nodetype_v)
{
@@ -1403,11 +1355,6 @@ static void node_free_type(void *nodetype_v)
* or we'd want to update *all* active Mains, which we cannot do anyway currently. */
update_typeinfo(G_MAIN, nullptr, nullptr, nodetype, nullptr, true);
- /* XXX deprecated */
- if (nodetype->type == NODE_DYNAMIC) {
- free_dynamic_typeinfo(nodetype);
- }
-
delete nodetype->fixed_declaration;
nodetype->fixed_declaration = nullptr;
@@ -1522,6 +1469,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)
{
@@ -1552,11 +1526,11 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
/* if no explicit identifier is given, assign a unique identifier based on the name */
BLI_strncpy(auto_identifier, name, sizeof(auto_identifier));
}
- /* make the identifier unique */
+ /* Make the identifier unique. */
BLI_uniquename_cb(
unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier));
- bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "sock");
+ bNodeSocket *sock = MEM_cnew<bNodeSocket>("sock");
sock->in_out = in_out;
BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR);
@@ -1721,26 +1695,7 @@ bNodeSocket *nodeAddSocket(bNodeTree *ntree,
BLI_remlink(lb, sock); /* does nothing for new socket */
BLI_addtail(lb, sock);
- node->update |= NODE_UPDATE;
-
- return sock;
-}
-
-bNodeSocket *nodeInsertSocket(bNodeTree *ntree,
- bNode *node,
- eNodeSocketInOut in_out,
- const char *idname,
- bNodeSocket *next_sock,
- const char *identifier,
- const char *name)
-{
- ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs);
- bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name);
-
- BLI_remlink(lb, sock); /* does nothing for new socket */
- BLI_insertlinkbefore(lb, next_sock, sock);
-
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_new(ntree, sock);
return sock;
}
@@ -1961,31 +1916,7 @@ bNodeSocket *nodeAddStaticSocket(bNodeTree *ntree,
return sock;
}
-bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree,
- bNode *node,
- eNodeSocketInOut in_out,
- int type,
- int subtype,
- bNodeSocket *next_sock,
- const char *identifier,
- const char *name)
-{
- const char *idname = nodeStaticSocketType(type, subtype);
-
- if (!idname) {
- CLOG_ERROR(&LOG, "static node socket type %d undefined", type);
- return nullptr;
- }
-
- bNodeSocket *sock = nodeInsertSocket(ntree, node, in_out, idname, next_sock, identifier, name);
- sock->type = type;
- return sock;
-}
-
-static void node_socket_free(bNodeTree *UNUSED(ntree),
- bNodeSocket *sock,
- bNode *UNUSED(node),
- const bool do_id_user)
+static void node_socket_free(bNodeSocket *sock, const bool do_id_user)
{
if (sock->prop) {
IDP_FreePropertyContent_ex(sock->prop, do_id_user);
@@ -2016,14 +1947,22 @@ void nodeRemoveSocketEx(struct bNodeTree *ntree,
}
}
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &node->internal_links) {
+ if (link->fromsock == sock || link->tosock == sock) {
+ BLI_remlink(&node->internal_links, link);
+ MEM_freeN(link);
+ BKE_ntree_update_tag_node_internal_link(ntree, node);
+ }
+ }
+
/* this is fast, this way we don't need an in_out argument */
BLI_remlink(&node->inputs, sock);
BLI_remlink(&node->outputs, sock);
- node_socket_free(ntree, sock, node, do_id_user);
+ node_socket_free(sock, do_id_user);
MEM_freeN(sock);
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_removed(ntree);
}
void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
@@ -2035,18 +1974,18 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
}
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
- node_socket_free(ntree, sock, node, true);
+ node_socket_free(sock, true);
MEM_freeN(sock);
}
BLI_listbase_clear(&node->inputs);
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) {
- node_socket_free(ntree, sock, node, true);
+ node_socket_free(sock, true);
MEM_freeN(sock);
}
BLI_listbase_clear(&node->outputs);
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_removed(ntree);
}
bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name)
@@ -2192,13 +2131,17 @@ void nodeUniqueName(bNodeTree *ntree, bNode *node)
bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname)
{
- bNode *node = (bNode *)MEM_callocN(sizeof(bNode), "new node");
+ bNode *node = MEM_cnew<bNode>("new node");
BLI_addtail(&ntree->nodes, node);
BLI_strncpy(node->idname, idname, sizeof(node->idname));
node_set_typeinfo(C, ntree, node, nodeTypeFind(idname));
- ntree->update |= NTREE_UPDATE_NODES;
+ BKE_ntree_update_tag_node_new(ntree, node);
+
+ if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
+ DEG_relations_tag_update(CTX_data_main(C));
+ }
return node;
}
@@ -2208,9 +2151,8 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type)
const char *idname = nullptr;
NODE_TYPES_BEGIN (ntype) {
- /* do an extra poll here, because some int types are used
- * for multiple node types, this helps find the desired type
- */
+ /* Do an extra poll here, because some int types are used
+ * for multiple node types, this helps find the desired type. */
const char *disabled_hint;
if (ntype->type == type && (!ntype->poll || ntype->poll(ntype, ntree, &disabled_hint))) {
idname = ntype->idname;
@@ -2240,143 +2182,98 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
}
sock_dst->stack_index = 0;
- /* XXX some compositor node (e.g. image, render layers) still store
- * some persistent buffer data here, need to clear this to avoid dangling pointers.
- */
+ /* XXX some compositor nodes (e.g. image, render layers) still store
+ * some persistent buffer data here, need to clear this to avoid dangling pointers. */
sock_dst->cache = nullptr;
}
-bNode *BKE_node_copy_ex(bNodeTree *ntree,
- const bNode *node_src,
- const int flag,
- const bool unique_name)
-{
- bNode *node_dst = (bNode *)MEM_callocN(sizeof(bNode), "dupli node");
- bNodeSocket *sock_dst, *sock_src;
- bNodeLink *link_dst, *link_src;
+namespace blender::bke {
- *node_dst = *node_src;
+bNode *node_copy_with_mapping(bNodeTree *dst_tree,
+ const bNode &node_src,
+ const int flag,
+ const bool unique_name,
+ Map<const bNodeSocket *, bNodeSocket *> &socket_map)
+{
+ bNode *node_dst = (bNode *)MEM_mallocN(sizeof(bNode), __func__);
+ *node_dst = node_src;
- /* can be called for nodes outside a node tree (e.g. clipboard) */
- if (ntree) {
+ /* Can be called for nodes outside a node tree (e.g. clipboard). */
+ if (dst_tree) {
if (unique_name) {
- nodeUniqueName(ntree, node_dst);
+ nodeUniqueName(dst_tree, node_dst);
}
-
- BLI_addtail(&ntree->nodes, node_dst);
+ BLI_addtail(&dst_tree->nodes, node_dst);
}
- BLI_duplicatelist(&node_dst->inputs, &node_src->inputs);
- for (sock_dst = (bNodeSocket *)node_dst->inputs.first,
- sock_src = (bNodeSocket *)node_src->inputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag);
+ BLI_listbase_clear(&node_dst->inputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.inputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag);
+ BLI_addtail(&node_dst->inputs, dst_socket);
+ socket_map.add_new(src_socket, dst_socket);
}
- BLI_duplicatelist(&node_dst->outputs, &node_src->outputs);
- for (sock_dst = (bNodeSocket *)node_dst->outputs.first,
- sock_src = (bNodeSocket *)node_src->outputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag);
+ BLI_listbase_clear(&node_dst->outputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.outputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag);
+ BLI_addtail(&node_dst->outputs, dst_socket);
+ socket_map.add_new(src_socket, dst_socket);
}
- if (node_src->prop) {
- node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag);
+ if (node_src.prop) {
+ node_dst->prop = IDP_CopyProperty_ex(node_src.prop, flag);
}
- BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links);
- for (link_dst = (bNodeLink *)node_dst->internal_links.first,
- link_src = (bNodeLink *)node_src->internal_links.first;
- link_dst != nullptr;
- link_dst = (bNodeLink *)link_dst->next, link_src = (bNodeLink *)link_src->next) {
- /* This is a bit annoying to do index lookups in a list, but is likely to be faster than
- * trying to create a hash-map. At least for usual nodes, which only have so much sockets
- * and internal links. */
- const int from_sock_index = BLI_findindex(&node_src->inputs, link_src->fromsock);
- const int to_sock_index = BLI_findindex(&node_src->outputs, link_src->tosock);
- BLI_assert(from_sock_index != -1);
- BLI_assert(to_sock_index != -1);
- link_dst->fromnode = node_dst;
- link_dst->tonode = node_dst;
- link_dst->fromsock = (bNodeSocket *)BLI_findlink(&node_dst->inputs, from_sock_index);
- link_dst->tosock = (bNodeSocket *)BLI_findlink(&node_dst->outputs, to_sock_index);
+ BLI_listbase_clear(&node_dst->internal_links);
+ LISTBASE_FOREACH (const bNodeLink *, src_link, &node_src.internal_links) {
+ bNodeLink *dst_link = (bNodeLink *)MEM_dupallocN(src_link);
+ dst_link->fromnode = node_dst;
+ dst_link->tonode = node_dst;
+ dst_link->fromsock = socket_map.lookup(src_link->fromsock);
+ dst_link->tosock = socket_map.lookup(src_link->tosock);
+ BLI_addtail(&node_dst->internal_links, dst_link);
}
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
id_us_plus(node_dst->id);
}
- if (node_src->typeinfo->copyfunc) {
- node_src->typeinfo->copyfunc(ntree, node_dst, node_src);
+ if (node_src.typeinfo->copyfunc) {
+ node_src.typeinfo->copyfunc(dst_tree, node_dst, &node_src);
}
- node_dst->new_node = nullptr;
-
/* Only call copy function when a copy is made for the main database, not
* for cases like the dependency graph and localization. */
if (node_dst->typeinfo->copyfunc_api && !(flag & LIB_ID_CREATE_NO_MAIN)) {
PointerRNA ptr;
- RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr);
+ RNA_pointer_create((ID *)dst_tree, &RNA_Node, node_dst, &ptr);
- node_dst->typeinfo->copyfunc_api(&ptr, node_src);
+ node_dst->typeinfo->copyfunc_api(&ptr, &node_src);
}
- if (ntree) {
- ntree->update |= NTREE_UPDATE_NODES;
+ if (dst_tree) {
+ BKE_ntree_update_tag_node_new(dst_tree, node_dst);
}
/* Reset the declaration of the new node. */
node_dst->declaration = nullptr;
- nodeDeclarationEnsure(ntree, node_dst);
+ nodeDeclarationEnsure(dst_tree, node_dst);
return node_dst;
}
-static void node_set_new_pointers(bNode *node_src, bNode *new_node)
+bNode *node_copy(bNodeTree *dst_tree,
+ const bNode &src_node,
+ const int flag,
+ const bool unique_name)
{
- /* Store mapping to the node itself. */
- node_src->new_node = new_node;
- /* Store mapping to inputs. */
- bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first;
- bNodeSocket *input_sock_src = (bNodeSocket *)node_src->inputs.first;
- while (new_input_sock != nullptr) {
- input_sock_src->new_sock = new_input_sock;
- new_input_sock = new_input_sock->next;
- input_sock_src = input_sock_src->next;
- }
- /* Store mapping to outputs. */
- bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first;
- bNodeSocket *output_sock_src = (bNodeSocket *)node_src->outputs.first;
- while (new_output_sock != nullptr) {
- output_sock_src->new_sock = new_output_sock;
- new_output_sock = new_output_sock->next;
- output_sock_src = output_sock_src->next;
- }
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+ return node_copy_with_mapping(dst_tree, src_node, flag, unique_name, socket_map);
}
-bNode *BKE_node_copy_store_new_pointers(bNodeTree *ntree, bNode *node_src, const int flag)
-{
- bNode *new_node = BKE_node_copy_ex(ntree, node_src, flag, true);
- node_set_new_pointers(node_src, new_node);
- return new_node;
-}
-
-bNodeTree *ntreeCopyTree_ex_new_pointers(const bNodeTree *ntree,
- Main *bmain,
- const bool do_id_user)
-{
- bNodeTree *new_ntree = ntreeCopyTree_ex(ntree, bmain, do_id_user);
- bNode *new_node = (bNode *)new_ntree->nodes.first;
- bNode *node_src = (bNode *)ntree->nodes.first;
- while (new_node != nullptr) {
- node_set_new_pointers(node_src, new_node);
- new_node = new_node->next;
- node_src = node_src->next;
- }
- return new_ntree;
-}
+} // namespace blender::bke
static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
{
@@ -2394,12 +2291,12 @@ bNodeLink *nodeAddLink(
{
bNodeLink *link = nullptr;
- /* test valid input */
+ /* Test valid input. */
BLI_assert(fromnode);
BLI_assert(tonode);
if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) {
- link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link");
+ link = MEM_cnew<bNodeLink>("link");
if (ntree) {
BLI_addtail(&ntree->links, link);
}
@@ -2410,7 +2307,7 @@ bNodeLink *nodeAddLink(
}
else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) {
/* OK but flip */
- link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link");
+ link = MEM_cnew<bNodeLink>("link");
if (ntree) {
BLI_addtail(&ntree->links, link);
}
@@ -2421,7 +2318,7 @@ bNodeLink *nodeAddLink(
}
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
}
if (link != nullptr && link->tosock->flag & SOCK_MULTI_INPUT) {
@@ -2433,7 +2330,7 @@ bNodeLink *nodeAddLink(
void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
{
- /* can be called for links outside a node tree (e.g. clipboard) */
+ /* Can be called for links outside a node tree (e.g. clipboard). */
if (ntree) {
BLI_remlink(&ntree->links, link);
}
@@ -2444,7 +2341,7 @@ void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
MEM_freeN(link);
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_removed(ntree);
}
}
@@ -2544,7 +2441,7 @@ void nodeMuteLinkToggle(bNodeTree *ntree, bNodeLink *link)
}
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_mute(ntree, link);
}
}
@@ -2555,8 +2452,6 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
nodeRemLink(ntree, link);
}
}
-
- ntree->update |= NTREE_UPDATE_LINKS;
}
bool nodeLinkIsHidden(const bNodeLink *link)
@@ -2621,7 +2516,7 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
link->flag |= NODE_LINK_MUTED;
}
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_changed(ntree);
}
else {
if (link->tosock->flag & SOCK_MULTI_INPUT) {
@@ -2815,13 +2710,16 @@ bool BKE_node_preview_used(const bNode *node)
return (node->typeinfo->flag & NODE_PREVIEW) != 0;
}
-bNodePreview *BKE_node_preview_verify(
- bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create)
+bNodePreview *BKE_node_preview_verify(bNodeInstanceHash *previews,
+ bNodeInstanceKey key,
+ const int xsize,
+ const int ysize,
+ const bool create)
{
bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key);
if (!preview) {
if (create) {
- preview = (bNodePreview *)MEM_callocN(sizeof(bNodePreview), "node preview");
+ preview = MEM_cnew<bNodePreview>("node preview");
BKE_node_instance_hash_insert(previews, key, preview);
}
else {
@@ -2873,9 +2771,8 @@ void BKE_node_preview_free(bNodePreview *preview)
static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
bNodeTree *ntree,
bNodeInstanceKey parent_key,
- int xsize,
- int ysize,
- bool create_previews)
+ const int xsize,
+ const int ysize)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
@@ -2884,17 +2781,16 @@ static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
node->preview_xsize = xsize;
node->preview_ysize = ysize;
- BKE_node_preview_verify(previews, key, xsize, ysize, create_previews);
+ BKE_node_preview_verify(previews, key, xsize, ysize, false);
}
if (node->type == NODE_GROUP && node->id) {
- node_preview_init_tree_recursive(
- previews, (bNodeTree *)node->id, key, xsize, ysize, create_previews);
+ node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize);
}
}
}
-void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool create_previews)
+void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize)
{
if (!ntree) {
return;
@@ -2904,8 +2800,7 @@ void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool cre
ntree->previews = BKE_node_instance_hash_new("node previews");
}
- node_preview_init_tree_recursive(
- ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize, create_previews);
+ node_preview_init_tree_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize);
}
static void node_preview_tag_used_recursive(bNodeInstanceHash *previews,
@@ -2939,18 +2834,6 @@ void BKE_node_preview_remove_unused(bNodeTree *ntree)
(bNodeInstanceValueFP)BKE_node_preview_free);
}
-void BKE_node_preview_free_tree(bNodeTree *ntree)
-{
- if (!ntree) {
- return;
- }
-
- if (ntree->previews) {
- BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
- ntree->previews = nullptr;
- }
-}
-
void BKE_node_preview_clear(bNodePreview *preview)
{
if (preview && preview->rect) {
@@ -2971,40 +2854,6 @@ void BKE_node_preview_clear_tree(bNodeTree *ntree)
}
}
-static void node_preview_sync(bNodePreview *to, bNodePreview *from)
-{
- /* sizes should have been initialized by BKE_node_preview_init_tree */
- BLI_assert(to->xsize == from->xsize && to->ysize == from->ysize);
-
- /* copy over contents of previews */
- if (to->rect && from->rect) {
- int xsize = to->xsize;
- int ysize = to->ysize;
- memcpy(to->rect, from->rect, xsize * ysize * sizeof(char[4]));
- }
-}
-
-void BKE_node_preview_sync_tree(bNodeTree *to_ntree, bNodeTree *from_ntree)
-{
- bNodeInstanceHash *from_previews = from_ntree->previews;
- bNodeInstanceHash *to_previews = to_ntree->previews;
-
- if (!from_previews || !to_previews) {
- return;
- }
-
- bNodeInstanceHashIterator iter;
- NODE_INSTANCE_HASH_ITER (iter, from_previews) {
- bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
- bNodePreview *from = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter);
- bNodePreview *to = (bNodePreview *)BKE_node_instance_hash_lookup(to_previews, key);
-
- if (from && to) {
- node_preview_sync(to, from);
- }
- }
-}
-
void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, bool remove_old)
{
if (remove_old || !to_ntree->previews) {
@@ -3041,27 +2890,6 @@ void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, boo
}
}
-void BKE_node_preview_set_pixel(
- bNodePreview *preview, const float col[4], int x, int y, bool do_manage)
-{
- if (preview) {
- if (x >= 0 && y >= 0) {
- if (x < preview->xsize && y < preview->ysize) {
- unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x);
-
- if (do_manage) {
- linearrgb_to_srgb_uchar4(tar, col);
- }
- else {
- rgba_float_to_uchar(tar, col);
- }
- }
- // else printf("prv out bound x y %d %d\n", x, y);
- }
- // else printf("prv out bound x y %d %d\n", x, y);
- }
-}
-
/* ************** Free stuff ********** */
void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
@@ -3070,9 +2898,6 @@ void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
ListBase *lb;
if (link->fromnode == node) {
lb = &node->outputs;
- if (link->tonode) {
- link->tonode->update |= NODE_UPDATE;
- }
}
else if (link->tonode == node) {
lb = &node->inputs;
@@ -3114,10 +2939,6 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
/* can be called for nodes outside a node tree (e.g. clipboard) */
if (ntree) {
- /* remove all references to this node */
- nodeUnlinkNode(ntree, node);
- node_unlink_attached(ntree, node);
-
BLI_remlink(&ntree->nodes, node);
if (ntree->typeinfo->free_node_cache) {
@@ -3137,12 +2958,12 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
/* Remember, no ID user refcount management here! */
- node_socket_free(ntree, sock, node, false);
+ node_socket_free(sock, false);
MEM_freeN(sock);
}
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) {
/* Remember, no ID user refcount management here! */
- node_socket_free(ntree, sock, node, false);
+ node_socket_free(sock, false);
MEM_freeN(sock);
}
@@ -3161,7 +2982,7 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
MEM_freeN(node);
if (ntree) {
- ntree->update |= NTREE_UPDATE_NODES;
+ BKE_ntree_update_tag_node_removed(ntree);
}
}
@@ -3169,6 +2990,12 @@ void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node)
{
/* For removing nodes while editing localized node trees. */
BLI_assert((ntree->id.tag & LIB_TAG_LOCALIZED) != 0);
+
+ /* These two lines assume the caller might want to free a single node and maintain
+ * a valid state in the node tree. */
+ nodeUnlinkNode(ntree, node);
+ node_unlink_attached(ntree, node);
+
node_free_node(ntree, node);
}
@@ -3213,6 +3040,9 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
}
}
+ nodeUnlinkNode(ntree, node);
+ node_unlink_attached(ntree, node);
+
/* Free node itself. */
node_free_node(ntree, node);
}
@@ -3238,8 +3068,7 @@ static void free_localized_node_groups(bNodeTree *ntree)
/* Only localized node trees store a copy for each node group tree.
* Each node group tree in a localized node tree can be freed,
* since it is a localized copy itself (no risk of accessing free'd
- * data in main, see T37939).
- */
+ * data in main, see T37939). */
if (!(ntree->id.tag & LIB_TAG_LOCALIZED)) {
return;
}
@@ -3384,26 +3213,6 @@ bNodeTree *ntreeFromID(ID *id)
return (nodetree != nullptr) ? *nodetree : nullptr;
}
-bool ntreeNodeExists(const bNodeTree *ntree, const bNode *testnode)
-{
- LISTBASE_FOREACH (const bNode *, node, &ntree->nodes) {
- if (node == testnode) {
- return true;
- }
- }
- return false;
-}
-
-bool ntreeOutputExists(const bNode *node, const bNodeSocket *testsock)
-{
- LISTBASE_FOREACH (const bNodeSocket *, sock, &node->outputs) {
- if (sock == testsock) {
- return true;
- }
- }
- return false;
-}
-
void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -3435,7 +3244,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
}
}
- /* ensures only a single output node is enabled */
+ /* Ensures only a single output node is enabled. */
ntreeSetOutput(ntree);
bNode *node_src = (bNode *)ntree->nodes.first;
@@ -3453,15 +3262,6 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
return ltree;
}
-void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
-{
- if (localtree && ntree) {
- if (ntree->typeinfo->local_sync) {
- ntree->typeinfo->local_sync(localtree, ntree);
- }
- }
-}
-
void ntreeLocalMerge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
{
if (ntree && localtree) {
@@ -3486,7 +3286,7 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree,
return nullptr;
}
- bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "socket template");
+ bNodeSocket *sock = MEM_cnew<bNodeSocket>("socket template");
BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname));
node_socket_set_typeinfo(ntree, sock, stype);
sock->in_out = in_out;
@@ -3532,12 +3332,11 @@ bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree,
bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name);
if (in_out == SOCK_IN) {
BLI_addtail(&ntree->inputs, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_IN;
}
else if (in_out == SOCK_OUT) {
BLI_addtail(&ntree->outputs, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
}
+ BKE_ntree_update_tag_interface(ntree);
return iosock;
}
@@ -3550,12 +3349,11 @@ bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree,
bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name);
if (in_out == SOCK_IN) {
BLI_insertlinkbefore(&ntree->inputs, next_sock, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_IN;
}
else if (in_out == SOCK_OUT) {
BLI_insertlinkbefore(&ntree->outputs, next_sock, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
}
+ BKE_ntree_update_tag_interface(ntree);
return iosock;
}
@@ -3601,7 +3399,7 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
node_socket_interface_free(ntree, sock, true);
MEM_freeN(sock);
- ntree->update |= NTREE_UPDATE_GROUP;
+ BKE_ntree_update_tag_interface(ntree);
}
/* generates a valid RNA identifier from the node tree name */
@@ -3739,11 +3537,6 @@ bNode *ntreeFindType(const bNodeTree *ntree, int type)
return nullptr;
}
-bool ntreeHasType(const bNodeTree *ntree, int type)
-{
- return ntreeFindType(ntree, type) != nullptr;
-}
-
bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup)
{
if (ntree == lookup) {
@@ -3797,93 +3590,6 @@ bNode *nodeGetActive(bNodeTree *ntree)
return nullptr;
}
-static bNode *node_get_active_id_recursive(bNodeInstanceKey active_key,
- bNodeInstanceKey parent_key,
- bNodeTree *ntree,
- short idtype)
-{
- if (parent_key.value == active_key.value || active_key.value == 0) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id && GS(node->id->name) == idtype) {
- if (node->flag & NODE_ACTIVE_ID) {
- return node;
- }
- }
- }
- }
- else {
- /* no node with active ID in this tree, look inside groups */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == NODE_GROUP) {
- bNodeTree *group = (bNodeTree *)node->id;
- if (group) {
- bNodeInstanceKey group_key = BKE_node_instance_key(parent_key, ntree, node);
- bNode *tnode = node_get_active_id_recursive(active_key, group_key, group, idtype);
- if (tnode) {
- return tnode;
- }
- }
- }
- }
- }
- return nullptr;
-}
-
-bNode *nodeGetActiveID(bNodeTree *ntree, short idtype)
-{
- if (ntree) {
- return node_get_active_id_recursive(
- ntree->active_viewer_key, NODE_INSTANCE_KEY_BASE, ntree, idtype);
- }
- return nullptr;
-}
-
-bool nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id)
-{
- bool ok = false;
-
- if (ntree == nullptr) {
- return ok;
- }
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id && GS(node->id->name) == idtype) {
- if (id && ok == false && node->id == id) {
- node->flag |= NODE_ACTIVE_ID;
- ok = true;
- }
- else {
- node->flag &= ~NODE_ACTIVE_ID;
- }
- }
- }
-
- /* update all groups linked from here
- * if active ID node has been found already,
- * just pass null so other matching nodes are deactivated.
- */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == NODE_GROUP) {
- ok |= nodeSetActiveID((bNodeTree *)node->id, idtype, (ok == false ? id : nullptr));
- }
- }
-
- return ok;
-}
-
-void nodeClearActiveID(bNodeTree *ntree, short idtype)
-{
- if (ntree == nullptr) {
- return;
- }
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id && GS(node->id->name) == idtype) {
- node->flag &= ~NODE_ACTIVE_ID;
- }
- }
-}
-
void nodeSetSelected(bNode *node, bool select)
{
if (select) {
@@ -3909,7 +3615,7 @@ void nodeClearActive(bNodeTree *ntree)
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_ID);
+ node->flag &= ~NODE_ACTIVE;
}
}
@@ -3919,11 +3625,6 @@ void nodeSetActive(bNodeTree *ntree, bNode *node)
LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) {
tnode->flag &= ~NODE_ACTIVE;
- if (node->id && tnode->id) {
- if (GS(node->id->name) == GS(tnode->id->name)) {
- tnode->flag &= ~NODE_ACTIVE_ID;
- }
- }
if ((node->typeinfo->nclass == NODE_CLASS_TEXTURE) ||
(node->typeinfo->type == GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE)) {
tnode->flag &= ~NODE_ACTIVE_TEXTURE;
@@ -3931,9 +3632,6 @@ void nodeSetActive(bNodeTree *ntree, bNode *node)
}
node->flag |= NODE_ACTIVE;
- if (node->id) {
- node->flag |= NODE_ACTIVE_ID;
- }
if ((node->typeinfo->nclass == NODE_CLASS_TEXTURE) ||
(node->typeinfo->type == GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE)) {
node->flag |= NODE_ACTIVE_TEXTURE;
@@ -3945,10 +3643,13 @@ int nodeSocketIsHidden(const bNodeSocket *sock)
return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0);
}
-void nodeSetSocketAvailability(bNodeTree *UNUSED(ntree), bNodeSocket *sock, bool is_available)
+void nodeSetSocketAvailability(bNodeTree *ntree, bNodeSocket *sock, bool is_available)
{
- /* #ntree is not needed right now, but it's generally necessary when changing the tree because we
- * want to tag it as changed in the future. */
+ const bool was_available = (sock->flag & SOCK_UNAVAIL) == 0;
+ if (is_available != was_available) {
+ BKE_ntree_update_tag_socket_availability(ntree, sock);
+ }
+
if (is_available) {
sock->flag &= ~SOCK_UNAVAIL;
}
@@ -4400,7 +4101,7 @@ void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***r_deplist,
}
/* only updates node->level for detecting cycles links */
-static void ntree_update_node_level(bNodeTree *ntree)
+void ntreeUpdateNodeLevels(bNodeTree *ntree)
{
/* first clear tag */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -4415,768 +4116,42 @@ static void ntree_update_node_level(bNodeTree *ntree)
}
}
-void ntreeTagUsedSockets(bNodeTree *ntree)
-{
- /* first clear data */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- sock->flag &= ~SOCK_IN_USE;
- }
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
- sock->flag &= ~SOCK_IN_USE;
- }
- }
-
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- link->fromsock->flag |= SOCK_IN_USE;
- if (!(link->flag & NODE_LINK_MUTED)) {
- link->tosock->flag |= SOCK_IN_USE;
- }
- }
-}
-
-static void ntree_update_link_pointers(bNodeTree *ntree)
-{
- /* first clear data */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- sock->link = nullptr;
- }
- }
-
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- link->tosock->link = link;
- }
-
- ntreeTagUsedSockets(ntree);
-}
-
-static void ntree_validate_links(bNodeTree *ntree)
-{
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- link->flag |= NODE_LINK_VALID;
- if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) {
- link->flag &= ~NODE_LINK_VALID;
- }
- else if (ntree->typeinfo->validate_link) {
- if (!ntree->typeinfo->validate_link(ntree, link)) {
- link->flag &= ~NODE_LINK_VALID;
- }
- }
- }
-}
-
void ntreeUpdateAllNew(Main *main)
{
+ Vector<bNodeTree *> new_ntrees;
+
/* Update all new node trees on file read or append, to add/remove sockets
* in groups nodes if the group changed, and handle any update flags that
* might have been set in file reading or versioning. */
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
if (owner_id->tag & LIB_TAG_NEW) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->typeinfo->group_update_func) {
- node->typeinfo->group_update_func(ntree, node);
- }
- }
-
- ntreeUpdateTree(nullptr, ntree);
+ BKE_ntree_update_tag_all(ntree);
}
}
FOREACH_NODETREE_END;
+ BKE_ntree_update_main(main, nullptr);
}
-namespace blender::bke::node_field_inferencing {
-
-static bool is_field_socket_type(eNodeSocketDatatype type)
-{
- return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
-}
-
-static bool is_field_socket_type(const SocketRef &socket)
-{
- return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type);
-}
-
-static bool update_field_inferencing(bNodeTree &btree);
-
-static InputSocketFieldType get_interface_input_field_type(const NodeRef &node,
- const InputSocketRef &socket)
-{
- if (!is_field_socket_type(socket)) {
- return InputSocketFieldType::None;
- }
- if (node.is_reroute_node()) {
- return InputSocketFieldType::IsSupported;
- }
- if (node.is_group_output_node()) {
- /* Outputs always support fields when the data type is correct. */
- return InputSocketFieldType::IsSupported;
- }
- if (node.is_undefined()) {
- return InputSocketFieldType::None;
- }
-
- const NodeDeclaration *node_decl = node.declaration();
-
- /* Node declarations should be implemented for nodes involved here. */
- BLI_assert(node_decl != nullptr);
-
- /* Get the field type from the declaration. */
- const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()];
- const InputSocketFieldType field_type = socket_decl.input_field_type();
- if (field_type == InputSocketFieldType::Implicit) {
- return field_type;
- }
- if (node_decl->is_function_node()) {
- /* In a function node, every socket supports fields. */
- return InputSocketFieldType::IsSupported;
- }
- return field_type;
-}
-
-static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node,
- const OutputSocketRef &socket)
-{
- if (!is_field_socket_type(socket)) {
- /* Non-field sockets always output data. */
- return OutputFieldDependency::ForDataSource();
- }
- if (node.is_reroute_node()) {
- /* The reroute just forwards what is passed in. */
- return OutputFieldDependency::ForDependentField();
- }
- if (node.is_group_input_node()) {
- /* Input nodes get special treatment in #determine_group_input_states. */
- return OutputFieldDependency::ForDependentField();
- }
- if (node.is_undefined()) {
- return OutputFieldDependency::ForDataSource();
- }
-
- const NodeDeclaration *node_decl = node.declaration();
-
- /* Node declarations should be implemented for nodes involved here. */
- BLI_assert(node_decl != nullptr);
-
- if (node_decl->is_function_node()) {
- /* In a generic function node, all outputs depend on all inputs. */
- return OutputFieldDependency::ForDependentField();
- }
-
- /* Use the socket declaration. */
- const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()];
- return socket_decl.output_field_dependency();
-}
-
-static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node)
-{
- FieldInferencingInterface inferencing_interface;
- inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size());
- inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(),
- node.outputs().size());
- return inferencing_interface;
-}
-
-/**
- * Retrieves information about how the node interacts with fields.
- * In the future, this information can be stored in the node declaration. This would allow this
- * function to return a reference, making it more efficient.
- */
-static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node)
-{
- /* Node groups already reference all required information, so just return that. */
- if (node.is_group_node()) {
- bNodeTree *group = (bNodeTree *)node.bnode()->id;
- if (group == nullptr) {
- return FieldInferencingInterface();
- }
- if (!ntreeIsRegistered(group)) {
- /* This can happen when there is a linked node group that was not found (see T92799). */
- return get_dummy_field_inferencing_interface(node);
- }
- if (group->field_inferencing_interface == nullptr) {
- /* Update group recursively. */
- update_field_inferencing(*group);
- }
- return *group->field_inferencing_interface;
- }
-
- FieldInferencingInterface inferencing_interface;
- for (const InputSocketRef *input_socket : node.inputs()) {
- inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket));
- }
-
- for (const OutputSocketRef *output_socket : node.outputs()) {
- inferencing_interface.outputs.append(
- get_interface_output_field_dependency(node, *output_socket));
- }
- return inferencing_interface;
-}
-
-/**
- * This struct contains information for every socket. The values are propagated through the
- * network.
- */
-struct SocketFieldState {
- /* This socket starts a new field. */
- bool is_field_source = false;
- /* This socket can never become a field, because the node itself does not support it. */
- bool is_always_single = false;
- /* This socket is currently a single value. It could become a field though. */
- bool is_single = true;
- /* This socket is required to be a single value. This can be because the node itself only
- * supports this socket to be a single value, or because a node afterwards requires this to be a
- * single value. */
- bool requires_single = false;
-};
-
-static Vector<const InputSocketRef *> gather_input_socket_dependencies(
- const OutputFieldDependency &field_dependency, const NodeRef &node)
-{
- const OutputSocketFieldType type = field_dependency.field_type();
- Vector<const InputSocketRef *> input_sockets;
- switch (type) {
- case OutputSocketFieldType::FieldSource:
- case OutputSocketFieldType::None: {
- break;
- }
- case OutputSocketFieldType::DependentField: {
- /* This output depends on all inputs. */
- input_sockets.extend(node.inputs());
- break;
- }
- case OutputSocketFieldType::PartiallyDependent: {
- /* This output depends only on a few inputs. */
- for (const int i : field_dependency.linked_input_indices()) {
- input_sockets.append(&node.input(i));
- }
- break;
- }
- }
- return input_sockets;
-}
-
-/**
- * Check what the group output socket depends on. Potentially traverses the node tree
- * to figure out if it is always a field or if it depends on any group inputs.
- */
-static OutputFieldDependency find_group_output_dependencies(
- const InputSocketRef &group_output_socket,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- if (!is_field_socket_type(group_output_socket)) {
- return OutputFieldDependency::ForDataSource();
- }
-
- /* Use a Set here instead of an array indexed by socket id, because we my only need to look at
- * very few sockets. */
- Set<const InputSocketRef *> handled_sockets;
- Stack<const InputSocketRef *> sockets_to_check;
-
- handled_sockets.add(&group_output_socket);
- sockets_to_check.push(&group_output_socket);
-
- /* Keeps track of group input indices that are (indirectly) connected to the output. */
- Vector<int> linked_input_indices;
-
- while (!sockets_to_check.is_empty()) {
- const InputSocketRef *input_socket = sockets_to_check.pop();
-
- for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
- const NodeRef &origin_node = origin_socket->node();
- const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
-
- if (origin_state.is_field_source) {
- if (origin_node.is_group_input_node()) {
- /* Found a group input that the group output depends on. */
- linked_input_indices.append_non_duplicates(origin_socket->index());
- }
- else {
- /* Found a field source that is not the group input. So the output is always a field. */
- return OutputFieldDependency::ForFieldSource();
- }
- }
- else if (!origin_state.is_single) {
- const FieldInferencingInterface inferencing_interface =
- get_node_field_inferencing_interface(origin_node);
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[origin_socket->index()];
-
- /* Propagate search further to the left. */
- for (const InputSocketRef *origin_input_socket :
- gather_input_socket_dependencies(field_dependency, origin_node)) {
- if (!origin_input_socket->is_available()) {
- continue;
- }
- if (!field_state_by_socket_id[origin_input_socket->id()].is_single) {
- if (handled_sockets.add(origin_input_socket)) {
- sockets_to_check.push(origin_input_socket);
- }
- }
- }
- }
- }
- }
- return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices));
-}
-
-static void propagate_data_requirements_from_right_to_left(
- const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
- NodeTreeRef::ToposortDirection::RightToLeft);
-
- for (const NodeRef *node : toposort_result.sorted_nodes) {
- const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
- *node);
-
- for (const OutputSocketRef *output_socket : node->outputs()) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
-
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[output_socket->index()];
-
- if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) {
- continue;
- }
- if (field_dependency.field_type() == OutputSocketFieldType::None) {
- state.requires_single = true;
- state.is_always_single = true;
- continue;
- }
-
- /* The output is required to be a single value when it is connected to any input that does
- * not support fields. */
- for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
- if (target_socket->is_available()) {
- state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
- }
- }
-
- if (state.requires_single) {
- bool any_input_is_field_implicitly = false;
- const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies(
- field_dependency, *node);
- for (const InputSocketRef *input_socket : connected_inputs) {
- if (!input_socket->is_available()) {
- continue;
- }
- if (inferencing_interface.inputs[input_socket->index()] ==
- InputSocketFieldType::Implicit) {
- if (!input_socket->is_logically_linked()) {
- any_input_is_field_implicitly = true;
- break;
- }
- }
- }
- if (any_input_is_field_implicitly) {
- /* This output isn't a single value actually. */
- state.requires_single = false;
- }
- else {
- /* If the output is required to be a single value, the connected inputs in the same node
- * must not be fields as well. */
- for (const InputSocketRef *input_socket : connected_inputs) {
- field_state_by_socket_id[input_socket->id()].requires_single = true;
- }
- }
- }
- }
-
- /* Some inputs do not require fields independent of what the outputs are connected to. */
- for (const InputSocketRef *input_socket : node->inputs()) {
- SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
- if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) {
- state.requires_single = true;
- state.is_always_single = true;
- }
- }
- }
-}
-
-static void determine_group_input_states(
- const NodeTreeRef &tree,
- FieldInferencingInterface &new_inferencing_interface,
- const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- {
- /* Non-field inputs never support fields. */
- int index;
- LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) {
- if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) {
- new_inferencing_interface.inputs[index] = InputSocketFieldType::None;
- }
- }
- }
- /* Check if group inputs are required to be single values, because they are (indirectly)
- * connected to some socket that does not support fields. */
- for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
- for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- if (state.requires_single) {
- new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None;
- }
- }
- }
- /* If an input does not support fields, this should be reflected in all Group Input nodes. */
- for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
- for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=
- InputSocketFieldType::None;
- if (supports_field) {
- state.is_single = false;
- state.is_field_source = true;
- }
- else {
- state.requires_single = true;
- }
- }
- SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()];
- dummy_socket_state.requires_single = true;
- }
-}
-
-static void propagate_field_status_from_left_to_right(
- const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
- NodeTreeRef::ToposortDirection::LeftToRight);
-
- for (const NodeRef *node : toposort_result.sorted_nodes) {
- if (node->is_group_input_node()) {
- continue;
- }
-
- const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
- *node);
-
- /* Update field state of input sockets, also taking into account linked origin sockets. */
- for (const InputSocketRef *input_socket : node->inputs()) {
- SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
- if (state.is_always_single) {
- state.is_single = true;
- continue;
- }
- state.is_single = true;
- if (input_socket->directly_linked_sockets().is_empty()) {
- if (inferencing_interface.inputs[input_socket->index()] ==
- InputSocketFieldType::Implicit) {
- state.is_single = false;
- }
- }
- else {
- for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
- if (!field_state_by_socket_id[origin_socket->id()].is_single) {
- state.is_single = false;
- break;
- }
- }
- }
- }
-
- /* Update field state of output sockets, also taking into account input sockets. */
- for (const OutputSocketRef *output_socket : node->outputs()) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[output_socket->index()];
-
- switch (field_dependency.field_type()) {
- case OutputSocketFieldType::None: {
- state.is_single = true;
- break;
- }
- case OutputSocketFieldType::FieldSource: {
- state.is_single = false;
- state.is_field_source = true;
- break;
- }
- case OutputSocketFieldType::PartiallyDependent:
- case OutputSocketFieldType::DependentField: {
- for (const InputSocketRef *input_socket :
- gather_input_socket_dependencies(field_dependency, *node)) {
- if (!input_socket->is_available()) {
- continue;
- }
- if (!field_state_by_socket_id[input_socket->id()].is_single) {
- state.is_single = false;
- break;
- }
- }
- break;
- }
- }
- }
- }
-}
-
-static void determine_group_output_states(const NodeTreeRef &tree,
- FieldInferencingInterface &new_inferencing_interface,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
- /* Ignore inactive group output nodes. */
- if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) {
- continue;
- }
- /* Determine dependencies of all group outputs. */
- for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) {
- OutputFieldDependency field_dependency = find_group_output_dependencies(
- *group_output_socket, field_state_by_socket_id);
- new_inferencing_interface.outputs[group_output_socket->index()] = std::move(
- field_dependency);
- }
- break;
- }
-}
-
-static void update_socket_shapes(const NodeTreeRef &tree,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
- const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT;
- const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
-
- auto get_shape_for_state = [&](const SocketFieldState &state) {
- if (state.is_always_single) {
- return requires_data_shape;
- }
- if (!state.is_single) {
- return is_field_shape;
- }
- if (state.requires_single) {
- return requires_data_shape;
- }
- return data_but_can_be_field_shape;
- };
-
- for (const InputSocketRef *socket : tree.input_sockets()) {
- bNodeSocket *bsocket = socket->bsocket();
- const SocketFieldState &state = field_state_by_socket_id[socket->id()];
- bsocket->display_shape = get_shape_for_state(state);
- }
- for (const OutputSocketRef *socket : tree.output_sockets()) {
- bNodeSocket *bsocket = socket->bsocket();
- const SocketFieldState &state = field_state_by_socket_id[socket->id()];
- bsocket->display_shape = get_shape_for_state(state);
- }
-}
-
-static bool update_field_inferencing(bNodeTree &btree)
-{
- using namespace blender::nodes;
- if (btree.type != NTREE_GEOMETRY) {
- return false;
- }
-
- /* Create new inferencing interface for this node group. */
- FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface();
- new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
- InputSocketFieldType::IsSupported);
- new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
- OutputFieldDependency::ForDataSource());
-
- /* Create #NodeTreeRef to accelerate various queries on the node tree (e.g. linked sockets). */
- const NodeTreeRef tree{&btree};
-
- /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */
- Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size());
-
- propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id);
- determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id);
- propagate_field_status_from_left_to_right(tree, field_state_by_socket_id);
- determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id);
- update_socket_shapes(tree, field_state_by_socket_id);
-
- /* Update the previous group interface. */
- const bool group_interface_changed = btree.field_inferencing_interface == nullptr ||
- *btree.field_inferencing_interface !=
- *new_inferencing_interface;
- delete btree.field_inferencing_interface;
- btree.field_inferencing_interface = new_inferencing_interface;
-
- return group_interface_changed;
-}
-
-} // namespace blender::bke::node_field_inferencing
-
-void ntreeUpdateAllUsers(Main *main, ID *id, const int tree_update_flag)
+void ntreeUpdateAllUsers(Main *main, ID *id)
{
if (id == nullptr) {
return;
}
+ bool need_update = false;
+
/* Update all users of ngroup, to add/remove sockets as needed. */
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
- bool need_update = false;
-
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id == id) {
- if (node->typeinfo->group_update_func) {
- node->typeinfo->group_update_func(ntree, node);
- }
-
+ BKE_ntree_update_tag_node_property(ntree, node);
need_update = true;
}
}
-
- if (need_update) {
- ntree->update |= tree_update_flag;
- ntreeUpdateTree(tree_update_flag ? main : nullptr, ntree);
- }
}
FOREACH_NODETREE_END;
-
- if (GS(id->name) == ID_NT) {
- bNodeTree *ngroup = (bNodeTree *)id;
- if (ngroup->type == NTREE_GEOMETRY && (ngroup->update & NTREE_UPDATE_GROUP)) {
- LISTBASE_FOREACH (Object *, object, &main->objects) {
- LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
- if (md->type == eModifierType_Nodes) {
- NodesModifierData *nmd = (NodesModifierData *)md;
- if (nmd->node_group == ngroup) {
- MOD_nodes_update_interface(object, nmd);
- }
- }
- }
- }
- }
- }
-}
-
-void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
-{
- if (!ntree) {
- return;
- }
-
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return;
- }
- ntree->is_updating = true;
-
- if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
- /* set the bNodeSocket->link pointers */
- ntree_update_link_pointers(ntree);
- }
-
- /* update individual nodes */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- /* node tree update tags override individual node update flags */
- if ((node->update & NODE_UPDATE) || (ntree->update & NTREE_UPDATE)) {
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
-
- nodeUpdateInternalLinks(ntree, node);
- }
- }
-
- /* generic tree update callback */
- if (ntree->typeinfo->update) {
- ntree->typeinfo->update(ntree);
- }
- /* XXX this should be moved into the tree type update callback for tree supporting node groups.
- * Currently the node tree interface is still a generic feature of the base NodeTree type.
- */
- if (ntree->update & NTREE_UPDATE_GROUP) {
- ntreeInterfaceTypeUpdate(ntree);
- }
-
- int tree_user_update_flag = 0;
-
- if (ntree->update & NTREE_UPDATE) {
- /* If the field interface of this node tree has changed, all node trees using
- * this group will need to recalculate their interface as well. */
- if (blender::bke::node_field_inferencing::update_field_inferencing(*ntree)) {
- tree_user_update_flag |= NTREE_UPDATE_FIELD_INFERENCING;
- }
- }
-
- if (bmain) {
- ntreeUpdateAllUsers(bmain, &ntree->id, tree_user_update_flag);
- }
-
- if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
- /* node updates can change sockets or links, repeat link pointer update afterward */
- ntree_update_link_pointers(ntree);
-
- /* update the node level from link dependencies */
- ntree_update_node_level(ntree);
-
- /* check link validity */
- ntree_validate_links(ntree);
- }
-
- /* clear update flags */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node->update = 0;
- }
- ntree->update = 0;
-
- ntree->is_updating = false;
-}
-
-void nodeUpdate(bNodeTree *ntree, bNode *node)
-{
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return;
- }
- ntree->is_updating = true;
-
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
-
- nodeUpdateInternalLinks(ntree, node);
-
- /* clear update flag */
- node->update = 0;
-
- ntree->is_updating = false;
-}
-
-bool nodeUpdateID(bNodeTree *ntree, ID *id)
-{
- bool changed = false;
-
- if (ELEM(nullptr, id, ntree)) {
- return changed;
- }
-
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return changed;
- }
- ntree->is_updating = true;
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id == id) {
- changed = true;
- node->update |= NODE_UPDATE_ID;
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
- /* clear update flag */
- node->update = 0;
- }
- }
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- nodeUpdateInternalLinks(ntree, node);
- }
-
- ntree->is_updating = false;
- return changed;
-}
-
-void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node)
-{
- BLI_freelistN(&node->internal_links);
- if (!node->typeinfo->no_muting) {
- node_internal_links_create(ntree, node);
+ if (need_update) {
+ BKE_ntree_update_main(main, nullptr);
}
}
@@ -5232,8 +4207,7 @@ static bool node_poll_instance_default(bNode *node, bNodeTree *ntree, const char
return node->typeinfo->poll(node->typeinfo, ntree, disabled_hint);
}
-/* NOLINTNEXTLINE: readability-function-size */
-void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
/* Use static type info header to map static int type to identifier string and RNA struct type.
* Associate the RNA struct type with the bNodeType.
@@ -5260,7 +4234,6 @@ void node_type_base(bNodeType *ntype, int type, const char *name, short nclass,
ntype->type = type;
BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name));
ntype->nclass = nclass;
- ntype->flag = flag;
node_type_base_defaults(ntype);
@@ -5268,14 +4241,12 @@ void node_type_base(bNodeType *ntype, int type, const char *name, short nclass,
ntype->poll_instance = node_poll_instance_default;
}
-void node_type_base_custom(
- bNodeType *ntype, const char *idname, const char *name, short nclass, short flag)
+void node_type_base_custom(bNodeType *ntype, const char *idname, const char *name, short nclass)
{
BLI_strncpy(ntype->idname, idname, sizeof(ntype->idname));
ntype->type = NODE_CUSTOM;
BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name));
ntype->nclass = nclass;
- ntype->flag = flag;
node_type_base_defaults(ntype);
}
@@ -5451,7 +4422,7 @@ static void register_undefined_types()
strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined"));
strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type"));
- node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0, 0);
+ node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0);
NodeTypeUndefined.poll = node_undefined_poll;
BLI_strncpy(NodeSocketTypeUndefined.idname,
@@ -5476,6 +4447,7 @@ static void registerCompositNodes()
register_node_type_cmp_value();
register_node_type_cmp_rgb();
register_node_type_cmp_curve_time();
+ register_node_type_cmp_scene_time();
register_node_type_cmp_movieclip();
register_node_type_cmp_composite();
@@ -5516,6 +4488,7 @@ static void registerCompositNodes()
register_node_type_cmp_denoise();
register_node_type_cmp_antialiasing();
+ register_node_type_cmp_convert_color_space();
register_node_type_cmp_valtorgb();
register_node_type_cmp_rgbtobw();
register_node_type_cmp_setalpha();
@@ -5695,6 +4668,7 @@ static void registerTextureNodes()
register_node_type_sh_tangent();
register_node_type_sh_normal_map();
register_node_type_sh_hair_info();
+ register_node_type_sh_point_info();
register_node_type_sh_volume_info();
register_node_type_tex_checker();
@@ -5745,6 +4719,7 @@ static void registerGeometryNodes()
register_node_type_geo_legacy_subdivision_surface();
register_node_type_geo_legacy_volume_to_mesh();
+ register_node_type_geo_accumulate_field();
register_node_type_geo_align_rotation_to_vector();
register_node_type_geo_attribute_capture();
register_node_type_geo_attribute_clamp();
@@ -5772,6 +4747,7 @@ 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_primitive_arc();
register_node_type_geo_curve_primitive_bezier_segment();
register_node_type_geo_curve_primitive_circle();
register_node_type_geo_curve_primitive_line();
@@ -5793,6 +4769,9 @@ static void registerGeometryNodes()
register_node_type_geo_distribute_points_on_faces();
register_node_type_geo_dual_mesh();
register_node_type_geo_edge_split();
+ register_node_type_geo_extrude_mesh();
+ register_node_type_geo_field_at_index();
+ register_node_type_geo_flip_faces();
register_node_type_geo_geometry_to_instance();
register_node_type_geo_image_texture();
register_node_type_geo_input_curve_handles();
@@ -5801,6 +4780,7 @@ static void registerGeometryNodes()
register_node_type_geo_input_index();
register_node_type_geo_input_material_index();
register_node_type_geo_input_material();
+ register_node_type_geo_input_mesh_edge_angle();
register_node_type_geo_input_mesh_edge_neighbors();
register_node_type_geo_input_mesh_edge_vertices();
register_node_type_geo_input_mesh_face_area();
@@ -5822,6 +4802,7 @@ static void registerGeometryNodes()
register_node_type_geo_join_geometry();
register_node_type_geo_material_replace();
register_node_type_geo_material_selection();
+ register_node_type_geo_merge_by_distance();
register_node_type_geo_mesh_primitive_circle();
register_node_type_geo_mesh_primitive_cone();
register_node_type_geo_mesh_primitive_cube();
@@ -5847,6 +4828,7 @@ static void registerGeometryNodes()
register_node_type_geo_realize_instances();
register_node_type_geo_rotate_instances();
register_node_type_geo_sample_texture();
+ register_node_type_geo_scale_elements();
register_node_type_geo_scale_instances();
register_node_type_geo_separate_components();
register_node_type_geo_separate_geometry();
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
new file mode 100644
index 00000000000..0555707b64c
--- /dev/null
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -0,0 +1,1670 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_map.hh"
+#include "BLI_multi_value_map.hh"
+#include "BLI_noise.hh"
+#include "BLI_set.hh"
+#include "BLI_stack.hh"
+#include "BLI_vector_set.hh"
+
+#include "DNA_anim_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+
+#include "BKE_anim_data.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
+
+#include "MOD_nodes.h"
+
+#include "NOD_node_declaration.hh"
+#include "NOD_node_tree_ref.hh"
+#include "NOD_texture.h"
+
+#include "DEG_depsgraph_query.h"
+
+using namespace blender::nodes;
+
+/**
+ * These flags are used by the `changed_flag` field in #bNodeTree, #bNode and #bNodeSocket.
+ * This enum is not part of the public api. It should be used through the `BKE_ntree_update_tag_*`
+ * api.
+ */
+enum eNodeTreeChangedFlag {
+ NTREE_CHANGED_NOTHING = 0,
+ NTREE_CHANGED_ANY = (1 << 1),
+ NTREE_CHANGED_NODE_PROPERTY = (1 << 2),
+ NTREE_CHANGED_NODE_OUTPUT = (1 << 3),
+ NTREE_CHANGED_INTERFACE = (1 << 4),
+ NTREE_CHANGED_LINK = (1 << 5),
+ NTREE_CHANGED_REMOVED_NODE = (1 << 6),
+ NTREE_CHANGED_REMOVED_SOCKET = (1 << 7),
+ NTREE_CHANGED_SOCKET_PROPERTY = (1 << 8),
+ NTREE_CHANGED_INTERNAL_LINK = (1 << 9),
+ NTREE_CHANGED_ALL = -1,
+};
+
+static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag)
+{
+ ntree->changed_flag |= flag;
+}
+
+static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag)
+{
+ add_tree_tag(ntree, flag);
+ node->changed_flag |= flag;
+}
+
+static void add_socket_tag(bNodeTree *ntree, bNodeSocket *socket, const eNodeTreeChangedFlag flag)
+{
+ add_tree_tag(ntree, flag);
+ socket->changed_flag |= flag;
+}
+
+namespace blender::bke {
+
+namespace node_field_inferencing {
+
+static bool is_field_socket_type(eNodeSocketDatatype type)
+{
+ return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
+}
+
+static bool is_field_socket_type(const SocketRef &socket)
+{
+ return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type);
+}
+
+static InputSocketFieldType get_interface_input_field_type(const NodeRef &node,
+ const InputSocketRef &socket)
+{
+ if (!is_field_socket_type(socket)) {
+ return InputSocketFieldType::None;
+ }
+ if (node.is_reroute_node()) {
+ return InputSocketFieldType::IsSupported;
+ }
+ if (node.is_group_output_node()) {
+ /* Outputs always support fields when the data type is correct. */
+ return InputSocketFieldType::IsSupported;
+ }
+ if (node.is_undefined()) {
+ return InputSocketFieldType::None;
+ }
+
+ const NodeDeclaration *node_decl = node.declaration();
+
+ /* Node declarations should be implemented for nodes involved here. */
+ BLI_assert(node_decl != nullptr);
+
+ /* Get the field type from the declaration. */
+ const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()];
+ const InputSocketFieldType field_type = socket_decl.input_field_type();
+ if (field_type == InputSocketFieldType::Implicit) {
+ return field_type;
+ }
+ if (node_decl->is_function_node()) {
+ /* In a function node, every socket supports fields. */
+ return InputSocketFieldType::IsSupported;
+ }
+ return field_type;
+}
+
+static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node,
+ const OutputSocketRef &socket)
+{
+ if (!is_field_socket_type(socket)) {
+ /* Non-field sockets always output data. */
+ return OutputFieldDependency::ForDataSource();
+ }
+ if (node.is_reroute_node()) {
+ /* The reroute just forwards what is passed in. */
+ return OutputFieldDependency::ForDependentField();
+ }
+ if (node.is_group_input_node()) {
+ /* Input nodes get special treatment in #determine_group_input_states. */
+ return OutputFieldDependency::ForDependentField();
+ }
+ if (node.is_undefined()) {
+ return OutputFieldDependency::ForDataSource();
+ }
+
+ const NodeDeclaration *node_decl = node.declaration();
+
+ /* Node declarations should be implemented for nodes involved here. */
+ BLI_assert(node_decl != nullptr);
+
+ if (node_decl->is_function_node()) {
+ /* In a generic function node, all outputs depend on all inputs. */
+ return OutputFieldDependency::ForDependentField();
+ }
+
+ /* Use the socket declaration. */
+ const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()];
+ return socket_decl.output_field_dependency();
+}
+
+static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node)
+{
+ FieldInferencingInterface inferencing_interface;
+ inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size());
+ inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(),
+ node.outputs().size());
+ return inferencing_interface;
+}
+
+/**
+ * Retrieves information about how the node interacts with fields.
+ * In the future, this information can be stored in the node declaration. This would allow this
+ * function to return a reference, making it more efficient.
+ */
+static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node)
+{
+ /* Node groups already reference all required information, so just return that. */
+ if (node.is_group_node()) {
+ bNodeTree *group = (bNodeTree *)node.bnode()->id;
+ if (group == nullptr) {
+ return FieldInferencingInterface();
+ }
+ if (!ntreeIsRegistered(group)) {
+ /* This can happen when there is a linked node group that was not found (see T92799). */
+ return get_dummy_field_inferencing_interface(node);
+ }
+ if (group->field_inferencing_interface == nullptr) {
+ /* This shouldn't happen because referenced node groups should always be updated first. */
+ BLI_assert_unreachable();
+ }
+ return *group->field_inferencing_interface;
+ }
+
+ FieldInferencingInterface inferencing_interface;
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket));
+ }
+
+ for (const OutputSocketRef *output_socket : node.outputs()) {
+ inferencing_interface.outputs.append(
+ get_interface_output_field_dependency(node, *output_socket));
+ }
+ return inferencing_interface;
+}
+
+/**
+ * This struct contains information for every socket. The values are propagated through the
+ * network.
+ */
+struct SocketFieldState {
+ /* This socket starts a new field. */
+ bool is_field_source = false;
+ /* This socket can never become a field, because the node itself does not support it. */
+ bool is_always_single = false;
+ /* This socket is currently a single value. It could become a field though. */
+ bool is_single = true;
+ /* This socket is required to be a single value. This can be because the node itself only
+ * supports this socket to be a single value, or because a node afterwards requires this to be a
+ * single value. */
+ bool requires_single = false;
+};
+
+static Vector<const InputSocketRef *> gather_input_socket_dependencies(
+ const OutputFieldDependency &field_dependency, const NodeRef &node)
+{
+ const OutputSocketFieldType type = field_dependency.field_type();
+ Vector<const InputSocketRef *> input_sockets;
+ switch (type) {
+ case OutputSocketFieldType::FieldSource:
+ case OutputSocketFieldType::None: {
+ break;
+ }
+ case OutputSocketFieldType::DependentField: {
+ /* This output depends on all inputs. */
+ input_sockets.extend(node.inputs());
+ break;
+ }
+ case OutputSocketFieldType::PartiallyDependent: {
+ /* This output depends only on a few inputs. */
+ for (const int i : field_dependency.linked_input_indices()) {
+ input_sockets.append(&node.input(i));
+ }
+ break;
+ }
+ }
+ return input_sockets;
+}
+
+/**
+ * Check what the group output socket depends on. Potentially traverses the node tree
+ * to figure out if it is always a field or if it depends on any group inputs.
+ */
+static OutputFieldDependency find_group_output_dependencies(
+ const InputSocketRef &group_output_socket,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ if (!is_field_socket_type(group_output_socket)) {
+ return OutputFieldDependency::ForDataSource();
+ }
+
+ /* Use a Set here instead of an array indexed by socket id, because we my only need to look at
+ * very few sockets. */
+ Set<const InputSocketRef *> handled_sockets;
+ Stack<const InputSocketRef *> sockets_to_check;
+
+ handled_sockets.add(&group_output_socket);
+ sockets_to_check.push(&group_output_socket);
+
+ /* Keeps track of group input indices that are (indirectly) connected to the output. */
+ Vector<int> linked_input_indices;
+
+ while (!sockets_to_check.is_empty()) {
+ const InputSocketRef *input_socket = sockets_to_check.pop();
+
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
+ const NodeRef &origin_node = origin_socket->node();
+ const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
+
+ if (origin_state.is_field_source) {
+ if (origin_node.is_group_input_node()) {
+ /* Found a group input that the group output depends on. */
+ linked_input_indices.append_non_duplicates(origin_socket->index());
+ }
+ else {
+ /* Found a field source that is not the group input. So the output is always a field. */
+ return OutputFieldDependency::ForFieldSource();
+ }
+ }
+ else if (!origin_state.is_single) {
+ const FieldInferencingInterface inferencing_interface =
+ get_node_field_inferencing_interface(origin_node);
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[origin_socket->index()];
+
+ /* Propagate search further to the left. */
+ for (const InputSocketRef *origin_input_socket :
+ gather_input_socket_dependencies(field_dependency, origin_node)) {
+ if (!origin_input_socket->is_available()) {
+ continue;
+ }
+ if (!field_state_by_socket_id[origin_input_socket->id()].is_single) {
+ if (handled_sockets.add(origin_input_socket)) {
+ sockets_to_check.push(origin_input_socket);
+ }
+ }
+ }
+ }
+ }
+ }
+ return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices));
+}
+
+static void propagate_data_requirements_from_right_to_left(
+ const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
+ NodeTreeRef::ToposortDirection::RightToLeft);
+
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
+ const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
+ *node);
+
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[output_socket->index()];
+
+ if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) {
+ continue;
+ }
+ if (field_dependency.field_type() == OutputSocketFieldType::None) {
+ state.requires_single = true;
+ state.is_always_single = true;
+ continue;
+ }
+
+ /* The output is required to be a single value when it is connected to any input that does
+ * not support fields. */
+ for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
+ if (target_socket->is_available()) {
+ state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
+ }
+ }
+
+ if (state.requires_single) {
+ bool any_input_is_field_implicitly = false;
+ const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies(
+ field_dependency, *node);
+ for (const InputSocketRef *input_socket : connected_inputs) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (inferencing_interface.inputs[input_socket->index()] ==
+ InputSocketFieldType::Implicit) {
+ if (!input_socket->is_logically_linked()) {
+ any_input_is_field_implicitly = true;
+ break;
+ }
+ }
+ }
+ if (any_input_is_field_implicitly) {
+ /* This output isn't a single value actually. */
+ state.requires_single = false;
+ }
+ else {
+ /* If the output is required to be a single value, the connected inputs in the same node
+ * must not be fields as well. */
+ for (const InputSocketRef *input_socket : connected_inputs) {
+ field_state_by_socket_id[input_socket->id()].requires_single = true;
+ }
+ }
+ }
+ }
+
+ /* Some inputs do not require fields independent of what the outputs are connected to. */
+ for (const InputSocketRef *input_socket : node->inputs()) {
+ SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
+ if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) {
+ state.requires_single = true;
+ state.is_always_single = true;
+ }
+ }
+ }
+}
+
+static void determine_group_input_states(
+ const NodeTreeRef &tree,
+ FieldInferencingInterface &new_inferencing_interface,
+ const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ {
+ /* Non-field inputs never support fields. */
+ int index;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) {
+ if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) {
+ new_inferencing_interface.inputs[index] = InputSocketFieldType::None;
+ }
+ }
+ }
+ /* Check if group inputs are required to be single values, because they are (indirectly)
+ * connected to some socket that does not support fields. */
+ for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
+ for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ if (state.requires_single) {
+ new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None;
+ }
+ }
+ }
+ /* If an input does not support fields, this should be reflected in all Group Input nodes. */
+ for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
+ for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=
+ InputSocketFieldType::None;
+ if (supports_field) {
+ state.is_single = false;
+ state.is_field_source = true;
+ }
+ else {
+ state.requires_single = true;
+ }
+ }
+ SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()];
+ dummy_socket_state.requires_single = true;
+ }
+}
+
+static void propagate_field_status_from_left_to_right(
+ const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
+ NodeTreeRef::ToposortDirection::LeftToRight);
+
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
+ if (node->is_group_input_node()) {
+ continue;
+ }
+
+ const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
+ *node);
+
+ /* Update field state of input sockets, also taking into account linked origin sockets. */
+ for (const InputSocketRef *input_socket : node->inputs()) {
+ SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
+ if (state.is_always_single) {
+ state.is_single = true;
+ continue;
+ }
+ state.is_single = true;
+ if (input_socket->directly_linked_sockets().is_empty()) {
+ if (inferencing_interface.inputs[input_socket->index()] ==
+ InputSocketFieldType::Implicit) {
+ state.is_single = false;
+ }
+ }
+ else {
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
+ if (!field_state_by_socket_id[origin_socket->id()].is_single) {
+ state.is_single = false;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Update field state of output sockets, also taking into account input sockets. */
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[output_socket->index()];
+
+ switch (field_dependency.field_type()) {
+ case OutputSocketFieldType::None: {
+ state.is_single = true;
+ break;
+ }
+ case OutputSocketFieldType::FieldSource: {
+ state.is_single = false;
+ state.is_field_source = true;
+ break;
+ }
+ case OutputSocketFieldType::PartiallyDependent:
+ case OutputSocketFieldType::DependentField: {
+ for (const InputSocketRef *input_socket :
+ gather_input_socket_dependencies(field_dependency, *node)) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (!field_state_by_socket_id[input_socket->id()].is_single) {
+ state.is_single = false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void determine_group_output_states(const NodeTreeRef &tree,
+ FieldInferencingInterface &new_inferencing_interface,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
+ /* Ignore inactive group output nodes. */
+ if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) {
+ continue;
+ }
+ /* Determine dependencies of all group outputs. */
+ for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) {
+ OutputFieldDependency field_dependency = find_group_output_dependencies(
+ *group_output_socket, field_state_by_socket_id);
+ new_inferencing_interface.outputs[group_output_socket->index()] = std::move(
+ field_dependency);
+ }
+ break;
+ }
+}
+
+static void update_socket_shapes(const NodeTreeRef &tree,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
+ const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT;
+ const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
+
+ auto get_shape_for_state = [&](const SocketFieldState &state) {
+ if (state.is_always_single) {
+ return requires_data_shape;
+ }
+ if (!state.is_single) {
+ return is_field_shape;
+ }
+ if (state.requires_single) {
+ return requires_data_shape;
+ }
+ return data_but_can_be_field_shape;
+ };
+
+ for (const InputSocketRef *socket : tree.input_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ const SocketFieldState &state = field_state_by_socket_id[socket->id()];
+ bsocket->display_shape = get_shape_for_state(state);
+ }
+ for (const OutputSocketRef *socket : tree.output_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ const SocketFieldState &state = field_state_by_socket_id[socket->id()];
+ bsocket->display_shape = get_shape_for_state(state);
+ }
+}
+
+static bool update_field_inferencing(const NodeTreeRef &tree)
+{
+ bNodeTree &btree = *tree.btree();
+
+ /* Create new inferencing interface for this node group. */
+ FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface();
+ new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
+ InputSocketFieldType::IsSupported);
+ new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
+ OutputFieldDependency::ForDataSource());
+
+ /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */
+ Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size());
+
+ propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id);
+ determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id);
+ propagate_field_status_from_left_to_right(tree, field_state_by_socket_id);
+ determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id);
+ update_socket_shapes(tree, field_state_by_socket_id);
+
+ /* Update the previous group interface. */
+ const bool group_interface_changed = btree.field_inferencing_interface == nullptr ||
+ *btree.field_inferencing_interface !=
+ *new_inferencing_interface;
+ delete btree.field_inferencing_interface;
+ btree.field_inferencing_interface = new_inferencing_interface;
+
+ return group_interface_changed;
+}
+
+} // namespace node_field_inferencing
+
+/**
+ * Common datatype priorities, works for compositor, shader and texture nodes alike
+ * defines priority of datatype connection based on output type (to):
+ * `< 0`: never connect these types.
+ * `>= 0`: priority of connection (higher values chosen first).
+ */
+static int get_internal_link_type_priority(const bNodeSocketType *from, const bNodeSocketType *to)
+{
+ switch (to->type) {
+ case SOCK_RGBA:
+ switch (from->type) {
+ case SOCK_RGBA:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_INT:
+ return 2;
+ case SOCK_BOOLEAN:
+ return 1;
+ }
+ return -1;
+ case SOCK_VECTOR:
+ switch (from->type) {
+ case SOCK_VECTOR:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_INT:
+ return 2;
+ case SOCK_BOOLEAN:
+ return 1;
+ }
+ return -1;
+ case SOCK_FLOAT:
+ switch (from->type) {
+ case SOCK_FLOAT:
+ return 5;
+ case SOCK_INT:
+ return 4;
+ case SOCK_BOOLEAN:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ case SOCK_INT:
+ switch (from->type) {
+ case SOCK_INT:
+ return 5;
+ case SOCK_FLOAT:
+ return 4;
+ case SOCK_BOOLEAN:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ case SOCK_BOOLEAN:
+ switch (from->type) {
+ case SOCK_BOOLEAN:
+ return 5;
+ case SOCK_INT:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ }
+
+ /* The rest of the socket types only allow an internal link if both the input and output socket
+ * have the same type. If the sockets are custom, we check the idname instead. */
+ if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) {
+ return 1;
+ }
+
+ return -1;
+}
+
+using TreeNodePair = std::pair<bNodeTree *, bNode *>;
+using ObjectModifierPair = std::pair<Object *, ModifierData *>;
+using NodeSocketPair = std::pair<bNode *, bNodeSocket *>;
+
+/**
+ * Cache common data about node trees from the #Main database that is expensive to retrieve on
+ * demand every time.
+ */
+struct NodeTreeRelations {
+ private:
+ Main *bmain_;
+ std::optional<Vector<bNodeTree *>> all_trees_;
+ std::optional<Map<bNodeTree *, ID *>> owner_ids_;
+ std::optional<MultiValueMap<bNodeTree *, TreeNodePair>> group_node_users_;
+ std::optional<MultiValueMap<bNodeTree *, ObjectModifierPair>> modifiers_users_;
+
+ public:
+ NodeTreeRelations(Main *bmain) : bmain_(bmain)
+ {
+ }
+
+ void ensure_all_trees()
+ {
+ if (all_trees_.has_value()) {
+ return;
+ }
+ all_trees_.emplace();
+ owner_ids_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
+ all_trees_->append(ntree);
+ if (&ntree->id != id) {
+ owner_ids_->add_new(ntree, id);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ void ensure_owner_ids()
+ {
+ this->ensure_all_trees();
+ }
+
+ void ensure_group_node_users()
+ {
+ if (group_node_users_.has_value()) {
+ return;
+ }
+ group_node_users_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ this->ensure_all_trees();
+
+ for (bNodeTree *ntree : *all_trees_) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == nullptr) {
+ continue;
+ }
+ ID *id = node->id;
+ if (GS(id->name) == ID_NT) {
+ bNodeTree *group = (bNodeTree *)id;
+ group_node_users_->add(group, {ntree, node});
+ }
+ }
+ }
+ }
+
+ void ensure_modifier_users()
+ {
+ if (modifiers_users_.has_value()) {
+ return;
+ }
+ modifiers_users_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ LISTBASE_FOREACH (Object *, object, &bmain_->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ if (nmd->node_group != nullptr) {
+ modifiers_users_->add(nmd->node_group, {object, md});
+ }
+ }
+ }
+ }
+ }
+
+ Span<ObjectModifierPair> get_modifier_users(bNodeTree *ntree)
+ {
+ BLI_assert(modifiers_users_.has_value());
+ return modifiers_users_->lookup(ntree);
+ }
+
+ Span<TreeNodePair> get_group_node_users(bNodeTree *ntree)
+ {
+ BLI_assert(group_node_users_.has_value());
+ return group_node_users_->lookup(ntree);
+ }
+
+ ID *get_owner_id(bNodeTree *ntree)
+ {
+ BLI_assert(owner_ids_.has_value());
+ return owner_ids_->lookup_default(ntree, &ntree->id);
+ }
+};
+
+struct TreeUpdateResult {
+ bool interface_changed = false;
+ bool output_changed = false;
+};
+
+class NodeTreeMainUpdater {
+ private:
+ Main *bmain_;
+ NodeTreeUpdateExtraParams *params_;
+ Map<bNodeTree *, TreeUpdateResult> update_result_by_tree_;
+ NodeTreeRelations relations_;
+
+ public:
+ NodeTreeMainUpdater(Main *bmain, NodeTreeUpdateExtraParams *params)
+ : bmain_(bmain), params_(params), relations_(bmain)
+ {
+ }
+
+ void update()
+ {
+ Vector<bNodeTree *> changed_ntrees;
+ FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
+ if (ntree->changed_flag != NTREE_CHANGED_NOTHING) {
+ changed_ntrees.append(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ this->update_rooted(changed_ntrees);
+ }
+
+ void update_rooted(Span<bNodeTree *> root_ntrees)
+ {
+ if (root_ntrees.is_empty()) {
+ return;
+ }
+
+ bool is_single_tree_update = false;
+
+ if (root_ntrees.size() == 1) {
+ bNodeTree *ntree = root_ntrees[0];
+ if (ntree->changed_flag == NTREE_CHANGED_NOTHING) {
+ return;
+ }
+ const TreeUpdateResult result = this->update_tree(*ntree);
+ update_result_by_tree_.add_new(ntree, result);
+ if (!result.interface_changed && !result.output_changed) {
+ is_single_tree_update = true;
+ }
+ }
+
+ if (!is_single_tree_update) {
+ Vector<bNodeTree *> ntrees_in_order = this->get_tree_update_order(root_ntrees);
+ for (bNodeTree *ntree : ntrees_in_order) {
+ if (ntree->changed_flag == NTREE_CHANGED_NOTHING) {
+ continue;
+ }
+ if (!update_result_by_tree_.contains(ntree)) {
+ const TreeUpdateResult result = this->update_tree(*ntree);
+ update_result_by_tree_.add_new(ntree, result);
+ }
+ const TreeUpdateResult result = update_result_by_tree_.lookup(ntree);
+ Span<TreeNodePair> dependent_trees = relations_.get_group_node_users(ntree);
+ if (result.output_changed) {
+ for (const TreeNodePair &pair : dependent_trees) {
+ add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_OUTPUT);
+ }
+ }
+ if (result.interface_changed) {
+ for (const TreeNodePair &pair : dependent_trees) {
+ add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_PROPERTY);
+ }
+ }
+ }
+ }
+
+ for (const auto item : update_result_by_tree_.items()) {
+ bNodeTree *ntree = item.key;
+ const TreeUpdateResult &result = item.value;
+
+ this->reset_changed_flags(*ntree);
+
+ if (result.interface_changed) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ relations_.ensure_modifier_users();
+ for (const ObjectModifierPair &pair : relations_.get_modifier_users(ntree)) {
+ Object *object = pair.first;
+ ModifierData *md = pair.second;
+
+ if (md->type == eModifierType_Nodes) {
+ MOD_nodes_update_interface(object, (NodesModifierData *)md);
+ }
+ }
+ }
+ }
+
+ if (params_) {
+ relations_.ensure_owner_ids();
+ ID *id = relations_.get_owner_id(ntree);
+ if (params_->tree_changed_fn) {
+ params_->tree_changed_fn(id, ntree, params_->user_data);
+ }
+ if (params_->tree_output_changed_fn && result.output_changed) {
+ params_->tree_output_changed_fn(id, ntree, params_->user_data);
+ }
+ }
+ }
+ }
+
+ private:
+ enum class ToposortMark {
+ None,
+ Temporary,
+ Permanent,
+ };
+
+ using ToposortMarkMap = Map<bNodeTree *, ToposortMark>;
+
+ /**
+ * Finds all trees that depend on the given trees (through node groups). Then those trees are
+ * ordered such that all trees used by one tree come before it.
+ */
+ Vector<bNodeTree *> get_tree_update_order(Span<bNodeTree *> root_ntrees)
+ {
+ relations_.ensure_group_node_users();
+
+ Set<bNodeTree *> trees_to_update = get_trees_to_update(root_ntrees);
+
+ Vector<bNodeTree *> sorted_ntrees;
+
+ ToposortMarkMap marks;
+ for (bNodeTree *ntree : trees_to_update) {
+ marks.add_new(ntree, ToposortMark::None);
+ }
+ for (bNodeTree *ntree : trees_to_update) {
+ if (marks.lookup(ntree) == ToposortMark::None) {
+ const bool cycle_detected = !this->get_tree_update_order__visit_recursive(
+ ntree, marks, sorted_ntrees);
+ /* This should be prevented by higher level operators. */
+ BLI_assert(!cycle_detected);
+ UNUSED_VARS_NDEBUG(cycle_detected);
+ }
+ }
+
+ std::reverse(sorted_ntrees.begin(), sorted_ntrees.end());
+
+ return sorted_ntrees;
+ }
+
+ bool get_tree_update_order__visit_recursive(bNodeTree *ntree,
+ ToposortMarkMap &marks,
+ Vector<bNodeTree *> &sorted_ntrees)
+ {
+ ToposortMark &mark = marks.lookup(ntree);
+ if (mark == ToposortMark::Permanent) {
+ return true;
+ }
+ if (mark == ToposortMark::Temporary) {
+ /* There is a dependency cycle. */
+ return false;
+ }
+
+ mark = ToposortMark::Temporary;
+
+ for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) {
+ this->get_tree_update_order__visit_recursive(pair.first, marks, sorted_ntrees);
+ }
+ sorted_ntrees.append(ntree);
+
+ mark = ToposortMark::Permanent;
+ return true;
+ }
+
+ Set<bNodeTree *> get_trees_to_update(Span<bNodeTree *> root_ntrees)
+ {
+ relations_.ensure_group_node_users();
+
+ Set<bNodeTree *> reachable_trees;
+ VectorSet<bNodeTree *> trees_to_check = root_ntrees;
+
+ while (!trees_to_check.is_empty()) {
+ bNodeTree *ntree = trees_to_check.pop();
+ if (reachable_trees.add(ntree)) {
+ for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) {
+ trees_to_check.add(pair.first);
+ }
+ }
+ }
+
+ return reachable_trees;
+ }
+
+ TreeUpdateResult update_tree(bNodeTree &ntree)
+ {
+ TreeUpdateResult result;
+
+ /* Use a #NodeTreeRef to speedup certain queries. It is rebuilt whenever the node tree topology
+ * changes, which typically happens zero or one times during the entire update of the node
+ * tree. */
+ std::unique_ptr<NodeTreeRef> tree_ref;
+ this->ensure_tree_ref(ntree, tree_ref);
+
+ this->update_socket_link_and_use(*tree_ref);
+ this->update_individual_nodes(ntree, tree_ref);
+ this->update_internal_links(ntree, tree_ref);
+ this->update_generic_callback(ntree, tree_ref);
+ this->remove_unused_previews_when_necessary(ntree);
+
+ this->ensure_tree_ref(ntree, tree_ref);
+ if (ntree.type == NTREE_GEOMETRY) {
+ if (node_field_inferencing::update_field_inferencing(*tree_ref)) {
+ result.interface_changed = true;
+ }
+ }
+
+ result.output_changed = this->check_if_output_changed(*tree_ref);
+
+ this->update_socket_link_and_use(*tree_ref);
+ this->update_node_levels(ntree);
+ this->update_link_validation(ntree);
+
+ if (ntree.type == NTREE_TEXTURE) {
+ ntreeTexCheckCyclics(&ntree);
+ }
+
+ if (ntree.changed_flag & NTREE_CHANGED_INTERFACE || ntree.changed_flag & NTREE_CHANGED_ANY) {
+ result.interface_changed = true;
+ }
+
+ if (result.interface_changed) {
+ ntreeInterfaceTypeUpdate(&ntree);
+ }
+
+ return result;
+ }
+
+ void ensure_tree_ref(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ if (!tree_ref) {
+ tree_ref = std::make_unique<NodeTreeRef>(&ntree);
+ }
+ }
+
+ void update_socket_link_and_use(const NodeTreeRef &tree)
+ {
+ for (const InputSocketRef *socket : tree.input_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ if (socket->directly_linked_links().is_empty()) {
+ bsocket->link = nullptr;
+ }
+ else {
+ bsocket->link = socket->directly_linked_links()[0]->blink();
+ }
+ }
+
+ this->update_socket_used_tags(tree);
+ }
+
+ void update_socket_used_tags(const NodeTreeRef &tree)
+ {
+ for (const SocketRef *socket : tree.sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ bsocket->flag &= ~SOCK_IN_USE;
+ for (const LinkRef *link : socket->directly_linked_links()) {
+ if (!link->is_muted()) {
+ bsocket->flag |= SOCK_IN_USE;
+ break;
+ }
+ }
+ }
+ }
+
+ void update_individual_nodes(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ /* Iterate over nodes instead of #NodeTreeRef, because the #tree_ref might be outdated after
+ * some update functions. */
+ LISTBASE_FOREACH (bNode *, bnode, &ntree.nodes) {
+ this->ensure_tree_ref(ntree, tree_ref);
+ const NodeRef &node = *tree_ref->find_node(*bnode);
+ if (this->should_update_individual_node(node)) {
+ const uint32_t old_changed_flag = ntree.changed_flag;
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+
+ /* This may set #ntree.changed_flag which is detected below. */
+ this->update_individual_node(node);
+
+ if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ /* The tree ref is outdated and needs to be rebuilt. Generally, only very few update
+ * functions change the node. Typically zero or one nodes change after an update. */
+ tree_ref.reset();
+ }
+ ntree.changed_flag |= old_changed_flag;
+ }
+ }
+ }
+
+ bool should_update_individual_node(const NodeRef &node)
+ {
+ bNodeTree &ntree = *node.btree();
+ bNode &bnode = *node.bnode();
+ if (ntree.changed_flag & NTREE_CHANGED_ANY) {
+ return true;
+ }
+ if (bnode.changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
+ return true;
+ }
+ if (ntree.changed_flag & NTREE_CHANGED_LINK) {
+ /* Node groups currently always rebuilt their sockets when they are updated.
+ * So avoid calling the update method when no new link was added to it. */
+ if (node.is_group_input_node()) {
+ if (node.outputs().last()->is_directly_linked()) {
+ return true;
+ }
+ }
+ else if (node.is_group_output_node()) {
+ if (node.inputs().last()->is_directly_linked()) {
+ return true;
+ }
+ }
+ else {
+ /* Currently we have no way to tell if a node needs to be updated when a link changed. */
+ return true;
+ }
+ }
+ if (ntree.changed_flag & NTREE_CHANGED_INTERFACE) {
+ if (node.is_group_input_node() || node.is_group_output_node()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void update_individual_node(const NodeRef &node)
+ {
+ bNodeTree &ntree = *node.btree();
+ bNode &bnode = *node.bnode();
+ bNodeType &ntype = *bnode.typeinfo;
+ if (ntype.group_update_func) {
+ ntype.group_update_func(&ntree, &bnode);
+ }
+ if (ntype.updatefunc) {
+ ntype.updatefunc(&ntree, &bnode);
+ }
+ }
+
+ void update_internal_links(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ bool any_internal_links_updated = false;
+ this->ensure_tree_ref(ntree, tree_ref);
+ for (const NodeRef *node : tree_ref->nodes()) {
+ if (!this->should_update_individual_node(*node)) {
+ continue;
+ }
+ /* Find all expected internal links. */
+ Vector<std::pair<bNodeSocket *, bNodeSocket *>> expected_internal_links;
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ if (!output_socket->is_available()) {
+ continue;
+ }
+ if (!output_socket->is_directly_linked()) {
+ continue;
+ }
+ if (output_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) {
+ continue;
+ }
+ const InputSocketRef *input_socket = this->find_internally_linked_input(output_socket);
+ if (input_socket != nullptr) {
+ expected_internal_links.append({input_socket->bsocket(), output_socket->bsocket()});
+ }
+ }
+ /* rebuilt internal links if they have changed. */
+ if (node->internal_links().size() != expected_internal_links.size()) {
+ this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links);
+ any_internal_links_updated = true;
+ }
+ else {
+ for (auto &item : expected_internal_links) {
+ const bNodeSocket *from_socket = item.first;
+ const bNodeSocket *to_socket = item.second;
+ bool found = false;
+ for (const InternalLinkRef *internal_link : node->internal_links()) {
+ if (from_socket == internal_link->from().bsocket() &&
+ to_socket == internal_link->to().bsocket()) {
+ found = true;
+ }
+ }
+ if (!found) {
+ this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links);
+ any_internal_links_updated = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (any_internal_links_updated) {
+ tree_ref.reset();
+ }
+ }
+
+ const InputSocketRef *find_internally_linked_input(const OutputSocketRef *output_socket)
+ {
+ const InputSocketRef *selected_socket = nullptr;
+ int selected_priority = -1;
+ bool selected_is_linked = false;
+ for (const InputSocketRef *input_socket : output_socket->node().inputs()) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (input_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) {
+ continue;
+ }
+ const int priority = get_internal_link_type_priority(input_socket->bsocket()->typeinfo,
+ output_socket->bsocket()->typeinfo);
+ if (priority < 0) {
+ continue;
+ }
+ const bool is_linked = input_socket->is_directly_linked();
+ const bool is_preferred = priority > selected_priority || (is_linked && !selected_is_linked);
+ if (!is_preferred) {
+ continue;
+ }
+ selected_socket = input_socket;
+ selected_priority = priority;
+ selected_is_linked = is_linked;
+ }
+ return selected_socket;
+ }
+
+ void update_internal_links_in_node(bNodeTree &ntree,
+ bNode &node,
+ Span<std::pair<bNodeSocket *, bNodeSocket *>> links)
+ {
+ BLI_freelistN(&node.internal_links);
+ for (const auto &item : links) {
+ bNodeSocket *from_socket = item.first;
+ bNodeSocket *to_socket = item.second;
+ bNodeLink *link = MEM_cnew<bNodeLink>(__func__);
+ link->fromnode = &node;
+ link->fromsock = from_socket;
+ link->tonode = &node;
+ link->tosock = to_socket;
+ link->flag |= NODE_LINK_VALID;
+ BLI_addtail(&node.internal_links, link);
+ }
+ BKE_ntree_update_tag_node_internal_link(&ntree, &node);
+ }
+
+ void update_generic_callback(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ if (ntree.typeinfo->update == nullptr) {
+ return;
+ }
+
+ /* Reset the changed_flag to allow detecting when the update callback changed the node tree. */
+ const uint32_t old_changed_flag = ntree.changed_flag;
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+
+ ntree.typeinfo->update(&ntree);
+
+ if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ /* The tree ref is outdated and needs to be rebuilt. */
+ tree_ref.reset();
+ }
+ ntree.changed_flag |= old_changed_flag;
+ }
+
+ void remove_unused_previews_when_necessary(bNodeTree &ntree)
+ {
+ /* Don't trigger preview removal when only those flags are set. */
+ const uint32_t allowed_flags = NTREE_CHANGED_LINK | NTREE_CHANGED_SOCKET_PROPERTY |
+ NTREE_CHANGED_NODE_PROPERTY | NTREE_CHANGED_NODE_OUTPUT |
+ NTREE_CHANGED_INTERFACE;
+ if ((ntree.changed_flag & allowed_flags) == ntree.changed_flag) {
+ return;
+ }
+ BKE_node_preview_remove_unused(&ntree);
+ }
+
+ void update_node_levels(bNodeTree &ntree)
+ {
+ ntreeUpdateNodeLevels(&ntree);
+ }
+
+ void update_link_validation(bNodeTree &ntree)
+ {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ link->flag |= NODE_LINK_VALID;
+ if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) {
+ link->flag &= ~NODE_LINK_VALID;
+ }
+ else if (ntree.typeinfo->validate_link) {
+ const eNodeSocketDatatype from_type = static_cast<eNodeSocketDatatype>(
+ link->fromsock->type);
+ const eNodeSocketDatatype to_type = static_cast<eNodeSocketDatatype>(link->tosock->type);
+ if (!ntree.typeinfo->validate_link(from_type, to_type)) {
+ link->flag &= ~NODE_LINK_VALID;
+ }
+ }
+ }
+ }
+
+ bool check_if_output_changed(const NodeTreeRef &tree)
+ {
+ bNodeTree &btree = *tree.btree();
+
+ /* Compute a hash that represents the node topology connected to the output. This always has to
+ * be updated even if it is not used to detect changes right now. Otherwise
+ * #btree.output_topology_hash will go out of date. */
+ const Vector<const SocketRef *> tree_output_sockets = this->find_output_sockets(tree);
+ const uint32_t old_topology_hash = btree.output_topology_hash;
+ const uint32_t new_topology_hash = this->get_combined_socket_topology_hash(
+ tree, tree_output_sockets);
+ btree.output_topology_hash = new_topology_hash;
+
+ if (const AnimData *adt = BKE_animdata_from_id(&btree.id)) {
+ /* Drivers may copy values in the node tree around arbitrarily and may cause the output to
+ * change even if it wouldn't without drivers. Only some special drivers like `frame/5` can
+ * be used without causing updates all the time currently. In the future we could try to
+ * handle other drivers better as well.
+ * Note that this optimization only works in practice when the depsgraph didn't also get a
+ * copy-on-write tag for the node tree (which happens when changing node properties). It does
+ * work in a few situations like adding reroutes and duplicating nodes though. */
+ LISTBASE_FOREACH (const FCurve *, fcurve, &adt->drivers) {
+ const ChannelDriver *driver = fcurve->driver;
+ const StringRef expression = driver->expression;
+ if (expression.startswith("frame")) {
+ const StringRef remaining_expression = expression.drop_known_prefix("frame");
+ if (remaining_expression.find_first_not_of(" */+-0123456789.") == StringRef::not_found) {
+ continue;
+ }
+ }
+ /* Unrecognized driver, assume that the output always changes. */
+ return true;
+ }
+ }
+
+ if (btree.changed_flag & NTREE_CHANGED_ANY) {
+ return true;
+ }
+
+ if (old_topology_hash != new_topology_hash) {
+ return true;
+ }
+
+ /* The topology hash can only be used when only topology-changing operations have been done. */
+ if (btree.changed_flag ==
+ (btree.changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) {
+ if (old_topology_hash == new_topology_hash) {
+ return false;
+ }
+ }
+
+ if (!this->check_if_socket_outputs_changed_based_on_flags(tree, tree_output_sockets)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ Vector<const SocketRef *> find_output_sockets(const NodeTreeRef &tree)
+ {
+ Vector<const SocketRef *> sockets;
+ for (const NodeRef *node : tree.nodes()) {
+ const bNode *bnode = node->bnode();
+ if (bnode->typeinfo->nclass != NODE_CLASS_OUTPUT && bnode->type != NODE_GROUP_OUTPUT) {
+ continue;
+ }
+ for (const InputSocketRef *socket : node->inputs()) {
+ if (socket->idname() != "NodeSocketVirtual") {
+ sockets.append(socket);
+ }
+ }
+ }
+ return sockets;
+ }
+
+ /**
+ * Computes a hash that changes when the node tree topology connected to an output node changes.
+ * Adding reroutes does not have an effect on the hash.
+ */
+ uint32_t get_combined_socket_topology_hash(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ if (tree.has_link_cycles()) {
+ /* Return dummy value when the link has any cycles. The algorithm below could be improved to
+ * handle cycles more gracefully. */
+ return 0;
+ }
+ Array<uint32_t> hashes = this->get_socket_topology_hashes(tree, sockets);
+ uint32_t combined_hash = 0;
+ for (uint32_t hash : hashes) {
+ combined_hash = noise::hash(combined_hash, hash);
+ }
+ return combined_hash;
+ }
+
+ Array<uint32_t> get_socket_topology_hashes(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ BLI_assert(!tree.has_link_cycles());
+ Array<std::optional<uint32_t>> hash_by_socket_id(tree.sockets().size());
+ Stack<const SocketRef *> sockets_to_check = sockets;
+
+ while (!sockets_to_check.is_empty()) {
+ const SocketRef &in_out_socket = *sockets_to_check.peek();
+ const NodeRef &node = in_out_socket.node();
+
+ if (hash_by_socket_id[in_out_socket.id()].has_value()) {
+ sockets_to_check.pop();
+ /* Socket is handled already. */
+ continue;
+ }
+
+ if (in_out_socket.is_input()) {
+ /* For input sockets, first compute the hashes of all linked sockets. */
+ const InputSocketRef &socket = in_out_socket.as_input();
+ bool all_origins_computed = true;
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ if (!hash_by_socket_id[origin_socket->id()].has_value()) {
+ sockets_to_check.push(origin_socket);
+ all_origins_computed = false;
+ }
+ }
+ if (!all_origins_computed) {
+ continue;
+ }
+ /* When the hashes for the linked sockets are ready, combine them into a hash for the input
+ * socket. */
+ const uint64_t socket_ptr = (uintptr_t)socket.bsocket();
+ uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32);
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->id()];
+ socket_hash = noise::hash(socket_hash, origin_socket_hash);
+ }
+ hash_by_socket_id[socket.id()] = socket_hash;
+ sockets_to_check.pop();
+ }
+ else {
+ /* For output sockets, first compute the hashes of all available input sockets. */
+ const OutputSocketRef &socket = in_out_socket.as_output();
+ bool all_available_inputs_computed = true;
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ if (input_socket->is_available()) {
+ if (!hash_by_socket_id[input_socket->id()].has_value()) {
+ sockets_to_check.push(input_socket);
+ all_available_inputs_computed = false;
+ }
+ }
+ }
+ if (!all_available_inputs_computed) {
+ continue;
+ }
+ /* When all input socket hashes have been computed, combine them into a hash for the output
+ * socket. */
+ const uint64_t socket_ptr = (uintptr_t)socket.bsocket();
+ uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32);
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ if (input_socket->is_available()) {
+ const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->id()];
+ socket_hash = noise::hash(socket_hash, input_socket_hash);
+ }
+ }
+ hash_by_socket_id[socket.id()] = socket_hash;
+ sockets_to_check.pop();
+ }
+ }
+
+ /* Create output array. */
+ Array<uint32_t> hashes(sockets.size());
+ for (const int i : sockets.index_range()) {
+ hashes[i] = *hash_by_socket_id[sockets[i]->id()];
+ }
+ return hashes;
+ }
+
+ /**
+ * Returns true when any of the provided sockets changed its values. A change is detected by
+ * checking the #changed_flag on connected sockets and nodes.
+ */
+ bool check_if_socket_outputs_changed_based_on_flags(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ /* Avoid visiting the same socket twice when multiple links point to the same socket. */
+ Array<bool> pushed_by_socket_id(tree.sockets().size(), false);
+ Stack<const SocketRef *> sockets_to_check = sockets;
+
+ for (const SocketRef *socket : sockets) {
+ pushed_by_socket_id[socket->id()] = true;
+ }
+
+ while (!sockets_to_check.is_empty()) {
+ const SocketRef &in_out_socket = *sockets_to_check.pop();
+ const bNode &bnode = *in_out_socket.node().bnode();
+ const bNodeSocket &bsocket = *in_out_socket.bsocket();
+ if (bsocket.changed_flag != NTREE_CHANGED_NOTHING) {
+ return true;
+ }
+ if (bnode.changed_flag != NTREE_CHANGED_NOTHING) {
+ const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 &&
+ bnode.changed_flag ==
+ NTREE_CHANGED_INTERNAL_LINK;
+ if (!only_unused_internal_link_changed) {
+ return true;
+ }
+ }
+ if (in_out_socket.is_input()) {
+ const InputSocketRef &socket = in_out_socket.as_input();
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ bool &pushed = pushed_by_socket_id[origin_socket->id()];
+ if (!pushed) {
+ sockets_to_check.push(origin_socket);
+ pushed = true;
+ }
+ }
+ }
+ else {
+ const OutputSocketRef &socket = in_out_socket.as_output();
+ for (const InputSocketRef *input_socket : socket.node().inputs()) {
+ if (input_socket->is_available()) {
+ bool &pushed = pushed_by_socket_id[input_socket->id()];
+ if (!pushed) {
+ sockets_to_check.push(input_socket);
+ pushed = true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ void reset_changed_flags(bNodeTree &ntree)
+ {
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ node->changed_flag = NTREE_CHANGED_NOTHING;
+ node->update = 0;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->changed_flag = NTREE_CHANGED_NOTHING;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->changed_flag = NTREE_CHANGED_NOTHING;
+ }
+ }
+ }
+};
+
+} // namespace blender::bke
+
+void BKE_ntree_update_tag_all(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_ANY);
+}
+
+void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+}
+
+void BKE_ntree_update_tag_node_new(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_property(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_new(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_REMOVED_SOCKET);
+}
+
+void BKE_ntree_update_tag_socket_type(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_availability(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_node_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_REMOVED_NODE);
+}
+
+void BKE_ntree_update_tag_node_mute(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+}
+
+void BKE_ntree_update_tag_node_internal_link(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_INTERNAL_LINK);
+}
+
+void BKE_ntree_update_tag_link_changed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_added(bNodeTree *ntree, bNodeLink *UNUSED(link))
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_mute(bNodeTree *ntree, bNodeLink *UNUSED(link))
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_missing_runtime_data(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_ALL);
+}
+
+void BKE_ntree_update_tag_interface(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_INTERFACE);
+}
+
+void BKE_ntree_update_tag_id_changed(Main *bmain, ID *id)
+{
+ FOREACH_NODETREE_BEGIN (bmain, ntree, ntree_id) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == id) {
+ node->update |= NODE_UPDATE_ID;
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+}
+
+/**
+ * Protect from recursive calls into the updating function. Some node update functions might
+ * trigger this from Python or in other cases.
+ *
+ * This could be added to #Main, but given that there is generally only one #Main, that's not
+ * really worth it now.
+ */
+static bool is_updating = false;
+
+void BKE_ntree_update_main(Main *bmain, NodeTreeUpdateExtraParams *params)
+{
+ if (is_updating) {
+ return;
+ }
+
+ is_updating = true;
+ blender::bke::NodeTreeMainUpdater updater{bmain, params};
+ updater.update();
+ is_updating = false;
+}
+
+void BKE_ntree_update_main_tree(Main *bmain, bNodeTree *ntree, NodeTreeUpdateExtraParams *params)
+{
+ if (ntree == nullptr) {
+ BKE_ntree_update_main(bmain, params);
+ return;
+ }
+
+ if (is_updating) {
+ return;
+ }
+
+ is_updating = true;
+ blender::bke::NodeTreeMainUpdater updater{bmain, params};
+ updater.update_rooted({ntree});
+ is_updating = false;
+}
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 7fec91ed65a..e177b1ce29e 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -87,6 +87,7 @@
#include "BKE_camera.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
+#include "BKE_crazyspace.h"
#include "BKE_curve.h"
#include "BKE_deform.h"
#include "BKE_displist.h"
@@ -333,30 +334,9 @@ static void object_make_local(Main *bmain, ID *id, const int flags)
Object *ob = (Object *)id;
const bool lib_local = (flags & LIB_ID_MAKELOCAL_FULL_LIBRARY) != 0;
const bool clear_proxy = (flags & LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING) == 0;
- bool force_local = (flags & LIB_ID_MAKELOCAL_FORCE_LOCAL) != 0;
- bool force_copy = (flags & LIB_ID_MAKELOCAL_FORCE_COPY) != 0;
- BLI_assert(force_copy == false || force_copy != force_local);
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing (unless force_local is set)
- * - only local users: set flag
- * - mixed: make copy
- * In case we make a whole lib's content local,
- * we always want to localize, and we skip remapping (done later).
- */
-
- if (!force_local && !force_copy) {
- BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib);
- if (lib_local || is_local) {
- if (!is_lib) {
- force_local = true;
- }
- else {
- force_copy = true;
- }
- }
- }
+ bool force_local, force_copy;
+ BKE_lib_id_make_local_generic_action_define(bmain, id, flags, &force_local, &force_copy);
if (force_local) {
BKE_lib_id_clear_library_data(bmain, &ob->id, flags);
@@ -1773,8 +1753,9 @@ static void object_update_from_subsurf_ccg(Object *object)
if (!object->runtime.is_data_eval_owned) {
return;
}
- /* Object was never evaluated, so can not have CCG subdivision surface. */
- Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object);
+ /* Object was never evaluated, so can not have CCG subdivision surface. If it were evaluated, do
+ * not try to compute OpenSubDiv on the CPU as it is not needed here. */
+ Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(object);
if (mesh_eval == nullptr) {
return;
}
@@ -1866,6 +1847,12 @@ void BKE_object_free_derived_caches(Object *ob)
object_update_from_subsurf_ccg(ob);
+ if (ob->runtime.editmesh_eval_cage &&
+ ob->runtime.editmesh_eval_cage != reinterpret_cast<Mesh *>(ob->runtime.data_eval)) {
+ BKE_mesh_eval_delete(ob->runtime.editmesh_eval_cage);
+ }
+ ob->runtime.editmesh_eval_cage = nullptr;
+
if (ob->runtime.data_eval != nullptr) {
if (ob->runtime.is_data_eval_owned) {
ID *data_eval = ob->runtime.data_eval;
@@ -1895,6 +1882,8 @@ void BKE_object_free_derived_caches(Object *ob)
BKE_object_to_curve_clear(ob);
BKE_object_free_curve_cache(ob);
+ BKE_crazyspace_api_eval_clear(ob);
+
/* Clear grease pencil data. */
if (ob->runtime.gpd_eval != nullptr) {
BKE_gpencil_eval_delete(ob->runtime.gpd_eval);
@@ -1905,6 +1894,8 @@ void BKE_object_free_derived_caches(Object *ob)
BKE_geometry_set_free(ob->runtime.geometry_set_eval);
ob->runtime.geometry_set_eval = nullptr;
}
+
+ MEM_SAFE_FREE(ob->runtime.editmesh_bb_cage);
}
void BKE_object_free_caches(Object *object)
@@ -3410,7 +3401,8 @@ static void give_parvert(Object *par, int nr, float vec[3])
if (par->type == OB_MESH) {
Mesh *me = (Mesh *)par->data;
BMEditMesh *em = me->edit_mesh;
- Mesh *me_eval = (em) ? em->mesh_eval_final : BKE_object_get_evaluated_mesh(par);
+ Mesh *me_eval = (em) ? BKE_object_get_editmesh_eval_final(par) :
+ BKE_object_get_evaluated_mesh(par);
if (me_eval) {
int count = 0;
@@ -3793,7 +3785,7 @@ BoundBox *BKE_boundbox_alloc_unit()
{
const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
- BoundBox *bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "OB-BoundBox");
+ BoundBox *bb = MEM_cnew<BoundBox>("OB-BoundBox");
BKE_boundbox_init_from_minmax(bb, min, max);
return bb;
@@ -3903,7 +3895,7 @@ void BKE_object_boundbox_calc_from_mesh(Object *ob, const Mesh *me_eval)
}
if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "DM-BoundBox");
+ ob->runtime.bb = MEM_cnew<BoundBox>("DM-BoundBox");
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
@@ -3917,11 +3909,15 @@ bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
INIT_MINMAX(min, max);
if (ob->runtime.geometry_set_eval) {
- ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max);
+ if (!ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max)) {
+ zero_v3(min);
+ zero_v3(max);
+ }
}
else if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob)) {
if (!BKE_mesh_wrapper_minmax(mesh_eval, min, max)) {
- return false;
+ zero_v3(min);
+ zero_v3(max);
}
}
else if (ob->runtime.curve_cache) {
@@ -3932,7 +3928,7 @@ bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
}
if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
+ ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
@@ -4108,7 +4104,7 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value)
if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
if (!ob->iuser) {
- ob->iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "image user");
+ ob->iuser = MEM_cnew<ImageUser>("image user");
ob->iuser->flag |= IMA_ANIM_ALWAYS;
ob->iuser->frames = 100;
ob->iuser->sfra = 1;
@@ -4447,7 +4443,7 @@ void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
void BKE_object_sculpt_data_create(Object *ob)
{
BLI_assert((ob->sculpt == nullptr) && (ob->mode & OB_MODE_ALL_SCULPT));
- ob->sculpt = (SculptSession *)MEM_callocN(sizeof(SculptSession), __func__);
+ ob->sculpt = MEM_cnew<SculptSession>(__func__);
ob->sculpt->mode_type = (eObjectMode)ob->mode;
}
@@ -4496,7 +4492,7 @@ bool BKE_object_obdata_texspace_get(Object *ob, char **r_texflag, float **r_loc,
return true;
}
-Mesh *BKE_object_get_evaluated_mesh(const Object *object)
+Mesh *BKE_object_get_evaluated_mesh_no_subsurf(const Object *object)
{
/* First attempt to retrieve the evaluated mesh from the evaluated geometry set. Most
* object types either store it there or add a reference to it if it's owned elsewhere. */
@@ -4523,6 +4519,20 @@ Mesh *BKE_object_get_evaluated_mesh(const Object *object)
return nullptr;
}
+Mesh *BKE_object_get_evaluated_mesh(const Object *object)
+{
+ Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(object);
+ if (!mesh) {
+ return nullptr;
+ }
+
+ if (object->data && GS(((const ID *)object->data)->name) == ID_ME) {
+ mesh = BKE_mesh_wrapper_ensure_subdivision(object, mesh);
+ }
+
+ return mesh;
+}
+
Mesh *BKE_object_get_pre_modified_mesh(const Object *object)
{
if (object->type == OB_MESH && object->runtime.data_orig != nullptr) {
@@ -4555,6 +4565,33 @@ Mesh *BKE_object_get_original_mesh(const Object *object)
return result;
}
+Mesh *BKE_object_get_editmesh_eval_final(const Object *object)
+{
+ BLI_assert(!DEG_is_original_id(&object->id));
+ BLI_assert(object->type == OB_MESH);
+
+ const Mesh *mesh = static_cast<const Mesh *>(object->data);
+ if (mesh->edit_mesh == nullptr) {
+ /* Happens when requesting material of evaluated 3d font object: the evaluated object get
+ * converted to mesh, and it does not have edit mesh. */
+ return nullptr;
+ }
+
+ return reinterpret_cast<Mesh *>(object->runtime.data_eval);
+}
+
+Mesh *BKE_object_get_editmesh_eval_cage(const Object *object)
+{
+ BLI_assert(!DEG_is_original_id(&object->id));
+ BLI_assert(object->type == OB_MESH);
+
+ const Mesh *mesh = static_cast<const Mesh *>(object->data);
+ BLI_assert(mesh->edit_mesh != nullptr);
+ UNUSED_VARS_NDEBUG(mesh);
+
+ return object->runtime.editmesh_eval_cage;
+}
+
Lattice *BKE_object_get_lattice(const Object *object)
{
ID *data = (ID *)object->data;
@@ -4621,7 +4658,7 @@ int BKE_object_insert_ptcache(Object *ob)
}
}
- link = (LinkData *)MEM_callocN(sizeof(LinkData), "PCLink");
+ link = MEM_cnew<LinkData>("PCLink");
link->data = POINTER_FROM_INT(i);
BLI_addtail(&ob->pc_ids, link);
@@ -5185,6 +5222,9 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag))
runtime->object_as_temp_mesh = nullptr;
runtime->object_as_temp_curve = nullptr;
runtime->geometry_set_eval = nullptr;
+
+ runtime->crazyspace_deform_imats = nullptr;
+ runtime->crazyspace_deform_cos = nullptr;
}
void BKE_object_runtime_free_data(Object *object)
@@ -5779,6 +5819,21 @@ void BKE_object_modifiers_lib_link_common(void *userData,
}
}
+SubsurfModifierData *BKE_object_get_last_subsurf_modifier(const Object *ob)
+{
+ ModifierData *md = (ModifierData *)(ob->modifiers.last);
+
+ while (md) {
+ if (md->type == eModifierType_Subsurf) {
+ break;
+ }
+
+ md = md->prev;
+ }
+
+ return (SubsurfModifierData *)(md);
+}
+
void BKE_object_replace_data_on_shallow_copy(Object *ob, ID *new_data)
{
ob->type = BKE_object_obdata_to_type(new_data);
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index 18bcf2041c3..3082d6f25f3 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -31,9 +31,9 @@
#include "BLI_string_utf8.h"
#include "BLI_array.hh"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_rand.h"
#include "BLI_span.hh"
#include "BLI_vector.hh"
@@ -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;
}
/**
@@ -188,7 +190,7 @@ static DupliObject *make_dupli(const DupliContext *ctx,
/* Add a #DupliObject instance to the result container. */
if (ctx->duplilist) {
- dob = (DupliObject *)MEM_callocN(sizeof(DupliObject), "dupli object");
+ dob = MEM_cnew<DupliObject>("dupli object");
BLI_addtail(ctx->duplilist, dob);
}
else {
@@ -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++;
}
@@ -367,7 +371,7 @@ static const Mesh *mesh_data_from_duplicator_object(Object *ob,
if (em != nullptr) {
/* Note that this will only show deformation if #eModifierMode_OnCage is enabled.
* We could change this but it matches 2.7x behavior. */
- me_eval = em->mesh_eval_cage;
+ me_eval = BKE_object_get_editmesh_eval_cage(ob);
if ((me_eval == nullptr) || (me_eval->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) {
EditMeshData *emd = me_eval ? me_eval->runtime.edit_data : nullptr;
@@ -457,6 +461,7 @@ struct VertexDupliData_Mesh {
int totvert;
const MVert *mvert;
+ const float (*vert_normals)[3];
const float (*orco)[3];
};
@@ -554,12 +559,9 @@ static void make_child_duplis_verts_from_mesh(const DupliContext *ctx,
float child_imat[4][4];
mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat);
- const MVert *mv = mvert;
- for (int i = 0; i < totvert; i++, mv++) {
- const float *co = mv->co;
- float no[3];
- normal_short_to_float_v3(no, mv->no);
- DupliObject *dob = vertex_dupli(vdd->params.ctx, inst_ob, child_imat, i, co, no, use_rotation);
+ for (int i = 0; i < totvert; i++) {
+ DupliObject *dob = vertex_dupli(
+ vdd->params.ctx, inst_ob, child_imat, i, mvert[i].co, vdd->vert_normals[i], use_rotation);
if (vdd->orco) {
copy_v3_v3(dob->orco, vdd->orco[i]);
}
@@ -636,6 +638,7 @@ static void make_duplis_verts(const DupliContext *ctx)
vdd.params = vdd_params;
vdd.totvert = me_eval->totvert;
vdd.mvert = me_eval->mvert;
+ vdd.vert_normals = BKE_mesh_vertex_normals_ensure(me_eval);
vdd.orco = (const float(*)[3])CustomData_get_layer(&me_eval->vdata, CD_ORCO);
make_child_duplis(ctx, &vdd, make_child_duplis_verts_from_mesh);
@@ -893,7 +896,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 +933,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 +958,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: {
@@ -1017,6 +1025,8 @@ static void get_dupliface_transform_from_coords(Span<float3> coords,
const float scale_fac,
float r_mat[4][4])
{
+ using namespace blender::math;
+
/* Location. */
float3 location(0);
for (const float3 &coord : coords) {
@@ -1027,9 +1037,7 @@ static void get_dupliface_transform_from_coords(Span<float3> coords,
/* Rotation. */
float quat[4];
- float3 f_no;
- cross_poly_v3(f_no, (const float(*)[3])coords.data(), (uint)coords.size());
- f_no.normalize();
+ float3 f_no = normalize(cross_poly(coords));
tri_to_quat_ex(quat, coords[0], coords[1], coords[2], f_no);
/* Scale. */
@@ -1609,8 +1617,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);
+ }
}
}
@@ -1640,6 +1649,14 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
return nullptr;
}
+ /* Give "Object as Font" instances higher priority than geometry set instances, to retain
+ * the behavior from before curve object meshes were processed as instances internally. */
+ if (transflag & OB_DUPLIVERTS) {
+ if (ctx->object->type == OB_FONT) {
+ return &gen_dupli_verts_font;
+ }
+ }
+
if (ctx->object->runtime.geometry_set_eval != nullptr) {
if (BKE_object_has_geometry_set_instances(ctx->object)) {
return &gen_dupli_geometry_set;
@@ -1653,9 +1670,6 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
if (ctx->object->type == OB_MESH) {
return &gen_dupli_verts;
}
- if (ctx->object->type == OB_FONT) {
- return &gen_dupli_verts_font;
- }
if (ctx->object->type == OB_POINTCLOUD) {
return &gen_dupli_verts_pointcloud;
}
@@ -1680,7 +1694,7 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
{
- ListBase *duplilist = (ListBase *)MEM_callocN(sizeof(ListBase), "duplilist");
+ ListBase *duplilist = MEM_cnew<ListBase>("duplilist");
DupliContext ctx;
Vector<Object *> instance_stack;
instance_stack.append(ob);
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 4c0d0303c1f..1a208355870 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -160,12 +160,6 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
/* includes all keys and modifiers */
switch (ob->type) {
case OB_MESH: {
-#if 0
- BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL;
-#else
- BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? ((Mesh *)ob->data)->edit_mesh : NULL;
-#endif
-
CustomData_MeshMasks cddata_masks = scene->customdata_mask;
CustomData_MeshMasks_update(&cddata_masks, &CD_MASK_BAREMESH);
/* Custom attributes should not be removed automatically. They might be used by the render
@@ -175,6 +169,11 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
cddata_masks.fmask |= CD_MASK_PROP_ALL;
cddata_masks.pmask |= CD_MASK_PROP_ALL;
cddata_masks.lmask |= CD_MASK_PROP_ALL;
+
+ /* Also copy over normal layers to avoid recomputation. */
+ cddata_masks.pmask |= CD_MASK_NORMAL;
+ cddata_masks.vmask |= CD_MASK_NORMAL;
+
/* Make sure Freestyle edge/face marks appear in DM for render (see T40315).
* Due to Line Art implementation, edge marks should also be shown in viewport. */
#ifdef WITH_FREESTYLE
@@ -187,12 +186,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
cddata_masks.lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
cddata_masks.vmask |= CD_MASK_ORCO | CD_MASK_PROP_COLOR;
}
- if (em) {
- makeDerivedMesh(depsgraph, scene, ob, em, &cddata_masks); /* was CD_MASK_BAREMESH */
- }
- else {
- makeDerivedMesh(depsgraph, scene, ob, NULL, &cddata_masks);
- }
+ makeDerivedMesh(depsgraph, scene, ob, &cddata_masks); /* was CD_MASK_BAREMESH */
break;
}
case OB_ARMATURE:
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 8989450e41b..3ddcdb424f9 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -734,7 +734,7 @@ void BKE_packedfile_pack_all_libraries(Main *bmain, ReportList *reports)
{
Library *lib;
- /* test for relativenss */
+ /* Test for relativeness. */
for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
if (!BLI_path_is_rel(lib->filepath)) {
break;
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 72210eea71d..407375c4d22 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1648,6 +1648,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->totvert = me->totvert;
ss->totpoly = me->totpoly;
ss->totfaces = me->totpoly;
+ ss->vert_normals = BKE_mesh_vertex_normals_ensure(me);
ss->mvert = me->mvert;
ss->mpoly = me->mpoly;
ss->mloop = me->mloop;
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 674f264feb7..4dba13ce4c2 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -1674,6 +1674,7 @@ static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCach
/************************************************/
void psys_interpolate_face(MVert *mvert,
+ const float (*vert_normals)[3],
MFace *mface,
MTFace *tface,
float (*orcodata)[3],
@@ -1695,13 +1696,13 @@ void psys_interpolate_face(MVert *mvert,
v2 = mvert[mface->v2].co;
v3 = mvert[mface->v3].co;
- normal_short_to_float_v3(n1, mvert[mface->v1].no);
- normal_short_to_float_v3(n2, mvert[mface->v2].no);
- normal_short_to_float_v3(n3, mvert[mface->v3].no);
+ copy_v3_v3(n1, vert_normals[mface->v1]);
+ copy_v3_v3(n2, vert_normals[mface->v2]);
+ copy_v3_v3(n3, vert_normals[mface->v3]);
if (mface->v4) {
v4 = mvert[mface->v4].co;
- normal_short_to_float_v3(n4, mvert[mface->v4].no);
+ copy_v3_v3(n4, vert_normals[mface->v4]);
interp_v3_v3v3v3v3(vec, v1, v2, v3, v4, w);
@@ -2124,13 +2125,13 @@ void psys_particle_on_dm(Mesh *mesh_final,
}
orcodata = CustomData_get_layer(&mesh_final->vdata, CD_ORCO);
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh_final);
if (from == PART_FROM_VERT) {
copy_v3_v3(vec, mesh_final->mvert[mapindex].co);
if (nor) {
- normal_short_to_float_v3(nor, mesh_final->mvert[mapindex].no);
- normalize_v3(nor);
+ copy_v3_v3(nor, vert_normals[mapindex]);
}
if (orco) {
@@ -2161,7 +2162,8 @@ void psys_particle_on_dm(Mesh *mesh_final,
}
if (from == PART_FROM_VOLUME) {
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco);
+ psys_interpolate_face(
+ mvert, vert_normals, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco);
if (nor) {
copy_v3_v3(nor, tmpnor);
}
@@ -2173,7 +2175,8 @@ void psys_particle_on_dm(Mesh *mesh_final,
add_v3_v3(vec, tmpnor);
}
else {
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco);
+ psys_interpolate_face(
+ mvert, vert_normals, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco);
}
}
}
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index fd4f89e3f6d..ba3f99a2800 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -626,7 +626,8 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
/* experimental */
tot = mesh->totface;
- psys_interpolate_face(mvert, mface, 0, 0, pa->fuv, co, nor, 0, 0, 0);
+ psys_interpolate_face(
+ mvert, BKE_mesh_vertex_normals_ensure(mesh), mface, 0, 0, pa->fuv, co, nor, 0, 0, 0);
normalize_v3(nor);
negate_v3(nor);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 2f22f94d142..1926bbcda02 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -32,7 +32,7 @@
#include "DNA_meshdata_types.h"
#include "BKE_ccg.h"
-#include "BKE_mesh.h" /* for BKE_mesh_calc_normals */
+#include "BKE_mesh.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_subdiv_ccg.h"
@@ -552,7 +552,7 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
}
void BKE_pbvh_build_mesh(PBVH *pbvh,
- const Mesh *mesh,
+ Mesh *mesh,
const MPoly *mpoly,
const MLoop *mloop,
MVert *verts,
@@ -572,6 +572,8 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
pbvh->mloop = mloop;
pbvh->looptri = looptri;
pbvh->verts = verts;
+ BKE_mesh_vertex_normals_ensure(mesh);
+ pbvh->vert_normals = BKE_mesh_vertex_normals_for_write(mesh);
pbvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap");
pbvh->totvert = totvert;
pbvh->leaf_limit = LEAF_LIMIT;
@@ -1076,7 +1078,6 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
* so we know only this thread will handle this vertex. */
if (mvert->flag & ME_VERT_PBVH_UPDATE) {
normalize_v3(vnors[v]);
- normal_float_to_short_v3(mvert->no, vnors[v]);
mvert->flag &= ~ME_VERT_PBVH_UPDATE;
}
}
@@ -1087,10 +1088,6 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
{
- /* could be per node to save some memory, but also means
- * we have to store for each vertex which node it is in */
- float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * pbvh->totvert, __func__);
-
/* subtle assumptions:
* - We know that for all edited vertices, the nodes with faces
* adjacent to these vertices have been marked with PBVH_UpdateNormals.
@@ -1104,7 +1101,7 @@ static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
PBVHUpdateData data = {
.pbvh = pbvh,
.nodes = nodes,
- .vnors = vnors,
+ .vnors = pbvh->vert_normals,
};
TaskParallelSettings settings;
@@ -1112,8 +1109,6 @@ static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
-
- MEM_freeN(vnors);
}
static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
@@ -1300,6 +1295,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
case PBVH_FACES:
GPU_pbvh_mesh_buffers_update(node->draw_buffers,
pbvh->verts,
+ pbvh->vert_normals,
CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK),
CustomData_get_layer(pbvh->ldata, CD_MLOOPCOL),
CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
@@ -2964,6 +2960,8 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->mask = NULL;
if (pbvh->type == PBVH_FACES) {
+ vi->vert_normals = pbvh->vert_normals;
+
vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK);
vi->vcol = CustomData_get_layer(pbvh->vdata, CD_PROP_COLOR);
}
@@ -3037,6 +3035,12 @@ MVert *BKE_pbvh_get_verts(const PBVH *pbvh)
return pbvh->verts;
}
+const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3]
+{
+ BLI_assert(pbvh->type == PBVH_FACES);
+ return pbvh->vert_normals;
+}
+
void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, SubdivCCG *subdiv_ccg)
{
pbvh->subdiv_ccg = subdiv_ccg;
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 12c2d7aac78..9562cda5f28 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -130,6 +130,9 @@ struct PBVH {
/* Mesh data */
const struct Mesh *mesh;
+
+ /* Note: Normals are not const because they can be updated for drawing by sculpt code. */
+ float (*vert_normals)[3];
MVert *verts;
const MPoly *mpoly;
const MLoop *mloop;
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 094181afca9..602546db8df 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -831,31 +831,23 @@ static void ptcache_rigidbody_interpolate(int index,
RigidBodyOb *rbo = ob->rigidbody_object;
if (rbo->type == RBO_TYPE_ACTIVE) {
- ParticleKey keys[4];
- ParticleKey result;
- float dfra;
-
- memset(keys, 0, sizeof(keys));
-
- copy_v3_v3(keys[1].co, rbo->pos);
- copy_qt_qt(keys[1].rot, rbo->orn);
+ /* It may be possible to improve results by taking into account velocity
+ * for interpolation using psys_interpolate_particle, however this is
+ * not currently cached. */
+ float pos[3], orn[4];
if (old_data) {
- memcpy(keys[2].co, data, sizeof(float[3]));
- memcpy(keys[2].rot, data + 3, sizeof(float[4]));
+ memcpy(pos, data, sizeof(float[3]));
+ memcpy(orn, data + 3, sizeof(float[4]));
}
else {
- BKE_ptcache_make_particle_key(&keys[2], 0, data, cfra2);
+ PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, index, pos);
+ PTCACHE_DATA_TO(data, BPHYS_DATA_ROTATION, index, orn);
}
- dfra = cfra2 - cfra1;
-
- /* NOTE: keys[0] and keys[3] unused for type < 1 (crappy). */
- psys_interpolate_particle(-1, keys, (cfra - cfra1) / dfra, &result, true);
- interp_qt_qtqt(result.rot, keys[1].rot, keys[2].rot, (cfra - cfra1) / dfra);
-
- copy_v3_v3(rbo->pos, result.co);
- copy_qt_qt(rbo->orn, result.rot);
+ const float t = (cfra - cfra1) / (cfra2 - cfra1);
+ interp_v3_v3v3(rbo->pos, rbo->pos, pos, t);
+ interp_qt_qtqt(rbo->orn, rbo->orn, orn, t);
}
}
}
@@ -1322,10 +1314,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) {
@@ -1337,7 +1330,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));
@@ -1422,8 +1415,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 */
@@ -1469,8 +1465,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);
@@ -3444,8 +3443,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");
@@ -3497,6 +3497,11 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
char old_path_full[MAX_PTCACHE_FILE];
char ext[MAX_PTCACHE_PATH];
+ /* If both names are the same, there is nothing to do. */
+ if (STREQ(name_src, name_dst)) {
+ return;
+ }
+
/* save old name */
BLI_strncpy(old_name, pid->cache->name, sizeof(old_name));
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 82dde79cff6..b5f016e4d76 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -25,10 +25,13 @@
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_rand.h"
+#include "BLI_span.hh"
#include "BLI_string.h"
+#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
@@ -51,6 +54,10 @@
#include "BLO_read_write.h"
+using blender::float3;
+using blender::IndexRange;
+using blender::Span;
+
/* PointCloud datablock */
static void pointcloud_random(PointCloud *pointcloud);
@@ -261,18 +268,70 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
return pointcloud;
}
-void BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3])
+struct MinMaxResult {
+ float3 min;
+ float3 max;
+};
+
+static MinMaxResult min_max_no_radii(Span<float3> positions)
{
- float(*pointcloud_co)[3] = pointcloud->co;
- float *pointcloud_radius = pointcloud->radius;
- for (int a = 0; a < pointcloud->totpoint; a++) {
- float *co = pointcloud_co[a];
- float radius = (pointcloud_radius) ? pointcloud_radius[a] : 0.0f;
- const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius};
- const float co_max[3] = {co[0] + radius, co[1] + radius, co[2] + radius};
- DO_MIN(co_min, r_min);
- DO_MAX(co_max, r_max);
+ using namespace blender::math;
+
+ return blender::threading::parallel_reduce(
+ positions.index_range(),
+ 1024,
+ MinMaxResult{float3(FLT_MAX), float3(-FLT_MAX)},
+ [&](IndexRange range, const MinMaxResult &init) {
+ MinMaxResult result = init;
+ for (const int i : range) {
+ min_max(positions[i], result.min, result.max);
+ }
+ return result;
+ },
+ [](const MinMaxResult &a, const MinMaxResult &b) {
+ return MinMaxResult{min(a.min, b.min), max(a.max, b.max)};
+ });
+}
+
+static MinMaxResult min_max_with_radii(Span<float3> positions, Span<float> radii)
+{
+ using namespace blender::math;
+
+ return blender::threading::parallel_reduce(
+ positions.index_range(),
+ 1024,
+ MinMaxResult{float3(FLT_MAX), float3(-FLT_MAX)},
+ [&](IndexRange range, const MinMaxResult &init) {
+ MinMaxResult result = init;
+ for (const int i : range) {
+ result.min = min(positions[i] - radii[i], result.min);
+ result.max = max(positions[i] + radii[i], result.max);
+ }
+ return result;
+ },
+ [](const MinMaxResult &a, const MinMaxResult &b) {
+ return MinMaxResult{min(a.min, b.min), max(a.max, b.max)};
+ });
+}
+
+bool BKE_pointcloud_minmax(const PointCloud *pointcloud, float r_min[3], float r_max[3])
+{
+ using namespace blender::math;
+
+ if (!pointcloud->totpoint) {
+ return false;
}
+
+ Span<float3> positions{reinterpret_cast<float3 *>(pointcloud->co), pointcloud->totpoint};
+ const MinMaxResult min_max = (pointcloud->radius) ?
+ min_max_with_radii(positions,
+ {pointcloud->radius, pointcloud->totpoint}) :
+ min_max_no_radii(positions);
+
+ copy_v3_v3(r_min, min(min_max.min, float3(r_min)));
+ copy_v3_v3(r_max, max(min_max.max, float3(r_max)));
+
+ return true;
}
BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
@@ -287,7 +346,7 @@ BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
ob->runtime.bb = static_cast<BoundBox *>(MEM_callocN(sizeof(BoundBox), "pointcloud boundbox"));
}
- blender::float3 min, max;
+ float3 min, max;
INIT_MINMAX(min, max);
if (ob->runtime.geometry_set_eval != nullptr) {
ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max);
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index cd8493ee559..6e352b6ba90 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -900,7 +900,7 @@ ARegion *BKE_area_find_region_active_win(ScrArea *area)
return BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
}
-ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int y)
+ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, const int xy[2])
{
if (area == NULL) {
return NULL;
@@ -908,7 +908,7 @@ ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
- if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
+ if (BLI_rcti_isect_pt_v(&region->winrct, xy)) {
return region;
}
}
@@ -916,11 +916,11 @@ ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int
return NULL;
}
-ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x, int y)
+ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, const int xy[2])
{
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
- if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
+ if (BLI_rcti_isect_pt_v(&region->winrct, xy)) {
return region;
}
}
@@ -961,11 +961,10 @@ ScrArea *BKE_screen_find_big_area(bScreen *screen, const int spacetype, const sh
ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
const int spacetype,
- int x,
- int y)
+ const int xy[2])
{
LISTBASE_FOREACH (ScrArea *, area, &areamap->areabase) {
- if (BLI_rcti_isect_pt(&area->totrct, x, y)) {
+ if (BLI_rcti_isect_pt_v(&area->totrct, xy)) {
if (ELEM(spacetype, SPACE_TYPE_ANY, area->spacetype)) {
return area;
}
@@ -974,9 +973,9 @@ ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
}
return NULL;
}
-ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, int x, int y)
+ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, const int xy[2])
{
- return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, x, y);
+ return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, xy);
}
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
@@ -1016,16 +1015,13 @@ void BKE_screen_view3d_shading_init(View3DShading *shading)
memcpy(shading, shading_default, sizeof(*shading));
}
-ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen,
- const int space_type,
- const int x,
- const int y)
+ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen, const int space_type, const int xy[2])
{
- ScrArea *area = BKE_screen_find_area_xy(screen, space_type, x, y);
+ ScrArea *area = BKE_screen_find_area_xy(screen, space_type, xy);
if (!area) {
return NULL;
}
- return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, x, y);
+ return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, xy);
}
/* Magic zoom calculation, no idea what it signifies, if you find out, tell me! -zr
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 7618323f488..d51ed2832f0 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -75,7 +75,8 @@ typedef struct ShrinkwrapCalcData {
struct Object *ob; /* object we are applying shrinkwrap to */
- struct MVert *vert; /* Array of verts being projected (to fetch normals or other data) */
+ struct MVert *vert; /* Array of verts being projected. */
+ const float (*vert_normals)[3];
float (*vertexCos)[3]; /* vertexs being shrinkwraped */
int numVerts;
@@ -146,7 +147,7 @@ bool BKE_shrinkwrap_init_tree(
}
if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
- data->pnors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ data->pnors = BKE_mesh_poly_normals_ensure(mesh);
if ((mesh->flag & ME_AUTOSMOOTH) != 0) {
data->clnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
}
@@ -313,18 +314,18 @@ static ShrinkwrapBoundaryData *shrinkwrap_build_boundary_data(struct Mesh *mesh)
MEM_freeN(vert_status);
/* Finalize average direction and compute normal. */
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
for (int i = 0; i < mesh->totvert; i++) {
int bidx = vert_boundary_id[i];
if (bidx >= 0) {
ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx];
- float no[3], tmp[3];
+ float tmp[3];
normalize_v3(vdata->direction);
- normal_short_to_float_v3(no, mesh->mvert[i].no);
- cross_v3_v3v3(tmp, no, vdata->direction);
- cross_v3_v3v3(vdata->normal_plane, tmp, no);
+ cross_v3_v3v3(tmp, vert_normals[i], vdata->direction);
+ cross_v3_v3v3(vdata->normal_plane, tmp, vert_normals[i]);
normalize_v3(vdata->normal_plane);
}
}
@@ -540,7 +541,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex(void *__restrict userdata,
* (to get correct normals) for other cases calc->verts contains undeformed coordinates and
* vertexCos should be used */
copy_v3_v3(tmp_co, calc->vert[i].co);
- normal_short_to_float_v3(tmp_no, calc->vert[i].no);
+ copy_v3_v3(tmp_no, calc->vert_normals[i]);
}
else {
copy_v3_v3(tmp_co, co);
@@ -1008,8 +1009,8 @@ static void target_project_edge(const ShrinkwrapTreeData *tree,
CLAMP(x, 0, 1);
float vedge_no[2][3];
- normal_short_to_float_v3(vedge_no[0], data->vert[edge->v1].no);
- normal_short_to_float_v3(vedge_no[1], data->vert[edge->v2].no);
+ copy_v3_v3(vedge_no[0], data->vert_normals[edge->v1]);
+ copy_v3_v3(vedge_no[1], data->vert_normals[edge->v2]);
interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x);
interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x);
@@ -1055,9 +1056,9 @@ static void mesh_looptri_target_project(void *userdata,
}
/* Decode normals */
- normal_short_to_float_v3(vtri_no[0], vtri[0]->no);
- normal_short_to_float_v3(vtri_no[1], vtri[1]->no);
- normal_short_to_float_v3(vtri_no[2], vtri[2]->no);
+ copy_v3_v3(vtri_no[0], tree->treeData.vert_normals[loop[0]->v]);
+ copy_v3_v3(vtri_no[1], tree->treeData.vert_normals[loop[1]->v]);
+ copy_v3_v3(vtri_no[2], tree->treeData.vert_normals[loop[2]->v]);
/* Solve the equations for the triangle */
if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) {
@@ -1191,14 +1192,13 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
{
const BVHTreeFromMesh *treeData = &tree->treeData;
const MLoopTri *tri = &treeData->looptri[looptri_idx];
+ const float(*vert_normals)[3] = tree->treeData.vert_normals;
/* Interpolate smooth normals if enabled. */
if ((tree->mesh->mpoly[tri->poly].flag & ME_SMOOTH) != 0) {
- const MVert *verts[] = {
- &treeData->vert[treeData->loop[tri->tri[0]].v],
- &treeData->vert[treeData->loop[tri->tri[1]].v],
- &treeData->vert[treeData->loop[tri->tri[2]].v],
- };
+ const uint32_t vert_indices[3] = {treeData->loop[tri->tri[0]].v,
+ treeData->loop[tri->tri[1]].v,
+ treeData->loop[tri->tri[2]].v};
float w[3], no[3][3], tmp_co[3];
/* Custom and auto smooth split normals. */
@@ -1209,9 +1209,9 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
}
/* Ordinary vertex normals. */
else {
- normal_short_to_float_v3(no[0], verts[0]->no);
- normal_short_to_float_v3(no[1], verts[1]->no);
- normal_short_to_float_v3(no[2], verts[2]->no);
+ copy_v3_v3(no[0], vert_normals[vert_indices[0]]);
+ copy_v3_v3(no[1], vert_normals[vert_indices[1]]);
+ copy_v3_v3(no[2], vert_normals[vert_indices[2]]);
}
/* Barycentric weights from hit point. */
@@ -1221,7 +1221,11 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
BLI_space_transform_apply(transform, tmp_co);
}
- interp_weights_tri_v3(w, verts[0]->co, verts[1]->co, verts[2]->co, tmp_co);
+ interp_weights_tri_v3(w,
+ treeData->vert[vert_indices[0]].co,
+ treeData->vert[vert_indices[1]].co,
+ treeData->vert[vert_indices[2]].co,
+ tmp_co);
/* Interpolate using weights. */
interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w);
@@ -1424,6 +1428,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
if (mesh != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
/* Setup arrays to get vertexs positions, normals and deform weights */
calc.vert = mesh->mvert;
+ calc.vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
/* Using vertexs positions/normals as if a subsurface was applied */
if (smd->subsurfLevels) {
@@ -1581,6 +1586,7 @@ void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object
calc.smd = &ssmd;
calc.numVerts = src_me->totvert;
calc.vertexCos = vertexCos;
+ calc.vert_normals = BKE_mesh_vertex_normals_ensure(src_me);
calc.vgroup = -1;
calc.target = target_me;
calc.keepDist = ssmd.keepDist;
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index b0f9de5963a..ec4b0e8d51d 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -28,9 +28,9 @@
#include "DNA_simulation_types.h"
#include "BLI_compiler_compat.h"
-#include "BLI_float3.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_rand.h"
#include "BLI_span.hh"
#include "BLI_string.h"
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index b811c17a3bc..baabf57f0c3 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -1673,7 +1673,7 @@ static int sb_detect_vertex_collisionCached(float opco[3],
if ((opco[0] < minx) || (opco[1] < miny) || (opco[2] < minz) || (opco[0] > maxx) ||
(opco[1] > maxy) || (opco[2] > maxz)) {
- /* outside the padded boundbox --> collision object is too far away */
+ /* Outside the padded bound-box -> collision object is too far away. */
BLI_ghashIterator_step(ihash);
continue;
}
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index 4ff392a5ddb..3262d768b6c 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -166,13 +166,15 @@ static void accumulate_lengths(Span<float3> positions,
const bool is_cyclic,
MutableSpan<float> lengths)
{
+ using namespace blender::math;
+
float length = 0.0f;
for (const int i : IndexRange(positions.size() - 1)) {
- length += float3::distance(positions[i], positions[i + 1]);
+ length += distance(positions[i], positions[i + 1]);
lengths[i] = length;
}
if (is_cyclic) {
- lengths.last() = length + float3::distance(positions.last(), positions.first());
+ lengths.last() = length + distance(positions.last(), positions.first());
}
}
@@ -200,11 +202,13 @@ Span<float> Spline::evaluated_lengths() const
static float3 direction_bisect(const float3 &prev, const float3 &middle, const float3 &next)
{
- const float3 dir_prev = (middle - prev).normalized();
- const float3 dir_next = (next - middle).normalized();
+ using namespace blender::math;
+
+ const float3 dir_prev = normalize(middle - prev);
+ const float3 dir_next = normalize(next - middle);
- const float3 result = (dir_prev + dir_next).normalized();
- if (UNLIKELY(result.is_zero())) {
+ const float3 result = normalize(dir_prev + dir_next);
+ if (UNLIKELY(is_zero(result))) {
return float3(0.0f, 0.0f, 1.0f);
}
return result;
@@ -214,6 +218,8 @@ static void calculate_tangents(Span<float3> positions,
const bool is_cyclic,
MutableSpan<float3> tangents)
{
+ using namespace blender::math;
+
if (positions.size() == 1) {
tangents.first() = float3(0.0f, 0.0f, 1.0f);
return;
@@ -232,8 +238,8 @@ static void calculate_tangents(Span<float3> positions,
tangents.last() = direction_bisect(second_to_last, last, first);
}
else {
- tangents.first() = (positions[1] - positions[0]).normalized();
- tangents.last() = (positions.last() - positions[positions.size() - 2]).normalized();
+ tangents.first() = normalize(positions[1] - positions[0]);
+ tangents.last() = normalize(positions.last() - positions[positions.size() - 2]);
}
}
@@ -264,18 +270,22 @@ static float3 rotate_direction_around_axis(const float3 &direction,
const float3 &axis,
const float angle)
{
+ using namespace blender::math;
+
BLI_ASSERT_UNIT_V3(direction);
BLI_ASSERT_UNIT_V3(axis);
- const float3 axis_scaled = axis * float3::dot(direction, axis);
+ const float3 axis_scaled = axis * dot(direction, axis);
const float3 diff = direction - axis_scaled;
- const float3 cross = float3::cross(axis, diff);
+ const float3 cross = blender::math::cross(axis, diff);
return axis_scaled + diff * std::cos(angle) + cross * std::sin(angle);
}
static void calculate_normals_z_up(Span<float3> tangents, MutableSpan<float3> r_normals)
{
+ using namespace blender::math;
+
BLI_assert(r_normals.size() == tangents.size());
/* Same as in `vec_to_quat`. */
@@ -286,7 +296,7 @@ static void calculate_normals_z_up(Span<float3> tangents, MutableSpan<float3> r_
r_normals[i] = {1.0f, 0.0f, 0.0f};
}
else {
- r_normals[i] = float3(tangent.y, -tangent.x, 0.0f).normalized();
+ r_normals[i] = normalize(float3(tangent.y, -tangent.x, 0.0f));
}
}
}
@@ -298,12 +308,14 @@ static float3 calculate_next_normal(const float3 &last_normal,
const float3 &last_tangent,
const float3 &current_tangent)
{
- if (last_tangent.is_zero() || current_tangent.is_zero()) {
+ using namespace blender::math;
+
+ if (is_zero(last_tangent) || is_zero(current_tangent)) {
return last_normal;
}
const float angle = angle_normalized_v3v3(last_tangent, current_tangent);
if (angle != 0.0) {
- const float3 axis = float3::cross(last_tangent, current_tangent).normalized();
+ const float3 axis = normalize(cross(last_tangent, current_tangent));
return rotate_direction_around_axis(last_normal, axis, angle);
}
return last_normal;
@@ -313,6 +325,7 @@ static void calculate_normals_minimum(Span<float3> tangents,
const bool cyclic,
MutableSpan<float3> r_normals)
{
+ using namespace blender::math;
BLI_assert(r_normals.size() == tangents.size());
if (r_normals.is_empty()) {
@@ -327,7 +340,7 @@ static void calculate_normals_minimum(Span<float3> tangents,
r_normals[0] = {1.0f, 0.0f, 0.0f};
}
else {
- r_normals[0] = float3(first_tangent.y, -first_tangent.x, 0.0f).normalized();
+ r_normals[0] = normalize(float3(first_tangent.y, -first_tangent.x, 0.0f));
}
/* Forward normal with minimum twist along the entire spline. */
@@ -417,7 +430,9 @@ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
const int next_index = (index == this->evaluated_points_size() - 1) ? 0 : index + 1;
const float previous_length = (index == 0) ? 0.0f : lengths[index - 1];
- const float factor = (length - previous_length) / (lengths[index] - previous_length);
+ const float length_in_segment = length - previous_length;
+ const float segment_length = lengths[index] - previous_length;
+ const float factor = segment_length == 0.0f ? 0.0f : length_in_segment / segment_length;
return LookupResult{index, next_index, factor};
}
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
index 9ce285cebb8..980437014b1 100644
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ b/source/blender/blenkernel/intern/spline_bezier.cc
@@ -70,24 +70,6 @@ void BezierSpline::set_resolution(const int value)
this->mark_cache_invalid();
}
-void BezierSpline::add_point(const float3 position,
- const HandleType handle_type_left,
- const float3 handle_position_left,
- const HandleType handle_type_right,
- const float3 handle_position_right,
- const float radius,
- const float tilt)
-{
- handle_types_left_.append(handle_type_left);
- handle_positions_left_.append(handle_position_left);
- positions_.append(position);
- handle_types_right_.append(handle_type_right);
- handle_positions_right_.append(handle_position_right);
- radii_.append(radius);
- tilts_.append(tilt);
- this->mark_cache_invalid();
-}
-
void BezierSpline::resize(const int size)
{
handle_types_left_.resize(size);
@@ -217,11 +199,13 @@ void BezierSpline::ensure_auto_handles() const
}
for (const int i : IndexRange(this->size())) {
+ using namespace blender;
+
if (ELEM(HandleType::Auto, handle_types_left_[i], handle_types_right_[i])) {
const float3 prev_diff = positions_[i] - previous_position(positions_, is_cyclic_, i);
const float3 next_diff = next_position(positions_, is_cyclic_, i) - positions_[i];
- float prev_len = prev_diff.length();
- float next_len = next_diff.length();
+ float prev_len = math::length(prev_diff);
+ float next_len = math::length(next_diff);
if (prev_len == 0.0f) {
prev_len = 1.0f;
}
@@ -231,7 +215,7 @@ void BezierSpline::ensure_auto_handles() const
const float3 dir = next_diff / next_len + prev_diff / prev_len;
/* This magic number is unfortunate, but comes from elsewhere in Blender. */
- const float len = dir.length() * 2.5614f;
+ const float len = math::length(dir) * 2.5614f;
if (len != 0.0f) {
if (handle_types_left_[i] == HandleType::Auto) {
const float prev_len_clamped = std::min(prev_len, next_len * 5.0f);
@@ -246,12 +230,12 @@ void BezierSpline::ensure_auto_handles() const
if (handle_types_left_[i] == HandleType::Vector) {
const float3 prev = previous_position(positions_, is_cyclic_, i);
- handle_positions_left_[i] = float3::interpolate(positions_[i], prev, 1.0f / 3.0f);
+ handle_positions_left_[i] = math::interpolate(positions_[i], prev, 1.0f / 3.0f);
}
if (handle_types_right_[i] == HandleType::Vector) {
const float3 next = next_position(positions_, is_cyclic_, i);
- handle_positions_right_[i] = float3::interpolate(positions_[i], next, 1.0f / 3.0f);
+ handle_positions_right_[i] = math::interpolate(positions_[i], next, 1.0f / 3.0f);
}
}
@@ -293,6 +277,8 @@ static void set_handle_position(const float3 &position,
float3 &handle,
float3 &handle_other)
{
+ using namespace blender::math;
+
/* Don't bother when the handle positions are calculated automatically anyway. */
if (ELEM(type, BezierSpline::HandleType::Auto, BezierSpline::HandleType::Vector)) {
return;
@@ -301,9 +287,9 @@ static void set_handle_position(const float3 &position,
handle = new_value;
if (type_other == BezierSpline::HandleType::Align) {
/* Keep track of the old length of the opposite handle. */
- const float length = float3::distance(handle_other, position);
+ const float length = distance(handle_other, position);
/* Set the other handle to directly opposite from the current handle. */
- const float3 dir = (handle - position).normalized();
+ const float3 dir = normalize(handle - position);
handle_other = position - dir * length;
}
}
@@ -371,6 +357,7 @@ int BezierSpline::evaluated_points_size() const
void BezierSpline::correct_end_tangents() const
{
+ using namespace blender::math;
if (is_cyclic_) {
return;
}
@@ -378,10 +365,10 @@ void BezierSpline::correct_end_tangents() const
MutableSpan<float3> tangents(evaluated_tangents_cache_);
if (handle_positions_right_.first() != positions_.first()) {
- tangents.first() = (handle_positions_right_.first() - positions_.first()).normalized();
+ tangents.first() = normalize(handle_positions_right_.first() - positions_.first());
}
if (handle_positions_left_.last() != positions_.last()) {
- tangents.last() = (positions_.last() - handle_positions_left_.last()).normalized();
+ tangents.last() = normalize(positions_.last() - handle_positions_left_.last());
}
}
@@ -389,20 +376,22 @@ BezierSpline::InsertResult BezierSpline::calculate_segment_insertion(const int i
const int next_index,
const float parameter)
{
+ using namespace blender::math;
+
BLI_assert(parameter <= 1.0f && parameter >= 0.0f);
BLI_assert(next_index == 0 || next_index == index + 1);
const float3 &point_prev = positions_[index];
const float3 &handle_prev = handle_positions_right_[index];
const float3 &handle_next = handle_positions_left_[next_index];
const float3 &point_next = positions_[next_index];
- const float3 center_point = float3::interpolate(handle_prev, handle_next, parameter);
+ const float3 center_point = interpolate(handle_prev, handle_next, parameter);
BezierSpline::InsertResult result;
- result.handle_prev = float3::interpolate(point_prev, handle_prev, parameter);
- result.handle_next = float3::interpolate(handle_next, point_next, parameter);
- result.left_handle = float3::interpolate(result.handle_prev, center_point, parameter);
- result.right_handle = float3::interpolate(center_point, result.handle_next, parameter);
- result.position = float3::interpolate(result.left_handle, result.right_handle, parameter);
+ result.handle_prev = interpolate(point_prev, handle_prev, parameter);
+ result.handle_next = interpolate(handle_next, point_next, parameter);
+ result.left_handle = interpolate(result.handle_prev, center_point, parameter);
+ result.right_handle = interpolate(center_point, result.handle_next, parameter);
+ result.position = interpolate(result.left_handle, result.right_handle, parameter);
return result;
}
diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc
index 69afb82baa8..5993b9a9a27 100644
--- a/source/blender/blenkernel/intern/spline_nurbs.cc
+++ b/source/blender/blenkernel/intern/spline_nurbs.cc
@@ -81,19 +81,6 @@ void NURBSpline::set_order(const uint8_t value)
this->mark_cache_invalid();
}
-void NURBSpline::add_point(const float3 position,
- const float radius,
- const float tilt,
- const float weight)
-{
- positions_.append(position);
- radii_.append(radius);
- tilts_.append(tilt);
- weights_.append(weight);
- knots_dirty_ = true;
- this->mark_cache_invalid();
-}
-
void NURBSpline::resize(const int size)
{
positions_.resize(size);
@@ -192,78 +179,48 @@ int NURBSpline::knots_size() const
void NURBSpline::calculate_knots() const
{
const KnotsMode mode = this->knots_mode;
- const int length = this->size();
const int order = order_;
+ const bool is_bezier = mode == NURBSpline::KnotsMode::Bezier;
+ const bool is_end_point = mode == NURBSpline::KnotsMode::EndPoint;
+ /* Inner knots are always repeated once except on Bezier case. */
+ const int repeat_inner = is_bezier ? order - 1 : 1;
+ /* How many times to repeat 0.0 at the beginning of knot. */
+ const int head = is_end_point && !is_cyclic_ ? order : (is_bezier ? order / 2 : 1);
+ /* Number of knots replicating widths of the starting knots.
+ * Covers both Cyclic and EndPoint cases. */
+ const int tail = is_cyclic_ ? 2 * order - 1 : (is_end_point ? order : 0);
knots_.resize(this->knots_size());
-
MutableSpan<float> knots = knots_;
- if (mode == NURBSpline::KnotsMode::Normal || is_cyclic_) {
- for (const int i : knots.index_range()) {
- knots[i] = static_cast<float>(i);
- }
- }
- else if (mode == NURBSpline::KnotsMode::EndPoint) {
- float k = 0.0f;
- for (const int i : IndexRange(1, knots.size())) {
- knots[i - 1] = k;
- if (i >= order && i <= length) {
- k += 1.0f;
- }
- }
- }
- else if (mode == NURBSpline::KnotsMode::Bezier) {
- BLI_assert(ELEM(order, 3, 4));
- if (order == 3) {
- float k = 0.6f;
- for (const int i : knots.index_range()) {
- if (i >= order && i <= length) {
- k += 0.5f;
- }
- knots[i] = std::floor(k);
- }
- }
- else {
- float k = 0.34f;
- for (const int i : knots.index_range()) {
- knots[i] = std::floor(k);
- k += 1.0f / 3.0f;
- }
- }
- }
+ int r = head;
+ float current = 0.0f;
- if (is_cyclic_) {
- const int b = length + order - 1;
- if (order > 2) {
- for (const int i : IndexRange(1, order - 2)) {
- if (knots[b] != knots[b - i]) {
- if (i == order - 1) {
- knots[length + order - 2] += 1.0f;
- break;
- }
- }
- }
+ for (const int i : IndexRange(knots.size() - tail)) {
+ knots[i] = current;
+ r--;
+ if (r == 0) {
+ current += 1.0;
+ r = repeat_inner;
}
+ }
- int c = order;
- for (int i = b; i < this->knots_size(); i++) {
- knots[i] = knots[i - 1] + (knots[c] - knots[c - 1]);
- c--;
- }
+ const int tail_index = knots.size() - tail;
+ for (const int i : IndexRange(tail)) {
+ knots[tail_index + i] = current + (knots[i] - knots[0]);
}
}
Span<float> NURBSpline::knots() const
{
if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->size() + order_);
+ BLI_assert(knots_.size() == this->knots_size());
return knots_;
}
std::lock_guard lock{knots_mutex_};
if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->size() + order_);
+ BLI_assert(knots_.size() == this->knots_size());
return knots_;
}
diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc
index 4af68b5f270..480bbd1dfe8 100644
--- a/source/blender/blenkernel/intern/spline_poly.cc
+++ b/source/blender/blenkernel/intern/spline_poly.cc
@@ -45,14 +45,6 @@ int PolySpline::size() const
return size;
}
-void PolySpline::add_point(const float3 position, const float radius, const float tilt)
-{
- positions_.append(position);
- radii_.append(radius);
- tilts_.append(tilt);
- this->mark_cache_invalid();
-}
-
void PolySpline::resize(const int size)
{
positions_.resize(size);
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index fd32f52351a..45810e29565 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -29,6 +29,9 @@
#include "BLI_utildefines.h"
+#include "BKE_modifier.h"
+#include "BKE_subdiv_modifier.h"
+
#include "MEM_guardedalloc.h"
#include "subdiv_converter.h"
@@ -189,6 +192,12 @@ Subdiv *BKE_subdiv_update_from_mesh(Subdiv *subdiv,
void BKE_subdiv_free(Subdiv *subdiv)
{
if (subdiv->evaluator != NULL) {
+ const eOpenSubdivEvaluator evaluator_type = subdiv->evaluator->type;
+ if (evaluator_type != OPENSUBDIV_EVALUATOR_CPU) {
+ /* Let the draw code do the freeing, to ensure that the OpenGL context is valid. */
+ BKE_subsurf_modifier_free_gpu_cache_cb(subdiv);
+ return;
+ }
openSubdiv_deleteEvaluator(subdiv->evaluator);
}
if (subdiv->topology_refiner != NULL) {
@@ -214,12 +223,13 @@ int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
}
const int num_coarse_faces = topology_refiner->getNumFaces(topology_refiner);
subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN(
- num_coarse_faces, sizeof(int), "subdiv face_ptex_offset");
+ num_coarse_faces + 1, sizeof(int), "subdiv face_ptex_offset");
int ptex_offset = 0;
for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
const int num_ptex_faces = topology_refiner->getNumFacePtexFaces(topology_refiner, face_index);
subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
ptex_offset += num_ptex_faces;
}
+ subdiv->cache_.face_ptex_offset[num_coarse_faces] = ptex_offset;
return subdiv->cache_.face_ptex_offset;
}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index 77962ec924c..7d876acf776 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -603,7 +603,8 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv,
{
/* Make sure evaluator is ready. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, coarse_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
if (coarse_mesh->totpoly) {
return NULL;
}
diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
index 41fc28c5d52..fc7ef887879 100644
--- a/source/blender/blenkernel/intern/subdiv_converter_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
@@ -40,6 +40,8 @@
#include "opensubdiv_capi.h"
#include "opensubdiv_converter_capi.h"
+#include "bmesh_class.h"
+
/* Enable work-around for non-working CPU evaluator when using bilinear scheme.
* This forces Catmark scheme with all edges marked as infinitely sharp. */
#define BUGGY_SIMPLE_SCHEME_WORKAROUND 1
@@ -47,6 +49,8 @@
typedef struct ConverterStorage {
SubdivSettings settings;
const Mesh *mesh;
+ /* CustomData layer for vertex sharpnesses. */
+ const float *cd_vertex_crease;
/* Indexed by loop index, value denotes index of face-varying vertex
* which corresponds to the UV coordinate.
*/
@@ -168,7 +172,7 @@ static float get_edge_sharpness(const OpenSubdiv_Converter *converter, int manif
}
const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
const MEdge *medge = storage->mesh->medge;
- return BKE_subdiv_edge_crease_to_sharpness_char(medge[edge_index].crease);
+ return BKE_subdiv_crease_to_sharpness_char(medge[edge_index].crease);
}
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
@@ -184,14 +188,14 @@ static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
return BLI_BITMAP_TEST_BOOL(storage->infinite_sharp_vertices_map, vertex_index);
}
-static float get_vertex_sharpness(const OpenSubdiv_Converter *converter,
- int UNUSED(manifold_vertex_index))
+static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, int manifold_vertex_index)
{
ConverterStorage *storage = converter->user_data;
- if (!storage->settings.use_creases) {
+ if (!storage->settings.use_creases || storage->cd_vertex_crease == NULL) {
return 0.0f;
}
- return 0.0f;
+ const int vertex_index = storage->manifold_vertex_index_reverse[manifold_vertex_index];
+ return BKE_subdiv_crease_to_sharpness_f(storage->cd_vertex_crease[vertex_index]);
}
static int get_num_uv_layers(const OpenSubdiv_Converter *converter)
@@ -393,6 +397,7 @@ static void init_user_data(OpenSubdiv_Converter *converter,
ConverterStorage *user_data = MEM_mallocN(sizeof(ConverterStorage), __func__);
user_data->settings = *settings;
user_data->mesh = mesh;
+ user_data->cd_vertex_crease = CustomData_get_layer(&mesh->vdata, CD_CREASE);
user_data->loop_uv_indices = NULL;
initialize_manifold_indices(user_data);
converter->user_data = user_data;
diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c
index 7a2d639e4e5..c385b1b291d 100644
--- a/source/blender/blenkernel/intern/subdiv_deform.c
+++ b/source/blender/blenkernel/intern/subdiv_deform.c
@@ -117,7 +117,8 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
const int UNUSED(num_vertices),
const int UNUSED(num_edges),
const int UNUSED(num_loops),
- const int UNUSED(num_polygons))
+ const int UNUSED(num_polygons),
+ const int *UNUSED(subdiv_polygon_offset))
{
SubdivDeformContext *subdiv_context = foreach_context->user_data;
subdiv_mesh_prepare_accumulator(subdiv_context, subdiv_context->coarse_mesh->totvert);
@@ -202,7 +203,8 @@ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* is refined for the new positions of coarse vertices. */
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, vertex_cos)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, coarse_mesh, vertex_cos, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 0001eb8a205..c2f7581637b 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -28,6 +28,7 @@
#include "BLI_bitmap.h"
#include "BLI_math_vector.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
@@ -38,7 +39,28 @@
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
-bool BKE_subdiv_eval_begin(Subdiv *subdiv)
+/* ============================ Helper Function ============================ */
+
+static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type(
+ eSubdivEvaluatorType evaluator_type)
+{
+ switch (evaluator_type) {
+ case SUBDIV_EVALUATOR_TYPE_CPU: {
+ return OPENSUBDIV_EVALUATOR_CPU;
+ }
+ case SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE: {
+ return OPENSUBDIV_EVALUATOR_GLSL_COMPUTE;
+ }
+ }
+ BLI_assert_msg(0, "Unknown evaluator type");
+ return OPENSUBDIV_EVALUATOR_CPU;
+}
+
+/* ====================== Main Subdivision Evaluation ====================== */
+
+bool BKE_subdiv_eval_begin(Subdiv *subdiv,
+ eSubdivEvaluatorType evaluator_type,
+ OpenSubdiv_EvaluatorCache *evaluator_cache)
{
BKE_subdiv_stats_reset(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
if (subdiv->topology_refiner == NULL) {
@@ -47,8 +69,11 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv)
return false;
}
if (subdiv->evaluator == NULL) {
+ eOpenSubdivEvaluator opensubdiv_evaluator_type =
+ opensubdiv_evalutor_from_subdiv_evaluator_type(evaluator_type);
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
- subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(subdiv->topology_refiner);
+ subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(
+ subdiv->topology_refiner, opensubdiv_evaluator_type, evaluator_cache);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
if (subdiv->evaluator == NULL) {
return false;
@@ -80,6 +105,9 @@ static void set_coarse_positions(Subdiv *subdiv,
BLI_BITMAP_ENABLE(vertex_used_map, loop->v);
}
}
+ /* Use a temporary buffer so we do not upload vertices one at a time to the GPU. */
+ float(*buffer)[3] = MEM_mallocN(sizeof(float[3]) * mesh->totvert, "subdiv tmp coarse positions");
+ int manifold_vertex_count = 0;
for (int vertex_index = 0, manifold_vertex_index = 0; vertex_index < mesh->totvert;
vertex_index++) {
if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) {
@@ -93,13 +121,49 @@ static void set_coarse_positions(Subdiv *subdiv,
const MVert *vertex = &mvert[vertex_index];
vertex_co = vertex->co;
}
- subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex_co, manifold_vertex_index, 1);
+ copy_v3_v3(&buffer[manifold_vertex_index][0], vertex_co);
manifold_vertex_index++;
+ manifold_vertex_count++;
}
+ subdiv->evaluator->setCoarsePositions(
+ subdiv->evaluator, &buffer[0][0], 0, manifold_vertex_count);
MEM_freeN(vertex_used_map);
+ MEM_freeN(buffer);
+}
+
+/* Context which is used to fill face varying data in parallel. */
+typedef struct FaceVaryingDataFromUVContext {
+ OpenSubdiv_TopologyRefiner *topology_refiner;
+ const Mesh *mesh;
+ const MLoopUV *mloopuv;
+ float (*buffer)[2];
+ int layer_index;
+} FaceVaryingDataFromUVContext;
+
+static void set_face_varying_data_from_uv_task(void *__restrict userdata,
+ const int face_index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ FaceVaryingDataFromUVContext *ctx = userdata;
+ OpenSubdiv_TopologyRefiner *topology_refiner = ctx->topology_refiner;
+ const int layer_index = ctx->layer_index;
+ const Mesh *mesh = ctx->mesh;
+ const MPoly *mpoly = &mesh->mpoly[face_index];
+ const MLoopUV *mluv = &ctx->mloopuv[mpoly->loopstart];
+
+ /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
+ * loops of a face, need to watch for that, to prevent wrong UVs assigned.
+ */
+ const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, face_index);
+ const int *uv_indices = topology_refiner->getFaceFVarValueIndices(
+ topology_refiner, face_index, layer_index);
+ for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) {
+ copy_v2_v2(ctx->buffer[uv_indices[vertex_index]], mluv->uv);
+ }
}
static void set_face_varying_data_from_uv(Subdiv *subdiv,
+ const Mesh *mesh,
const MLoopUV *mloopuv,
const int layer_index)
{
@@ -107,25 +171,37 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
const int num_faces = topology_refiner->getNumFaces(topology_refiner);
const MLoopUV *mluv = mloopuv;
- /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
- * loops of a face, need to watch for that, to prevent wrong UVs assigned.
- */
- for (int face_index = 0; face_index < num_faces; face_index++) {
- const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner,
- face_index);
- const int *uv_indices = topology_refiner->getFaceFVarValueIndices(
- topology_refiner, face_index, layer_index);
- for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) {
- evaluator->setFaceVaryingData(evaluator, layer_index, mluv->uv, uv_indices[vertex_index], 1);
- }
- }
+
+ const int num_fvar_values = topology_refiner->getNumFVarValues(topology_refiner, layer_index);
+ /* Use a temporary buffer so we do not upload UVs one at a time to the GPU. */
+ float(*buffer)[2] = MEM_mallocN(sizeof(float[2]) * num_fvar_values, "temp UV storage");
+
+ FaceVaryingDataFromUVContext ctx;
+ ctx.topology_refiner = topology_refiner;
+ ctx.layer_index = layer_index;
+ ctx.mloopuv = mluv;
+ ctx.mesh = mesh;
+ ctx.buffer = buffer;
+
+ TaskParallelSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ parallel_range_settings.min_iter_per_thread = 1;
+
+ BLI_task_parallel_range(
+ 0, num_faces, &ctx, set_face_varying_data_from_uv_task, &parallel_range_settings);
+
+ evaluator->setFaceVaryingData(evaluator, layer_index, &buffer[0][0], 0, num_fvar_values);
+
+ MEM_freeN(buffer);
}
bool BKE_subdiv_eval_begin_from_mesh(Subdiv *subdiv,
const Mesh *mesh,
- const float (*coarse_vertex_cos)[3])
+ const float (*coarse_vertex_cos)[3],
+ eSubdivEvaluatorType evaluator_type,
+ OpenSubdiv_EvaluatorCache *evaluator_cache)
{
- if (!BKE_subdiv_eval_begin(subdiv)) {
+ if (!BKE_subdiv_eval_begin(subdiv, evaluator_type, evaluator_cache)) {
return false;
}
return BKE_subdiv_eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos);
@@ -146,7 +222,7 @@ bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv,
const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
const MLoopUV *mloopuv = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPUV, layer_index);
- set_face_varying_data_from_uv(subdiv, mloopuv, layer_index);
+ set_face_varying_data_from_uv(subdiv, mesh, mloopuv, layer_index);
}
/* Update evaluator to the new coarse geometry. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
@@ -188,8 +264,8 @@ void BKE_subdiv_eval_limit_point_and_derivatives(Subdiv *subdiv,
* This happens, for example, in single vertex on Suzannne's nose (where two quads have 2 common
* edges).
*
- * This makes tangent space displacement (such as multires) impossible to be used in those
- * vertices, so those needs to be addressed in one way or another.
+ * This makes tangent space displacement (such as multi-resolution) impossible to be used in
+ * those vertices, so those needs to be addressed in one way or another.
*
* Simplest thing to do: step inside of the face a little bit, where there is known patch at
* which there must be proper derivatives. This might break continuity of normals, but is better
@@ -221,18 +297,6 @@ void BKE_subdiv_eval_limit_point_and_normal(Subdiv *subdiv,
normalize_v3(r_N);
}
-void BKE_subdiv_eval_limit_point_and_short_normal(Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
- float r_P[3],
- short r_N[3])
-{
- float N_float[3];
- BKE_subdiv_eval_limit_point_and_normal(subdiv, ptex_face_index, u, v, r_P, N_float);
- normal_float_to_short_v3(r_N, N_float);
-}
-
void BKE_subdiv_eval_face_varying(Subdiv *subdiv,
const int face_varying_channel,
const int ptex_face_index,
@@ -273,125 +337,3 @@ void BKE_subdiv_eval_final_point(
BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_P);
}
}
-
-/* =================== Patch queries at given resolution =================== */
-
-/* Move buffer forward by a given number of bytes. */
-static void buffer_apply_offset(void **buffer, const int offset)
-{
- *buffer = ((unsigned char *)*buffer) + offset;
-}
-
-/* Write given number of floats to the beginning of given buffer. */
-static void buffer_write_float_value(void **buffer, const float *values_buffer, int num_values)
-{
- memcpy(*buffer, values_buffer, sizeof(float) * num_values);
-}
-
-/* Similar to above, just operates with short values. */
-static void buffer_write_short_value(void **buffer, const short *values_buffer, int num_values)
-{
- memcpy(*buffer, values_buffer, sizeof(short) * num_values);
-}
-
-void BKE_subdiv_eval_limit_patch_resolution_point(Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *buffer,
- const int offset,
- const int stride)
-{
- buffer_apply_offset(&buffer, offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, buffer);
- buffer_apply_offset(&buffer, stride);
- }
- }
-}
-
-void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *du_buffer,
- const int du_offset,
- const int du_stride,
- void *dv_buffer,
- const int dv_offset,
- const int dv_stride)
-{
- buffer_apply_offset(&point_buffer, point_offset);
- buffer_apply_offset(&du_buffer, du_offset);
- buffer_apply_offset(&dv_buffer, dv_offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- BKE_subdiv_eval_limit_point_and_derivatives(
- subdiv, ptex_face_index, u, v, point_buffer, du_buffer, dv_buffer);
- buffer_apply_offset(&point_buffer, point_stride);
- buffer_apply_offset(&du_buffer, du_stride);
- buffer_apply_offset(&dv_buffer, dv_stride);
- }
- }
-}
-
-void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *normal_buffer,
- const int normal_offset,
- const int normal_stride)
-{
- buffer_apply_offset(&point_buffer, point_offset);
- buffer_apply_offset(&normal_buffer, normal_offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- float normal[3];
- BKE_subdiv_eval_limit_point_and_normal(subdiv, ptex_face_index, u, v, point_buffer, normal);
- buffer_write_float_value(&normal_buffer, normal, 3);
- buffer_apply_offset(&point_buffer, point_stride);
- buffer_apply_offset(&normal_buffer, normal_stride);
- }
- }
-}
-
-void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *normal_buffer,
- const int normal_offset,
- const int normal_stride)
-{
- buffer_apply_offset(&point_buffer, point_offset);
- buffer_apply_offset(&normal_buffer, normal_offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- short normal[3];
- BKE_subdiv_eval_limit_point_and_short_normal(
- subdiv, ptex_face_index, u, v, point_buffer, normal);
- buffer_write_short_value(&normal_buffer, normal, 3);
- buffer_apply_offset(&point_buffer, point_stride);
- buffer_apply_offset(&normal_buffer, normal_stride);
- }
- }
-}
diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c
index 061c196df2a..69bead27fe6 100644
--- a/source/blender/blenkernel/intern/subdiv_foreach.c
+++ b/source/blender/blenkernel/intern/subdiv_foreach.c
@@ -1877,7 +1877,8 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
ctx.num_subdiv_vertices,
ctx.num_subdiv_edges,
ctx.num_subdiv_loops,
- ctx.num_subdiv_polygons)) {
+ ctx.num_subdiv_polygons,
+ ctx.subdiv_polygon_offset)) {
subdiv_foreach_ctx_free(&ctx);
return false;
}
diff --git a/source/blender/blenkernel/intern/subdiv_inline.h b/source/blender/blenkernel/intern/subdiv_inline.h
index ba45d0a4997..d52adff1e61 100644
--- a/source/blender/blenkernel/intern/subdiv_inline.h
+++ b/source/blender/blenkernel/intern/subdiv_inline.h
@@ -103,13 +103,13 @@ BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
}
}
-BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_f(float edge_crease)
+BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease)
{
return edge_crease * edge_crease * 10.0f;
}
-BLI_INLINE float BKE_subdiv_edge_crease_to_sharpness_char(char edge_crease)
+BLI_INLINE float BKE_subdiv_crease_to_sharpness_char(char edge_crease)
{
const float edge_crease_f = edge_crease / 255.0f;
- return BKE_subdiv_edge_crease_to_sharpness_f(edge_crease_f);
+ return BKE_subdiv_crease_to_sharpness_f(edge_crease_f);
}
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index e5c7d13edab..c334d9a2c33 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -21,6 +21,7 @@
* \ingroup bke
*/
+#include "BKE_mesh.h"
#include "BKE_subdiv_mesh.h"
#include "atomic_ops.h"
@@ -58,23 +59,8 @@ typedef struct SubdivMeshContext {
/* UV layers interpolation. */
int num_uv_layers;
MLoopUV *uv_layers[MAX_MTFACE];
- /* Accumulated values.
- *
- * Averaging is happening for vertices along the coarse edges and corners.
- * This is needed for both displacement and normals.
- *
- * Displacement is being accumulated to a vertices coordinates, since those
- * are not needed during traversal of edge/corner vertices.
- *
- * For normals we are using dedicated array, since we can not use same
- * vertices (normals are `short`, which will cause a lot of precision
- * issues). */
- float (*accumulated_normals)[3];
/* Per-subdivided vertex counter of averaged values. */
int *accumulated_counters;
- /* Denotes whether normals can be evaluated from a limit surface. One case
- * when it's not possible is when displacement is used. */
- bool can_evaluate_normals;
bool have_displacement;
} SubdivMeshContext;
@@ -102,20 +88,12 @@ static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx)
static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vertices)
{
- if (!ctx->can_evaluate_normals && !ctx->have_displacement) {
- return;
- }
- /* TODO(sergey): Technically, this is overallocating, we don't need memory
- * for an inner subdivision vertices. */
- ctx->accumulated_normals = MEM_calloc_arrayN(
- num_vertices, sizeof(*ctx->accumulated_normals), "subdiv accumulated normals");
ctx->accumulated_counters = MEM_calloc_arrayN(
num_vertices, sizeof(*ctx->accumulated_counters), "subdiv accumulated counters");
}
static void subdiv_mesh_context_free(SubdivMeshContext *ctx)
{
- MEM_SAFE_FREE(ctx->accumulated_normals);
MEM_SAFE_FREE(ctx->accumulated_counters);
}
@@ -450,48 +428,23 @@ static void subdiv_mesh_tls_free(void *tls_v)
/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Evaluation helper functions
- * \{ */
-
-static void eval_final_point_and_vertex_normal(Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
- float r_P[3],
- short r_N[3])
-{
- if (subdiv->displacement_evaluator == NULL) {
- BKE_subdiv_eval_limit_point_and_short_normal(subdiv, ptex_face_index, u, v, r_P, r_N);
- }
- else {
- BKE_subdiv_eval_final_point(subdiv, ptex_face_index, u, v, r_P);
- }
-}
-
/** \} */
/* -------------------------------------------------------------------- */
/** \name Accumulation helpers
* \{ */
-static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *ctx,
- const int ptex_face_index,
- const float u,
- const float v,
- MVert *subdiv_vert)
+static void subdiv_accumulate_vertex_displacement(SubdivMeshContext *ctx,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ MVert *subdiv_vert)
{
Subdiv *subdiv = ctx->subdiv;
const int subdiv_vertex_index = subdiv_vert - ctx->subdiv_mesh->mvert;
float dummy_P[3], dPdu[3], dPdv[3], D[3];
BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
- /* Accumulate normal. */
- if (ctx->can_evaluate_normals) {
- float N[3];
- cross_v3_v3v3(N, dPdu, dPdv);
- normalize_v3(N);
- add_v3_v3(ctx->accumulated_normals[subdiv_vertex_index], N);
- }
+
/* Accumulate displacement if needed. */
if (ctx->have_displacement) {
/* NOTE: The subdivided mesh is allocated in this module, and its vertices are kept at zero
@@ -514,9 +467,10 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
const int num_vertices,
const int num_edges,
const int num_loops,
- const int num_polygons)
+ const int num_polygons,
+ const int *UNUSED(subdiv_polygon_offset))
{
- /* Multires grid data will be applied or become invalid after subdivision,
+ /* Multi-resolution grid data will be applied or become invalid after subdivision,
* so don't try to preserve it and use memory. */
CustomData_MeshMasks mask = CD_MASK_EVERYTHING;
mask.lmask &= ~CD_MASK_MULTIRES_GRIDS;
@@ -588,13 +542,6 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext
BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co);
/* Apply displacement. */
add_v3_v3(subdiv_vert->co, D);
- /* Copy normal from accumulated storage. */
- if (ctx->can_evaluate_normals) {
- float N[3];
- copy_v3_v3(N, ctx->accumulated_normals[subdiv_vertex_index]);
- normalize_v3(N);
- normal_float_to_short_v3(subdiv_vert->no, N);
- }
/* Remove facedot flag. This can happen if there is more than one subsurf modifier. */
subdiv_vert->flag &= ~ME_VERT_FACEDOT;
}
@@ -621,15 +568,6 @@ static void evaluate_vertex_and_apply_displacement_interpolate(
BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co);
/* Apply displacement. */
add_v3_v3(subdiv_vert->co, D);
- /* Copy normal from accumulated storage. */
- if (ctx->can_evaluate_normals) {
- const float inv_num_accumulated = 1.0f / ctx->accumulated_counters[subdiv_vertex_index];
- float N[3];
- copy_v3_v3(N, ctx->accumulated_normals[subdiv_vertex_index]);
- mul_v3_fl(N, inv_num_accumulated);
- normalize_v3(N);
- normal_float_to_short_v3(subdiv_vert->no, N);
- }
}
static void subdiv_mesh_vertex_every_corner_or_edge(const SubdivForeachContext *foreach_context,
@@ -643,7 +581,7 @@ static void subdiv_mesh_vertex_every_corner_or_edge(const SubdivForeachContext *
Mesh *subdiv_mesh = ctx->subdiv_mesh;
MVert *subdiv_mvert = subdiv_mesh->mvert;
MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
- subdiv_accumulate_vertex_normal_and_displacement(ctx, ptex_face_index, u, v, subdiv_vert);
+ subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, subdiv_vert);
}
static void subdiv_mesh_vertex_every_corner(const SubdivForeachContext *foreach_context,
@@ -792,8 +730,7 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context
MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
subdiv_mesh_ensure_vertex_interpolation(ctx, tls, coarse_poly, coarse_corner);
subdiv_vertex_data_interpolate(ctx, subdiv_vert, &tls->vertex_interpolation, u, v);
- eval_final_point_and_vertex_normal(
- subdiv, ptex_face_index, u, v, subdiv_vert->co, subdiv_vert->no);
+ BKE_subdiv_eval_final_point(subdiv, ptex_face_index, u, v, subdiv_vert->co);
subdiv_mesh_tag_center_vertex(coarse_poly, subdiv_vert, u, v);
}
@@ -1117,7 +1054,7 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *
find_edge_neighbors(ctx, coarse_edge, neighbors);
/* Interpolate custom data when not an end point.
* This data has already been copied from the original vertex by #subdiv_mesh_vertex_loose. */
- if (u != 0.0 && u != 1.0) {
+ if (!ELEM(u, 0.0, 1.0)) {
subdiv_mesh_vertex_of_loose_edge_interpolate(ctx, coarse_edge, u, subdiv_vertex_index);
}
/* Interpolate coordinate. */
@@ -1140,12 +1077,6 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *
/* TODO(sergey): This matches old behavior, but we can as well interpolate
* it. Maybe even using vertex varying attributes. */
subdiv_vertex->bweight = 0.0f;
- /* Reset normal, initialize it in a similar way as edit mode does for a
- * vertices adjacent to a loose edges.
- * See `mesh_evaluate#mesh_calc_normals_vert_fallback` */
- float no[3];
- normalize_v3_v3(no, subdiv_vertex->co);
- normal_float_to_short_v3(subdiv_vertex->no, no);
}
/** \} */
@@ -1160,8 +1091,8 @@ static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
memset(foreach_context, 0, sizeof(*foreach_context));
/* General information. */
foreach_context->topology_info = subdiv_mesh_topology_info;
- /* Every boundary geometry. Used for displacement and normals averaging. */
- if (subdiv_context->can_evaluate_normals || subdiv_context->have_displacement) {
+ /* Every boundary geometry. Used for displacement averaging. */
+ if (subdiv_context->have_displacement) {
foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner;
foreach_context->vertex_every_edge = subdiv_mesh_vertex_every_edge;
}
@@ -1193,7 +1124,8 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* it is refined for the new positions of coarse vertices. */
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, coarse_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
@@ -1210,8 +1142,6 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
subdiv_context.coarse_mesh = coarse_mesh;
subdiv_context.subdiv = subdiv;
subdiv_context.have_displacement = (subdiv->displacement_evaluator != NULL);
- subdiv_context.can_evaluate_normals = !subdiv_context.have_displacement &&
- subdiv_context.subdiv->settings.is_adaptive;
/* Multi-threaded traversal/evaluation. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
SubdivForeachContext foreach_context;
@@ -1225,9 +1155,11 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
Mesh *result = subdiv_context.subdiv_mesh;
// BKE_mesh_validate(result, true, true);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
- if (!subdiv_context.can_evaluate_normals) {
- BKE_mesh_normals_tag_dirty(result);
- }
+ /* Using normals from the limit surface gives different results than Blender's vertex normal
+ * calculation. Since vertex normals are supposed to be a consistent cache, don't bother
+ * calculating them here. The work may have been pointless anyway if the mesh is deformed or
+ * changed afterwards. */
+ BKE_mesh_normals_tag_dirty(result);
/* Free used memory. */
subdiv_mesh_context_free(&subdiv_context);
return result;
diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c
new file mode 100644
index 00000000000..525c4837bc4
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_modifier.c
@@ -0,0 +1,160 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "BKE_subdiv_modifier.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_modifier.h"
+#include "BKE_subdiv.h"
+
+#include "GPU_capabilities.h"
+#include "GPU_context.h"
+
+#include "opensubdiv_capi.h"
+
+void BKE_subsurf_modifier_subdiv_settings_init(SubdivSettings *settings,
+ const SubsurfModifierData *smd,
+ const bool use_render_params)
+{
+ const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels;
+
+ settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
+ settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
+ settings->level = settings->is_simple ?
+ 1 :
+ (settings->is_adaptive ? smd->quality : requested_levels);
+ settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
+ settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
+ smd->boundary_smooth);
+ settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
+ smd->uv_smooth);
+}
+
+static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene,
+ const Object *ob,
+ int required_mode)
+{
+ ModifierData *md = ob->modifiers.last;
+
+ while (md) {
+ if (BKE_modifier_is_enabled(scene, md, required_mode)) {
+ break;
+ }
+
+ md = md->prev;
+ }
+
+ return md;
+}
+
+bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const Scene *scene,
+ const Object *ob,
+ const SubsurfModifierData *smd,
+ int required_mode,
+ bool skip_check_is_last)
+{
+ if ((U.gpu_flag & USER_GPU_FLAG_SUBDIVISION_EVALUATION) == 0) {
+ return false;
+ }
+
+ if (!skip_check_is_last) {
+ ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode);
+ if (md != (const ModifierData *)smd) {
+ return false;
+ }
+ }
+
+ /* Only OpenGL is supported for OpenSubdiv evaluation for now. */
+ if (GPU_backend_get_type() != GPU_BACKEND_OPENGL) {
+ return false;
+ }
+
+ if (!(GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support())) {
+ return false;
+ }
+
+ const int available_evaluators = openSubdiv_getAvailableEvaluators();
+ if ((available_evaluators & OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
+ const Object *ob,
+ int required_mode)
+{
+ ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode);
+
+ if (!md) {
+ return false;
+ }
+
+ if (md->type != eModifierType_Subsurf) {
+ return false;
+ }
+
+ return BKE_subsurf_modifier_can_do_gpu_subdiv_ex(
+ scene, ob, (SubsurfModifierData *)md, required_mode, true);
+}
+
+void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv) = NULL;
+
+Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(const SubsurfModifierData *smd,
+ const SubdivSettings *subdiv_settings,
+ const Mesh *mesh,
+ const bool for_draw_code)
+{
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (runtime_data->subdiv && runtime_data->set_by_draw_code != for_draw_code) {
+ BKE_subdiv_free(runtime_data->subdiv);
+ runtime_data->subdiv = NULL;
+ }
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh);
+ runtime_data->subdiv = subdiv;
+ runtime_data->set_by_draw_code = for_draw_code;
+ return subdiv;
+}
+
+SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(SubsurfModifierData *smd)
+{
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (runtime_data == NULL) {
+ runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
+ smd->modifier.runtime = runtime_data;
+ }
+ return runtime_data;
+}
+
+int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode)
+{
+ if (is_final_render) {
+ return eModifierMode_Render;
+ }
+
+ return eModifierMode_Realtime | (is_edit_mode ? eModifierMode_Editmode : 0);
+}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 2669da98488..9d66c354b54 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -803,17 +803,11 @@ static int ccgDM_getNumLoops(DerivedMesh *dm)
return 4 * ccgSubSurf_getNumFinalFaces(ccgdm->ss);
}
-static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
+static CCGElem *get_vertex_elem(CCGDerivedMesh *ccgdm, int vertNum)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
CCGSubSurf *ss = ccgdm->ss;
- CCGElem *vd;
- CCGKey key;
int i;
- CCG_key_top_level(&key, ss);
- memset(mv, 0, sizeof(*mv));
-
if ((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
/* this vert comes from face data */
int lastface = ccgSubSurf_getNumFaces(ss) - 1;
@@ -842,30 +836,24 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
offset = vertNum - ccgdm->faceMap[i].startVert;
if (offset < 1) {
- vd = ccgSubSurf_getFaceCenterData(f);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getFaceCenterData(f);
}
- else if (offset < gridSideEnd) {
+ if (offset < gridSideEnd) {
offset -= 1;
grid = offset / gridSideVerts;
x = offset % gridSideVerts + 1;
- vd = ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x);
}
- else if (offset < gridInternalEnd) {
+ if (offset < gridInternalEnd) {
offset -= gridSideEnd;
grid = offset / gridInternalVerts;
offset %= gridInternalVerts;
y = offset / gridSideVerts + 1;
x = offset % gridSideVerts + 1;
- vd = ccgSubSurf_getFaceGridData(ss, f, grid, x, y);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getFaceGridData(ss, f, grid, x, y);
}
}
- else if ((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
+ if ((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
/* this vert comes from edge data */
CCGEdge *e;
int lastedge = ccgSubSurf_getNumEdges(ss) - 1;
@@ -879,36 +867,37 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
e = ccgdm->edgeMap[i].edge;
x = vertNum - ccgdm->edgeMap[i].startVert + 1;
- vd = ccgSubSurf_getEdgeData(ss, e, x);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getEdgeData(ss, e, x);
}
- else {
- /* this vert comes from vert data */
- CCGVert *v;
- i = vertNum - ccgdm->vertMap[0].startVert;
- v = ccgdm->vertMap[i].vert;
- vd = ccgSubSurf_getVertData(ss, v);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
- }
+ /* this vert comes from vert data */
+ CCGVert *v;
+ i = vertNum - ccgdm->vertMap[0].startVert;
+
+ v = ccgdm->vertMap[i].vert;
+ return ccgSubSurf_getVertData(ss, v);
}
static void ccgDM_getFinalVertCo(DerivedMesh *dm, int vertNum, float r_co[3])
{
- MVert mvert;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
- ccgDM_getFinalVert(dm, vertNum, &mvert);
- copy_v3_v3(r_co, mvert.co);
+ CCGElem *vd = get_vertex_elem(ccgdm, vertNum);
+ CCGKey key;
+ CCG_key_top_level(&key, ss);
+ copy_v3_v3(r_co, CCG_elem_co(&key, vd));
}
static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float r_no[3])
{
- MVert mvert;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
- ccgDM_getFinalVert(dm, vertNum, &mvert);
- normal_short_to_float_v3(r_no, mvert.no);
+ CCGElem *vd = get_vertex_elem(ccgdm, vertNum);
+ CCGKey key;
+ CCG_key_top_level(&key, ss);
+ copy_v3_v3(r_no, CCG_elem_no(&key, vd));
}
void subsurf_copy_grid_hidden(DerivedMesh *dm,
@@ -995,7 +984,6 @@ void subsurf_copy_grid_paint_mask(DerivedMesh *dm,
BLI_INLINE void ccgDM_to_MVert(MVert *mv, const CCGKey *key, CCGElem *elem)
{
copy_v3_v3(mv->co, CCG_elem_co(key, elem));
- normal_float_to_short_v3(mv->no, CCG_elem_no(key, elem));
mv->flag = mv->bweight = 0;
}
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index ee9247e6e60..37d5d732a70 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -67,6 +67,8 @@
#include "BKE_scene.h"
#include "BKE_texture.h"
+#include "NOD_texture.h"
+
#include "RE_texture.h"
#include "BLO_read_write.h"
diff --git a/source/blender/blenkernel/intern/tracking_region_tracker.c b/source/blender/blenkernel/intern/tracking_region_tracker.c
index ad3f226fa92..4b23f74bc8f 100644
--- a/source/blender/blenkernel/intern/tracking_region_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_region_tracker.c
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_movieclip_types.h"
#include "BLI_threads.h"
@@ -42,7 +43,7 @@
/* **** utility functions for tracking **** */
-/* convert from float and byte RGBA to grayscale. Supports different coefficients for RGB. */
+/** Convert from float and byte RGBA to gray-scale. Supports different coefficients for RGB. */
static void float_rgba_to_gray(const float *rgba,
float *gray,
int num_pixels,
@@ -71,7 +72,7 @@ static void uint8_rgba_to_float_gray(const unsigned char *rgba,
}
}
-/* Get grayscale float search buffer for given marker and frame. */
+/** Get gray-scale float search buffer for given marker and frame. */
static float *track_get_search_floatbuf(ImBuf *ibuf,
MovieTrackingTrack *track,
MovieTrackingMarker *marker,
@@ -322,7 +323,7 @@ void BKE_tracking_refine_marker(MovieClip *clip,
int search_area_height, search_area_width;
int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
int reference_framenr;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
double dst_pixel_x[5], dst_pixel_y[5];
bool tracked;
diff --git a/source/blender/blenkernel/intern/tracking_test.cc b/source/blender/blenkernel/intern/tracking_test.cc
index a3845dcad8f..d85d71b7c86 100644
--- a/source/blender/blenkernel/intern/tracking_test.cc
+++ b/source/blender/blenkernel/intern/tracking_test.cc
@@ -5,7 +5,7 @@
#include "DNA_tracking_types.h"
#include "BKE_tracking.h"
-#include "BLI_float2.hh"
+#include "BLI_math_vec_types.hh"
namespace blender {
diff --git a/source/blender/blenkernel/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc
index b23220286e6..cb05337ef2a 100644
--- a/source/blender/blenkernel/intern/type_conversions.cc
+++ b/source/blender/blenkernel/intern/type_conversions.cc
@@ -19,8 +19,7 @@
#include "FN_multi_function_builder.hh"
#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
namespace blender::bke {
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index 743ae91f6f7..3e263fafe28 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -819,6 +819,9 @@ void BKE_undosys_step_load_from_index(UndoStack *ustack, bContext *C, const int
{
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);
}
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 130aa957491..39a7725bfa3 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -28,12 +28,12 @@
#include "BLI_compiler_compat.h"
#include "BLI_fileops.h"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
#include "BLI_ghash.h"
#include "BLI_index_range.hh"
#include "BLI_map.hh"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
@@ -138,11 +138,19 @@ static struct VolumeFileCache {
}
std::lock_guard<std::mutex> lock(mutex);
- return simplified_grids.lookup_or_add_cb(simplify_level, [&]() {
- const float resolution_factor = 1.0f / (1 << simplify_level);
- const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(*grid);
- return BKE_volume_grid_create_with_changed_resolution(grid_type, *grid, resolution_factor);
+ openvdb::GridBase::Ptr simple_grid;
+
+ /* Isolate creating grid since that's multithreaded and we are
+ * holding a mutex lock. */
+ blender::threading::isolate_task([&] {
+ simple_grid = simplified_grids.lookup_or_add_cb(simplify_level, [&]() {
+ const float resolution_factor = 1.0f / (1 << simplify_level);
+ const VolumeGridType grid_type = BKE_volume_grid_type_openvdb(*grid);
+ return BKE_volume_grid_create_with_changed_resolution(
+ grid_type, *grid, resolution_factor);
+ });
});
+ return simple_grid;
}
/* Unique key: filename + grid name. */
@@ -247,16 +255,20 @@ static struct VolumeFileCache {
protected:
void update_for_remove_user(Entry &entry)
{
- if (entry.num_metadata_users + entry.num_tree_users == 0) {
- cache.erase(entry);
- }
- else if (entry.num_tree_users == 0) {
- /* Note we replace the grid rather than clearing, so that if there is
- * any other shared pointer to the grid it will keep the tree. */
- entry.grid = entry.grid->copyGridWithNewTree();
- entry.simplified_grids.clear();
- entry.is_loaded = false;
- }
+ /* Isolate file unloading since that's multithreaded and we are
+ * holding a mutex lock. */
+ blender::threading::isolate_task([&] {
+ if (entry.num_metadata_users + entry.num_tree_users == 0) {
+ cache.erase(entry);
+ }
+ else if (entry.num_tree_users == 0) {
+ /* Note we replace the grid rather than clearing, so that if there is
+ * any other shared pointer to the grid it will keep the tree. */
+ entry.grid = entry.grid->copyGridWithNewTree();
+ entry.simplified_grids.clear();
+ entry.is_loaded = false;
+ }
+ });
}
/* Cache contents */
@@ -537,7 +549,7 @@ static void volume_copy_data(Main *UNUSED(bmain),
#ifdef WITH_OPENVDB
if (volume_src->runtime.grids) {
const VolumeGridVector &grids_src = *(volume_src->runtime.grids);
- volume_dst->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector, grids_src);
+ volume_dst->runtime.grids = MEM_new<VolumeGridVector>(__func__, grids_src);
}
#endif
@@ -551,7 +563,8 @@ static void volume_free_data(ID *id)
BKE_volume_batch_cache_free(volume);
MEM_SAFE_FREE(volume->mat);
#ifdef WITH_OPENVDB
- OBJECT_GUARDED_SAFE_DELETE(volume->runtime.grids, VolumeGridVector);
+ MEM_delete(volume->runtime.grids);
+ volume->runtime.grids = nullptr;
#endif
}
@@ -683,7 +696,7 @@ void BKE_volume_init_grids(Volume *volume)
{
#ifdef WITH_OPENVDB
if (volume->runtime.grids == nullptr) {
- volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector);
+ volume->runtime.grids = MEM_new<VolumeGridVector>(__func__);
}
#else
UNUSED_VARS(volume);
@@ -954,7 +967,7 @@ BoundBox *BKE_volume_boundbox_get(Object *ob)
}
if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
+ ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
const Volume *volume = (Volume *)ob->data;
@@ -1129,16 +1142,16 @@ void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, co
if (!grids->is_loaded()) {
/* No grids loaded in CoW datablock, nothing lost by discarding. */
- OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
+ MEM_delete(grids);
}
else if (!STREQ(volume->filepath, filepath)) {
/* Filepath changed, discard grids from CoW datablock. */
- OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
+ MEM_delete(grids);
}
else {
/* Keep grids from CoW datablock. We might still unload them a little
* later in BKE_volume_eval_geometry if the frame changes. */
- OBJECT_GUARDED_DELETE(volume->runtime.grids, VolumeGridVector);
+ MEM_delete(volume->runtime.grids);
volume->runtime.grids = grids;
}
#else
@@ -1543,11 +1556,6 @@ bool BKE_volume_grid_bounds(openvdb::GridBase::ConstPtr grid, float3 &r_min, flo
return true;
}
-/**
- * Return a new grid pointer with only the metadata and transform changed.
- * This is useful for instances, where there is a separate transform on top of the original
- * grid transform that must be applied for some operations that only take a grid argument.
- */
openvdb::GridBase::ConstPtr BKE_volume_grid_shallow_transform(openvdb::GridBase::ConstPtr grid,
const blender::float4x4 &transform)
{
diff --git a/source/blender/blenkernel/intern/volume_render.cc b/source/blender/blenkernel/intern/volume_render.cc
index 6dc497bb616..c0a205b5673 100644
--- a/source/blender/blenkernel/intern/volume_render.cc
+++ b/source/blender/blenkernel/intern/volume_render.cc
@@ -21,8 +21,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
-#include "BLI_float3.hh"
#include "BLI_math_matrix.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
#include "BLI_vector.hh"
diff --git a/source/blender/blenkernel/intern/volume_to_mesh.cc b/source/blender/blenkernel/intern/volume_to_mesh.cc
index 6e465b2fdf0..336ce724e35 100644
--- a/source/blender/blenkernel/intern/volume_to_mesh.cc
+++ b/source/blender/blenkernel/intern/volume_to_mesh.cc
@@ -16,7 +16,7 @@
#include <vector>
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
@@ -121,11 +121,6 @@ struct VolumeToMeshOp {
}
};
-/**
- * Convert mesh data from the format provided by OpenVDB into Blender's #Mesh data structure.
- * This can be used to add mesh data from a grid into an existing mesh rather than merging multiple
- * meshes later on.
- */
void fill_mesh_from_openvdb_data(const Span<openvdb::Vec3s> vdb_verts,
const Span<openvdb::Vec3I> vdb_tris,
const Span<openvdb::Vec4I> vdb_quads,
@@ -165,10 +160,6 @@ void fill_mesh_from_openvdb_data(const Span<openvdb::Vec3s> vdb_verts,
}
}
-/**
- * Convert an OpenVDB volume grid to corresponding mesh data: vertex positions and quad and
- * triangle indices.
- */
bke::OpenVDBMeshData volume_to_mesh_data(const openvdb::GridBase &grid,
const VolumeToMeshResolution &resolution,
const float threshold,
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 035e56993f9..4d94132e6fd 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -1434,6 +1434,8 @@ int BKE_ffmpeg_append(void *context_v,
/* 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));
+# else
+ UNUSED_VARS(start_frame);
# endif
if (context->ffmpeg_autosplit) {
diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h
index 93014c1b859..c338540b5f5 100644
--- a/source/blender/blenkernel/nla_private.h
+++ b/source/blender/blenkernel/nla_private.h
@@ -185,7 +185,7 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list,
ListBase *strips,
short index,
const struct AnimationEvalContext *anim_eval_context,
- const bool flush_to_original);
+ bool flush_to_original);
/**
* Evaluates the given evaluation strip.
*/
@@ -195,14 +195,14 @@ void nlastrip_evaluate(PointerRNA *ptr,
NlaEvalStrip *nes,
NlaEvalSnapshot *snapshot,
const struct AnimationEvalContext *anim_eval_context,
- const bool flush_to_original);
+ bool flush_to_original);
/**
* write the accumulated settings to.
*/
void nladata_flush_channels(PointerRNA *ptr,
NlaEvalData *channels,
NlaEvalSnapshot *snapshot,
- const bool flush_to_original);
+ bool flush_to_original);
void nlasnapshot_enable_all_blend_domain(NlaEvalSnapshot *snapshot);
@@ -219,8 +219,8 @@ void nlasnapshot_ensure_channels(NlaEvalData *eval_data, NlaEvalSnapshot *snapsh
void nlasnapshot_blend(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *upper_snapshot,
- const short upper_blendmode,
- const float upper_influence,
+ short upper_blendmode,
+ float upper_influence,
NlaEvalSnapshot *r_blended_snapshot);
/**
@@ -234,8 +234,8 @@ void nlasnapshot_blend(NlaEvalData *eval_data,
void nlasnapshot_blend_get_inverted_upper_snapshot(NlaEvalData *eval_data,
NlaEvalSnapshot *lower_snapshot,
NlaEvalSnapshot *blended_snapshot,
- const short upper_blendmode,
- const float upper_influence,
+ short upper_blendmode,
+ float upper_influence,
NlaEvalSnapshot *r_upper_snapshot);
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_any.hh b/source/blender/blenlib/BLI_any.hh
index 0fc5de5540f..7ffc323adf6 100644
--- a/source/blender/blenlib/BLI_any.hh
+++ b/source/blender/blenlib/BLI_any.hh
@@ -209,7 +209,7 @@ class Any {
/**
* Constructs a new #Any that contains the given value.
*/
- template<typename T, typename X = std::enable_if_t<!is_same_any_v<T>, void>>
+ template<typename T, BLI_ENABLE_IF((!is_same_any_v<T>))>
Any(T &&value) : Any(std::in_place_type<T>, std::forward<T>(value))
{
}
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index 5b15bb979f5..85fa07d8563 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -53,9 +53,9 @@
*/
void _bli_array_grow_func(void **arr_p,
const void *arr_static,
- const int sizeof_arr_p,
- const int arr_len,
- const int num,
+ int sizeof_arr_p,
+ int arr_len,
+ int num,
const char *alloc_str);
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh
index 32588b7450d..80464499634 100644
--- a/source/blender/blenlib/BLI_array.hh
+++ b/source/blender/blenlib/BLI_array.hh
@@ -100,7 +100,7 @@ class Array {
/**
* Create a new array that contains copies of all values.
*/
- template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
Array(Span<U> values, Allocator allocator = {}) : Array(NoExceptConstructor(), allocator)
{
const int64_t size = values.size();
@@ -112,7 +112,7 @@ class Array {
/**
* Create a new array that contains copies of all values.
*/
- template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
Array(const std::initializer_list<U> &values, Allocator allocator = {})
: Array(Span<U>(values), allocator)
{
@@ -230,13 +230,13 @@ class Array {
return MutableSpan<T>(data_, size_);
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
operator Span<U>() const
{
return Span<U>(data_, size_);
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
operator MutableSpan<U>()
{
return MutableSpan<U>(data_, size_);
diff --git a/source/blender/blenlib/BLI_array_store.h b/source/blender/blenlib/BLI_array_store.h
index 0be361d4ab9..68928f53e55 100644
--- a/source/blender/blenlib/BLI_array_store.h
+++ b/source/blender/blenlib/BLI_array_store.h
@@ -84,7 +84,7 @@ size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs);
*/
BArrayState *BLI_array_store_state_add(BArrayStore *bs,
const void *data,
- const size_t data_len,
+ size_t data_len,
const BArrayState *state_reference);
/**
* Remove a state and free any unused #BChunk data.
diff --git a/source/blender/blenlib/BLI_array_store_utils.h b/source/blender/blenlib/BLI_array_store_utils.h
index 771f4f962a7..01d7f8804ab 100644
--- a/source/blender/blenlib/BLI_array_store_utils.h
+++ b/source/blender/blenlib/BLI_array_store_utils.h
@@ -32,10 +32,10 @@ struct BArrayStore_AtSize {
};
BArrayStore *BLI_array_store_at_size_ensure(struct BArrayStore_AtSize *bs_stride,
- const int stride,
- const int chunk_size);
+ int stride,
+ int chunk_size);
-BArrayStore *BLI_array_store_at_size_get(struct BArrayStore_AtSize *bs_stride, const int stride);
+BArrayStore *BLI_array_store_at_size_get(struct BArrayStore_AtSize *bs_stride, int stride);
void BLI_array_store_at_size_clear(struct BArrayStore_AtSize *bs_stride);
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index eb14b030bf9..202ae9a9786 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -52,7 +52,7 @@ void _bli_array_wrap(void *arr, uint arr_len, size_t arr_stride, int dir);
* 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);
+ void *arr, uint arr_len, size_t arr_stride, const uint *order, void *arr_temp);
#define BLI_array_permute(arr, arr_len, order) \
_bli_array_permute(arr, arr_len, sizeof(*(arr)), order, NULL)
#define BLI_array_permute_ex(arr, arr_len, order, arr_temp) \
@@ -152,7 +152,7 @@ bool _bli_array_is_zeroed(const void *arr, uint arr_len, size_t arr_stride);
*/
bool _bli_array_iter_spiral_square(const void *arr_v,
const int arr_shape[2],
- const size_t elem_size,
+ size_t elem_size,
const int center[2],
bool (*test_fn)(const void *arr_item, void *user_data),
void *user_data);
diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h
index 6019f0f3566..ad5e2b29766 100644
--- a/source/blender/blenlib/BLI_assert.h
+++ b/source/blender/blenlib/BLI_assert.h
@@ -30,11 +30,12 @@ extern "C" {
#endif
/* Utility functions. */
-void _BLI_assert_print_pos(const char *file, const int line, const char *function, const char *id);
+
+void _BLI_assert_print_pos(const char *file, int line, const char *function, const char *id);
void _BLI_assert_print_extra(const char *str);
void _BLI_assert_print_backtrace(void);
void _BLI_assert_abort(void);
-void _BLI_assert_unreachable_print(const char *file, const int line, const char *function);
+void _BLI_assert_unreachable_print(const char *file, int line, const char *function);
#ifdef _MSC_VER
# include <crtdbg.h> /* for _STATIC_ASSERT */
diff --git a/source/blender/blenlib/BLI_astar.h b/source/blender/blenlib/BLI_astar.h
index a1d4e28dad9..26b45f1ebe6 100644
--- a/source/blender/blenlib/BLI_astar.h
+++ b/source/blender/blenlib/BLI_astar.h
@@ -82,7 +82,7 @@ typedef struct BLI_AStarGraph {
* \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);
+void BLI_astar_node_init(BLI_AStarGraph *as_graph, int node_index, void *custom_data);
/**
* Add a link between two nodes of our A* graph.
*
@@ -91,15 +91,12 @@ void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *c
* \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);
+void BLI_astar_node_link_add(
+ BLI_AStarGraph *as_graph, int node1_index, int node2_index, 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);
+int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, int idx);
/**
* Initialize a solution data for given A* graph. Does not compute anything!
@@ -138,9 +135,9 @@ void BLI_astar_solution_free(BLI_AStarSolution *as_solution);
typedef float (*astar_f_cost)(BLI_AStarGraph *as_graph,
BLI_AStarSolution *as_solution,
BLI_AStarGNLink *link,
- const int node_idx_curr,
- const int node_idx_next,
- const int node_idx_dst);
+ int node_idx_curr,
+ int node_idx_next,
+ int node_idx_dst);
/**
* Initialize an A* graph. Total number of nodes must be known.
@@ -150,7 +147,7 @@ typedef float (*astar_f_cost)(BLI_AStarGraph *as_graph,
* \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_init(BLI_AStarGraph *as_graph, 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.
@@ -161,11 +158,11 @@ void BLI_astar_graph_free(BLI_AStarGraph *as_graph);
* \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,
+ int node_index_src,
+ int node_index_dst,
astar_f_cost f_cost_cb,
BLI_AStarSolution *r_solution,
- const int max_steps);
+ int max_steps);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_bitmap_draw_2d.h b/source/blender/blenlib/BLI_bitmap_draw_2d.h
index 1b9ff2162e3..3831ed3c9e7 100644
--- a/source/blender/blenlib/BLI_bitmap_draw_2d.h
+++ b/source/blender/blenlib/BLI_bitmap_draw_2d.h
@@ -55,12 +55,12 @@ void BLI_bitmap_draw_2d_tri_v2i(const int p1[2],
* } while (++x != x_end);
* \endcode
*/
-void BLI_bitmap_draw_2d_poly_v2i_n(const int xmin,
- const int ymin,
- const int xmax,
- const int ymax,
+void BLI_bitmap_draw_2d_poly_v2i_n(int xmin,
+ int ymin,
+ int xmax,
+ int ymax,
const int verts[][2],
- const int verts_len,
+ int verts_len,
void (*callback)(int x, int x_end, int y, void *),
void *user_data);
diff --git a/source/blender/blenlib/BLI_boxpack_2d.h b/source/blender/blenlib/BLI_boxpack_2d.h
index e743424db59..eee1a0d3d41 100644
--- a/source/blender/blenlib/BLI_boxpack_2d.h
+++ b/source/blender/blenlib/BLI_boxpack_2d.h
@@ -58,7 +58,7 @@ typedef struct BoxPack {
* \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);
+void BLI_box_pack_2d(BoxPack *boxarray, unsigned int len, float *r_tot_x, float *r_tot_y);
typedef struct FixedSizeBoxPack {
struct FixedSizeBoxPack *next, *prev;
diff --git a/source/blender/blenlib/BLI_buffer.h b/source/blender/blenlib/BLI_buffer.h
index 7f577443cf7..e79d44fd934 100644
--- a/source/blender/blenlib/BLI_buffer.h
+++ b/source/blender/blenlib/BLI_buffer.h
@@ -74,7 +74,7 @@ enum {
/**
* \note Never decreases the amount of memory allocated.
*/
-void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count);
+void BLI_buffer_resize(BLI_Buffer *buffer, size_t new_count);
/**
* Ensure size, throwing away old data, respecting #BLI_BUFFER_USE_CALLOC.
@@ -83,7 +83,7 @@ void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count);
* - Ignored (malloc'd).
* - Cleared (when #BLI_BUFFER_USE_CALLOC is set).
*/
-void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count);
+void BLI_buffer_reinit(BLI_Buffer *buffer, size_t new_count);
/**
* Append an array of elements.
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
index d93bd7f6f76..deb1774a4c5 100644
--- a/source/blender/blenlib/BLI_color.hh
+++ b/source/blender/blenlib/BLI_color.hh
@@ -73,27 +73,27 @@ namespace blender {
* - Add non RGB spaces/storages ColorXyz.
*/
-/* Enumeration containing the different alpha modes. */
+/** Enumeration containing the different alpha modes. */
enum class eAlpha {
- /* Color and alpha are unassociated. */
+ /** Color and alpha are unassociated. */
Straight,
- /* Color and alpha are associated. */
+ /** Color and alpha are associated. */
Premultiplied,
};
std::ostream &operator<<(std::ostream &stream, const eAlpha &space);
-/* Enumeration containing internal spaces. */
+/** Enumeration containing internal spaces. */
enum class eSpace {
- /* Blender theme color space (sRGB). */
+ /** Blender theme color space (sRGB). */
Theme,
- /* Blender internal scene linear color space (maps to SceneReference role in OCIO). */
+ /** Blender internal scene linear color space (maps to scene_linear role in OCIO). */
SceneLinear,
- /* Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
+ /** Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
SceneLinearByteEncoded,
};
std::ostream &operator<<(std::ostream &stream, const eSpace &space);
-/* Template class to store RGBA values with different precision, space and alpha association. */
+/** Template class to store RGBA values with different precision, space and alpha association. */
template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGBA {
public:
ChannelStorageType r, g, b, a;
@@ -153,11 +153,13 @@ template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGB
};
/* Forward declarations of concrete color classes. */
+
template<eAlpha Alpha> class ColorSceneLinear4f;
template<eAlpha Alpha> class ColorSceneLinearByteEncoded4b;
template<typename ChannelStorageType> class ColorTheme4;
/* Forward declaration of precision conversion methods. */
+
BLI_INLINE ColorTheme4<float> BLI_color_convert_to_theme4f(const ColorTheme4<uint8_t> &srgb4b);
BLI_INLINE ColorTheme4<uint8_t> BLI_color_convert_to_theme4b(const ColorTheme4<float> &srgb4f);
@@ -354,6 +356,7 @@ BLI_color_convert_to_theme4b(const ColorSceneLinear4f<eAlpha::Straight> &scene_l
}
/* Internal roles. For convenience to shorten the type names and hide complexity. */
+
using ColorGeometry4f = ColorSceneLinear4f<eAlpha::Premultiplied>;
using ColorGeometry4b = ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>;
diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h
index bd8f84cedd6..023fea3853e 100644
--- a/source/blender/blenlib/BLI_compiler_compat.h
+++ b/source/blender/blenlib/BLI_compiler_compat.h
@@ -34,7 +34,7 @@
#if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus)
extern "C++" {
-/* Some magic to be sure we don't have reference in the type. */
+/** Some magic to be sure we don't have reference in the type. */
template<typename T> static inline T decltype_helper(T x)
{
return x;
diff --git a/source/blender/blenlib/BLI_convexhull_2d.h b/source/blender/blenlib/BLI_convexhull_2d.h
index 44758fb3880..77f3eedec95 100644
--- a/source/blender/blenlib/BLI_convexhull_2d.h
+++ b/source/blender/blenlib/BLI_convexhull_2d.h
@@ -32,7 +32,7 @@ extern "C" {
* \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[]);
+int BLI_convexhull_2d_sorted(const float (*points)[2], int n, int r_points[]);
/**
* A.M. Andrew's monotone chain 2D convex hull algorithm.
*
@@ -43,7 +43,7 @@ int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points
* 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[]);
+int BLI_convexhull_2d(const float (*points)[2], int n, int r_points[]);
/**
* \return The best angle for fitting the convex hull to an axis aligned bounding box.
diff --git a/source/blender/blenlib/BLI_delaunay_2d.h b/source/blender/blenlib/BLI_delaunay_2d.h
index 658dcadadce..1ee0be64cee 100644
--- a/source/blender/blenlib/BLI_delaunay_2d.h
+++ b/source/blender/blenlib/BLI_delaunay_2d.h
@@ -215,14 +215,14 @@ void BLI_delaunay_2d_cdt_free(CDT_result *result);
/* C++ Interface. */
# include "BLI_array.hh"
-# include "BLI_double2.hh"
# include "BLI_math_mpq.hh"
-# include "BLI_mpq2.hh"
+# include "BLI_math_vec_mpq_types.hh"
+# include "BLI_math_vec_types.hh"
# include "BLI_vector.hh"
namespace blender::meshintersect {
-/* vec2<Arith_t> is a 2d vector with Arith_t as the type for coordinates. */
+/** #vec2<Arith_t> is a 2d vector with #Arith_t as the type for coordinates. */
template<typename Arith_t> struct vec2_impl;
template<> struct vec2_impl<double> {
typedef double2 type;
diff --git a/source/blender/blenlib/BLI_dlrbTree.h b/source/blender/blenlib/BLI_dlrbTree.h
index 72f18244d5b..3cf849efaef 100644
--- a/source/blender/blenlib/BLI_dlrbTree.h
+++ b/source/blender/blenlib/BLI_dlrbTree.h
@@ -40,7 +40,7 @@ extern "C" {
/** \name Base Structs
* \{ */
-/* Basic Layout for a Node */
+/** Basic Layout for a Node. */
typedef struct DLRBT_Node {
/* ListBase capabilities */
struct DLRBT_Node *next, *prev;
@@ -53,7 +53,7 @@ typedef struct DLRBT_Node {
/* ... for nice alignment, next item should usually be a char too... */
} DLRBT_Node;
-/* Red/Black defines for tree_col */
+/** Red/Black defines for tree_col. */
typedef enum eDLRBT_Colors {
DLRBT_BLACK = 0,
DLRBT_RED,
@@ -61,7 +61,7 @@ typedef enum eDLRBT_Colors {
/* -------- */
-/* The Tree Data */
+/** The Tree Data. */
typedef struct DLRBT_Tree {
/* ListBase capabilities */
void *first, *last; /* these should be based on DLRBT_Node-s */
diff --git a/source/blender/blenlib/BLI_double2.hh b/source/blender/blenlib/BLI_double2.hh
deleted file mode 100644
index 0abff01ab2f..00000000000
--- a/source/blender/blenlib/BLI_double2.hh
+++ /dev/null
@@ -1,143 +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
-
-/** \file
- * \ingroup bli
- */
-
-#include "BLI_double3.hh"
-
-namespace blender {
-
-struct double2 {
- double x, y;
-
- double2() = default;
-
- double2(const double *ptr) : x{ptr[0]}, y{ptr[1]}
- {
- }
-
- double2(double x, double y) : x(x), y(y)
- {
- }
-
- double2(const double3 &other) : x(other.x), y(other.y)
- {
- }
-
- operator double *()
- {
- return &x;
- }
-
- operator const double *() const
- {
- return &x;
- }
-
- double length() const
- {
- return len_v2_db(*this);
- }
-
- friend double2 operator+(const double2 &a, const double2 &b)
- {
- return {a.x + b.x, a.y + b.y};
- }
-
- friend double2 operator-(const double2 &a, const double2 &b)
- {
- return {a.x - b.x, a.y - b.y};
- }
-
- friend double2 operator*(const double2 &a, double b)
- {
- return {a.x * b, a.y * b};
- }
-
- friend double2 operator/(const double2 &a, double b)
- {
- BLI_assert(b != 0.0);
- return {a.x / b, a.y / b};
- }
-
- friend double2 operator*(double a, const double2 &b)
- {
- return b * a;
- }
-
- friend bool operator==(const double2 &a, const double2 &b)
- {
- return a.x == b.x && a.y == b.y;
- }
-
- friend bool operator!=(const double2 &a, const double2 &b)
- {
- return a.x != b.x || a.y != b.y;
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const double2 &v)
- {
- stream << "(" << v.x << ", " << v.y << ")";
- return stream;
- }
-
- static double dot(const double2 &a, const double2 &b)
- {
- return a.x * b.x + a.y * b.y;
- }
-
- static double2 interpolate(const double2 &a, const double2 &b, double t)
- {
- return a * (1 - t) + b * t;
- }
-
- static double2 abs(const double2 &a)
- {
- return double2(fabs(a.x), fabs(a.y));
- }
-
- static double distance(const double2 &a, const double2 &b)
- {
- return (a - b).length();
- }
-
- static double distance_squared(const double2 &a, const double2 &b)
- {
- double2 diff = a - b;
- return double2::dot(diff, diff);
- }
-
- struct isect_result {
- enum {
- LINE_LINE_COLINEAR = -1,
- LINE_LINE_NONE = 0,
- LINE_LINE_EXACT = 1,
- LINE_LINE_CROSS = 2,
- } kind;
- double lambda;
- };
-
- static isect_result isect_seg_seg(const double2 &v1,
- const double2 &v2,
- const double2 &v3,
- const double2 &v4);
-};
-
-} // namespace blender
diff --git a/source/blender/blenlib/BLI_double3.hh b/source/blender/blenlib/BLI_double3.hh
deleted file mode 100644
index ab258c9121b..00000000000
--- a/source/blender/blenlib/BLI_double3.hh
+++ /dev/null
@@ -1,246 +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
-
-/** \file
- * \ingroup bli
- */
-
-#include <iostream>
-
-#include "BLI_math_vector.h"
-#include "BLI_span.hh"
-
-namespace blender {
-
-struct double3 {
- double x, y, z;
-
- double3() = default;
-
- double3(const double *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}
- {
- }
-
- double3(const double (*ptr)[3]) : double3((const double *)ptr)
- {
- }
-
- explicit double3(double value) : x(value), y(value), z(value)
- {
- }
-
- explicit double3(int value) : x(value), y(value), z(value)
- {
- }
-
- double3(double x, double y, double z) : x{x}, y{y}, z{z}
- {
- }
-
- operator const double *() const
- {
- return &x;
- }
-
- operator double *()
- {
- return &x;
- }
-
- double normalize_and_get_length()
- {
- return normalize_v3_db(*this);
- }
-
- double3 normalized() const
- {
- double3 result;
- normalize_v3_v3_db(result, *this);
- return result;
- }
-
- double length() const
- {
- return len_v3_db(*this);
- }
-
- double length_squared() const
- {
- return len_squared_v3_db(*this);
- }
-
- void reflect(const double3 &normal)
- {
- *this = this->reflected(normal);
- }
-
- double3 reflected(const double3 &normal) const
- {
- double3 result;
- reflect_v3_v3v3_db(result, *this, normal);
- return result;
- }
-
- static double3 safe_divide(const double3 &a, const double3 &b)
- {
- double3 result;
- result.x = (b.x == 0.0) ? 0.0 : a.x / b.x;
- result.y = (b.y == 0.0) ? 0.0 : a.y / b.y;
- result.z = (b.z == 0.0) ? 0.0 : a.z / b.z;
- return result;
- }
-
- void invert()
- {
- x = -x;
- y = -y;
- z = -z;
- }
-
- friend double3 operator+(const double3 &a, const double3 &b)
- {
- return {a.x + b.x, a.y + b.y, a.z + b.z};
- }
-
- void operator+=(const double3 &b)
- {
- this->x += b.x;
- this->y += b.y;
- this->z += b.z;
- }
-
- friend double3 operator-(const double3 &a, const double3 &b)
- {
- return {a.x - b.x, a.y - b.y, a.z - b.z};
- }
-
- friend double3 operator-(const double3 &a)
- {
- return {-a.x, -a.y, -a.z};
- }
-
- void operator-=(const double3 &b)
- {
- this->x -= b.x;
- this->y -= b.y;
- this->z -= b.z;
- }
-
- void operator*=(const double &scalar)
- {
- this->x *= scalar;
- this->y *= scalar;
- this->z *= scalar;
- }
-
- void operator*=(const double3 &other)
- {
- this->x *= other.x;
- this->y *= other.y;
- this->z *= other.z;
- }
-
- friend double3 operator*(const double3 &a, const double3 &b)
- {
- return {a.x * b.x, a.y * b.y, a.z * b.z};
- }
-
- friend double3 operator*(const double3 &a, const double &b)
- {
- return {a.x * b, a.y * b, a.z * b};
- }
-
- friend double3 operator*(const double &a, const double3 &b)
- {
- return b * a;
- }
-
- friend double3 operator/(const double3 &a, const double &b)
- {
- BLI_assert(b != 0.0);
- return {a.x / b, a.y / b, a.z / b};
- }
-
- friend bool operator==(const double3 &a, const double3 &b)
- {
- return a.x == b.x && a.y == b.y && a.z == b.z;
- }
-
- friend bool operator!=(const double3 &a, const double3 &b)
- {
- return a.x != b.x || a.y != b.y || a.z != b.z;
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const double3 &v)
- {
- stream << "(" << v.x << ", " << v.y << ", " << v.z << ")";
- return stream;
- }
-
- static double dot(const double3 &a, const double3 &b)
- {
- return a.x * b.x + a.y * b.y + a.z * b.z;
- }
-
- static double3 cross_high_precision(const double3 &a, const double3 &b)
- {
- double3 result;
- cross_v3_v3v3_db(result, a, b);
- return result;
- }
-
- static double3 project(const double3 &a, const double3 &b)
- {
- double3 result;
- project_v3_v3v3_db(result, a, b);
- return result;
- }
-
- static double distance(const double3 &a, const double3 &b)
- {
- return (a - b).length();
- }
-
- static double distance_squared(const double3 &a, const double3 &b)
- {
- double3 diff = a - b;
- return double3::dot(diff, diff);
- }
-
- static double3 interpolate(const double3 &a, const double3 &b, double t)
- {
- return a * (1 - t) + b * t;
- }
-
- static double3 abs(const double3 &a)
- {
- return double3(fabs(a.x), fabs(a.y), fabs(a.z));
- }
-
- static int dominant_axis(const double3 &a)
- {
- double x = (a.x >= 0) ? a.x : -a.x;
- double y = (a.y >= 0) ? a.y : -a.y;
- double z = (a.z >= 0) ? a.z : -a.z;
- return ((x > y) ? ((x > z) ? 0 : 2) : ((y > z) ? 1 : 2));
- }
-
- static double3 cross_poly(Span<double3> poly);
-};
-
-} // namespace blender
diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h
index b0f71655c19..26eb8ab7665 100644
--- a/source/blender/blenlib/BLI_edgehash.h
+++ b/source/blender/blenlib/BLI_edgehash.h
@@ -54,7 +54,7 @@ enum {
EDGEHASH_FLAG_ALLOW_DUPES = (1 << 0),
};
-EdgeHash *BLI_edgehash_new_ex(const char *info, const unsigned int nentries_reserve);
+EdgeHash *BLI_edgehash_new_ex(const char *info, 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);
@@ -138,7 +138,7 @@ 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);
+void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, uint reserve);
/**
* Wraps #BLI_edgehash_clear_ex with zero entries reserved.
*/
@@ -207,8 +207,8 @@ typedef struct EdgeSetIterator {
uint index;
} EdgeSetIterator;
-EdgeSet *BLI_edgeset_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+EdgeSet *BLI_edgeset_new_ex(const char *info,
+ unsigned int nentries_reserve) 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;
/**
diff --git a/source/blender/blenlib/BLI_endian_switch.h b/source/blender/blenlib/BLI_endian_switch.h
index b512133b34c..c8257483616 100644
--- a/source/blender/blenlib/BLI_endian_switch.h
+++ b/source/blender/blenlib/BLI_endian_switch.h
@@ -30,6 +30,7 @@ extern "C" {
#endif
/* BLI_endian_switch_inline.h */
+
BLI_INLINE void BLI_endian_switch_int16(short *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1);
@@ -40,14 +41,15 @@ BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_double(double *val) ATTR_NONNULL(1);
/* endian_switch.c */
-void BLI_endian_switch_int16_array(short *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_uint16_array(unsigned short *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_int32_array(int *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_uint32_array(unsigned int *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_float_array(float *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_int64_array(int64_t *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_uint64_array(uint64_t *val, const int size) ATTR_NONNULL(1);
-void BLI_endian_switch_double_array(double *val, const int size) ATTR_NONNULL(1);
+
+void BLI_endian_switch_int16_array(short *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_uint16_array(unsigned short *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_int32_array(int *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_uint32_array(unsigned int *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_float_array(float *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_int64_array(int64_t *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_uint64_array(uint64_t *val, int size) ATTR_NONNULL(1);
+void BLI_endian_switch_double_array(double *val, int size) ATTR_NONNULL(1);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_endian_switch_inline.h b/source/blender/blenlib/BLI_endian_switch_inline.h
index ec4cfe4801a..31be7fd47e4 100644
--- a/source/blender/blenlib/BLI_endian_switch_inline.h
+++ b/source/blender/blenlib/BLI_endian_switch_inline.h
@@ -33,6 +33,7 @@ extern "C" {
* use bit shifting instead. */
/* *** 16 *** */
+
BLI_INLINE void BLI_endian_switch_int16(short *val)
{
BLI_endian_switch_uint16((unsigned short *)val);
@@ -48,6 +49,7 @@ BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val)
}
/* *** 32 *** */
+
BLI_INLINE void BLI_endian_switch_int32(int *val)
{
BLI_endian_switch_uint32((unsigned int *)val);
@@ -67,6 +69,7 @@ BLI_INLINE void BLI_endian_switch_float(float *val)
}
/* *** 64 *** */
+
BLI_INLINE void BLI_endian_switch_int64(int64_t *val)
{
BLI_endian_switch_uint64((uint64_t *)val);
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 2ef9b8f6c36..28cb5f6d84b 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -155,8 +155,7 @@ double BLI_dir_free_space(const char *dir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(
*
* \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();
+char *BLI_current_working_dir(char *dir, size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
eFileAttributes BLI_file_attributes(const char *path);
/** \} */
@@ -181,7 +180,7 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s
*/
void BLI_filelist_duplicate(struct direntry **dest_filelist,
struct direntry *const src_filelist,
- const unsigned int nrentries);
+ unsigned int nrentries);
/**
* Frees storage for a single direntry, not the direntry itself.
*/
@@ -189,20 +188,20 @@ 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);
+void BLI_filelist_free(struct direntry *filelist, 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,
+ uint64_t sz,
+ 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,
+ bool compact,
char r_mode1[FILELIST_DIRENTRY_MODE_LEN],
char r_mode2[FILELIST_DIRENTRY_MODE_LEN],
char r_mode3[FILELIST_DIRENTRY_MODE_LEN]);
@@ -210,7 +209,7 @@ void BLI_filelist_entry_mode_to_string(const struct stat *st,
* Convert given entry's owner into human-readable strings.
*/
void BLI_filelist_entry_owner_to_string(const struct stat *st,
- const bool compact,
+ bool compact,
char r_owner[FILELIST_DIRENTRY_OWNER_LEN]);
/**
* Convert given entry's time into human-readable strings.
@@ -219,8 +218,8 @@ void BLI_filelist_entry_owner_to_string(const struct stat *st,
* \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,
+ int64_t ts,
+ bool compact,
char r_time[FILELIST_DIRENTRY_TIME_LEN],
char r_date[FILELIST_DIRENTRY_DATE_LEN],
bool *r_is_today,
diff --git a/source/blender/blenlib/BLI_fileops.hh b/source/blender/blenlib/BLI_fileops.hh
new file mode 100644
index 00000000000..c69b1983c59
--- /dev/null
+++ b/source/blender/blenlib/BLI_fileops.hh
@@ -0,0 +1,52 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ * \brief File and directory operations.
+ */
+
+#pragma once
+
+#ifndef __cplusplus
+# error This is a C++ header
+#endif
+
+#include "BLI_fileops.h"
+#include "BLI_string_ref.hh"
+
+#include <fstream>
+#include <string>
+
+namespace blender {
+
+/**
+ * std::fstream subclass that handles UTF-16 encoding on Windows.
+ *
+ * For documentation, see https://en.cppreference.com/w/cpp/io/basic_fstream
+ */
+class fstream : public std::fstream {
+ public:
+ fstream() = default;
+ explicit fstream(const char *filepath,
+ std::ios_base::openmode mode = ios_base::in | ios_base::out);
+ explicit fstream(const std::string &filepath,
+ std::ios_base::openmode mode = ios_base::in | ios_base::out);
+
+ void open(StringRefNull filepath, ios_base::openmode mode = ios_base::in | ios_base::out);
+};
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_filereader.h b/source/blender/blenlib/BLI_filereader.h
index da223cddf40..f232ad72cc4 100644
--- a/source/blender/blenlib/BLI_filereader.h
+++ b/source/blender/blenlib/BLI_filereader.h
@@ -47,7 +47,7 @@ typedef ssize_t (*FileReaderReadFn)(struct FileReader *reader, void *buffer, siz
typedef off64_t (*FileReaderSeekFn)(struct FileReader *reader, off64_t offset, int whence);
typedef void (*FileReaderCloseFn)(struct FileReader *reader);
-/* General structure for all FileReaders, implementations add custom fields at the end. */
+/** General structure for all #FileReaders, implementations add custom fields at the end. */
typedef struct FileReader {
FileReaderReadFn read;
FileReaderSeekFn seek;
@@ -64,16 +64,16 @@ typedef struct FileReader {
* take over the base FileReader and will clean it up when their clean() is called.
*/
-/* Create FileReader from raw file descriptor. */
+/** Create #FileReader from raw file descriptor. */
FileReader *BLI_filereader_new_file(int filedes) ATTR_WARN_UNUSED_RESULT;
-/* Create FileReader from raw file descriptor using memory-mapped IO. */
+/** Create #FileReader from raw file descriptor using memory-mapped IO. */
FileReader *BLI_filereader_new_mmap(int filedes) ATTR_WARN_UNUSED_RESULT;
-/* Create FileReader from a region of memory. */
+/** Create #FileReader from a region of memory. */
FileReader *BLI_filereader_new_memory(const void *data, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-/* Create FileReader from applying `Zstd` decompression on an underlying file. */
+/** Create #FileReader from applying `Zstd` decompression on an underlying file. */
FileReader *BLI_filereader_new_zstd(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* Create FileReader from applying `Gzip` decompression on an underlying file. */
+/** Create #FileReader from applying `Gzip` decompression on an underlying file. */
FileReader *BLI_filereader_new_gzip(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_float2.hh b/source/blender/blenlib/BLI_float2.hh
deleted file mode 100644
index bb4229db86e..00000000000
--- a/source/blender/blenlib/BLI_float2.hh
+++ /dev/null
@@ -1,218 +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 "BLI_float3.hh"
-
-namespace blender {
-
-struct float2 {
- float x, y;
-
- float2() = default;
-
- float2(const float *ptr) : x{ptr[0]}, y{ptr[1]}
- {
- }
-
- explicit float2(float value) : x(value), y(value)
- {
- }
-
- explicit float2(int value) : x(value), y(value)
- {
- }
-
- float2(float x, float y) : x(x), y(y)
- {
- }
-
- float2(const float3 &other) : x(other.x), y(other.y)
- {
- }
-
- operator float *()
- {
- return &x;
- }
-
- operator const float *() const
- {
- return &x;
- }
-
- float length() const
- {
- return len_v2(*this);
- }
-
- float length_squared() const
- {
- return len_squared_v2(*this);
- }
-
- bool is_zero() const
- {
- return this->x == 0.0f && this->y == 0.0f;
- }
-
- float2 &operator+=(const float2 &other)
- {
- x += other.x;
- y += other.y;
- return *this;
- }
-
- float2 &operator-=(const float2 &other)
- {
- x -= other.x;
- y -= other.y;
- return *this;
- }
-
- float2 &operator*=(float factor)
- {
- x *= factor;
- y *= factor;
- return *this;
- }
-
- float2 &operator/=(float divisor)
- {
- x /= divisor;
- y /= divisor;
- return *this;
- }
-
- uint64_t hash() const
- {
- uint64_t x1 = *reinterpret_cast<const uint32_t *>(&x);
- uint64_t x2 = *reinterpret_cast<const uint32_t *>(&y);
- return (x1 * 812519) ^ (x2 * 707951);
- }
-
- friend float2 operator+(const float2 &a, const float2 &b)
- {
- return {a.x + b.x, a.y + b.y};
- }
-
- friend float2 operator-(const float2 &a, const float2 &b)
- {
- return {a.x - b.x, a.y - b.y};
- }
-
- friend float2 operator-(const float2 &a, const float &b)
- {
- return {a.x - b, a.y - b};
- }
-
- friend float2 operator*(const float2 &a, float b)
- {
- return {a.x * b, a.y * b};
- }
-
- friend float2 operator/(const float2 &a, float b)
- {
- BLI_assert(b != 0.0f);
- return {a.x / b, a.y / b};
- }
-
- friend float2 operator*(float a, const float2 &b)
- {
- return b * a;
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const float2 &v)
- {
- stream << "(" << v.x << ", " << v.y << ")";
- return stream;
- }
-
- static float2 safe_divide(const float2 &a, const float b)
- {
- return (b != 0.0f) ? a / b : float2(0.0f);
- }
-
- static float2 floor(const float2 &a)
- {
- return float2(floorf(a.x), floorf(a.y));
- }
-
- /**
- * Returns a normalized vector. The original vector is not changed.
- */
- float2 normalized() const
- {
- float2 result;
- normalize_v2_v2(result, *this);
- return result;
- }
-
- static float dot(const float2 &a, const float2 &b)
- {
- return a.x * b.x + a.y * b.y;
- }
-
- static float2 interpolate(const float2 &a, const float2 &b, float t)
- {
- return a * (1 - t) + b * t;
- }
-
- static float2 abs(const float2 &a)
- {
- return float2(fabsf(a.x), fabsf(a.y));
- }
-
- static float distance(const float2 &a, const float2 &b)
- {
- return (a - b).length();
- }
-
- static float distance_squared(const float2 &a, const float2 &b)
- {
- float2 diff = a - b;
- return float2::dot(diff, diff);
- }
-
- struct isect_result {
- enum {
- LINE_LINE_COLINEAR = -1,
- LINE_LINE_NONE = 0,
- LINE_LINE_EXACT = 1,
- LINE_LINE_CROSS = 2,
- } kind;
- float lambda;
- float mu;
- };
-
- static isect_result isect_seg_seg(const float2 &v1,
- const float2 &v2,
- const float2 &v3,
- const float2 &v4);
-
- friend bool operator==(const float2 &a, const float2 &b)
- {
- return a.x == b.x && a.y == b.y;
- }
-
- friend bool operator!=(const float2 &a, const float2 &b)
- {
- return !(a == b);
- }
-};
-
-} // namespace blender
diff --git a/source/blender/blenlib/BLI_float3.hh b/source/blender/blenlib/BLI_float3.hh
deleted file mode 100644
index 6ee0c4b973b..00000000000
--- a/source/blender/blenlib/BLI_float3.hh
+++ /dev/null
@@ -1,304 +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 <iostream>
-
-#include "BLI_math_vector.h"
-
-namespace blender {
-
-struct float3 {
- float x, y, z;
-
- float3() = default;
-
- float3(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}
- {
- }
-
- float3(const float (*ptr)[3]) : float3(static_cast<const float *>(ptr[0]))
- {
- }
-
- explicit float3(float value) : x(value), y(value), z(value)
- {
- }
-
- explicit float3(int value) : x(value), y(value), z(value)
- {
- }
-
- float3(float x, float y, float z) : x{x}, y{y}, z{z}
- {
- }
-
- operator const float *() const
- {
- return &x;
- }
-
- operator float *()
- {
- return &x;
- }
-
- friend float3 operator+(const float3 &a, const float3 &b)
- {
- return {a.x + b.x, a.y + b.y, a.z + b.z};
- }
-
- friend float3 operator+(const float3 &a, const float &b)
- {
- return {a.x + b, a.y + b, a.z + b};
- }
-
- float3 &operator+=(const float3 &b)
- {
- this->x += b.x;
- this->y += b.y;
- this->z += b.z;
- return *this;
- }
-
- friend float3 operator-(const float3 &a, const float3 &b)
- {
- return {a.x - b.x, a.y - b.y, a.z - b.z};
- }
-
- friend float3 operator-(const float3 &a)
- {
- return {-a.x, -a.y, -a.z};
- }
-
- friend float3 operator-(const float3 &a, const float &b)
- {
- return {a.x - b, a.y - b, a.z - b};
- }
-
- float3 &operator-=(const float3 &b)
- {
- this->x -= b.x;
- this->y -= b.y;
- this->z -= b.z;
- return *this;
- }
-
- float3 &operator*=(float scalar)
- {
- this->x *= scalar;
- this->y *= scalar;
- this->z *= scalar;
- return *this;
- }
-
- float3 &operator*=(const float3 &other)
- {
- this->x *= other.x;
- this->y *= other.y;
- this->z *= other.z;
- return *this;
- }
-
- friend float3 operator*(const float3 &a, const float3 &b)
- {
- return {a.x * b.x, a.y * b.y, a.z * b.z};
- }
-
- friend float3 operator*(const float3 &a, float b)
- {
- return {a.x * b, a.y * b, a.z * b};
- }
-
- friend float3 operator*(float a, const float3 &b)
- {
- return b * a;
- }
-
- friend float3 operator/(const float3 &a, float b)
- {
- BLI_assert(b != 0.0f);
- return {a.x / b, a.y / b, a.z / b};
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const float3 &v)
- {
- stream << "(" << v.x << ", " << v.y << ", " << v.z << ")";
- return stream;
- }
-
- friend bool operator==(const float3 &a, const float3 &b)
- {
- return a.x == b.x && a.y == b.y && a.z == b.z;
- }
-
- friend bool operator!=(const float3 &a, const float3 &b)
- {
- return !(a == b);
- }
-
- float normalize_and_get_length()
- {
- return normalize_v3(*this);
- }
-
- /**
- * Normalizes the vector in place.
- */
- void normalize()
- {
- normalize_v3(*this);
- }
-
- /**
- * Returns a normalized vector. The original vector is not changed.
- */
- float3 normalized() const
- {
- float3 result;
- normalize_v3_v3(result, *this);
- return result;
- }
-
- float length() const
- {
- return len_v3(*this);
- }
-
- float length_squared() const
- {
- return len_squared_v3(*this);
- }
-
- bool is_zero() const
- {
- return this->x == 0.0f && this->y == 0.0f && this->z == 0.0f;
- }
-
- void reflect(const float3 &normal)
- {
- *this = this->reflected(normal);
- }
-
- float3 reflected(const float3 &normal) const
- {
- float3 result;
- reflect_v3_v3v3(result, *this, normal);
- return result;
- }
-
- static float3 refract(const float3 &incident, const float3 &normal, const float eta)
- {
- float3 result;
- float k = 1.0f - eta * eta * (1.0f - dot(normal, incident) * dot(normal, incident));
- if (k < 0.0f) {
- result = float3(0.0f);
- }
- else {
- result = eta * incident - (eta * dot(normal, incident) + sqrt(k)) * normal;
- }
- return result;
- }
-
- static float3 faceforward(const float3 &vector, const float3 &incident, const float3 &reference)
- {
- return dot(reference, incident) < 0.0f ? vector : -vector;
- }
-
- static float3 safe_divide(const float3 &a, const float3 &b)
- {
- float3 result;
- result.x = (b.x == 0.0f) ? 0.0f : a.x / b.x;
- result.y = (b.y == 0.0f) ? 0.0f : a.y / b.y;
- result.z = (b.z == 0.0f) ? 0.0f : a.z / b.z;
- return result;
- }
-
- static float3 safe_divide(const float3 &a, const float b)
- {
- return (b != 0.0f) ? a / b : float3(0.0f);
- }
-
- static float3 floor(const float3 &a)
- {
- return float3(floorf(a.x), floorf(a.y), floorf(a.z));
- }
-
- void invert()
- {
- x = -x;
- y = -y;
- z = -z;
- }
-
- uint64_t hash() const
- {
- uint64_t x1 = *reinterpret_cast<const uint32_t *>(&x);
- uint64_t x2 = *reinterpret_cast<const uint32_t *>(&y);
- uint64_t x3 = *reinterpret_cast<const uint32_t *>(&z);
- return (x1 * 435109) ^ (x2 * 380867) ^ (x3 * 1059217);
- }
-
- static float dot(const float3 &a, const float3 &b)
- {
- return a.x * b.x + a.y * b.y + a.z * b.z;
- }
-
- static float3 cross_high_precision(const float3 &a, const float3 &b)
- {
- float3 result;
- cross_v3_v3v3_hi_prec(result, a, b);
- return result;
- }
-
- static float3 cross(const float3 &a, const float3 &b)
- {
- float3 result;
- cross_v3_v3v3(result, a, b);
- return result;
- }
-
- static float3 project(const float3 &a, const float3 &b)
- {
- float3 result;
- project_v3_v3v3(result, a, b);
- return result;
- }
-
- static float distance(const float3 &a, const float3 &b)
- {
- return (a - b).length();
- }
-
- static float distance_squared(const float3 &a, const float3 &b)
- {
- float3 diff = a - b;
- return float3::dot(diff, diff);
- }
-
- static float3 interpolate(const float3 &a, const float3 &b, float t)
- {
- return a * (1 - t) + b * t;
- }
-
- static float3 abs(const float3 &a)
- {
- return float3(fabsf(a.x), fabsf(a.y), fabsf(a.z));
- }
-};
-
-} // namespace blender
diff --git a/source/blender/blenlib/BLI_float4.hh b/source/blender/blenlib/BLI_float4.hh
deleted file mode 100644
index 5b487f6d029..00000000000
--- a/source/blender/blenlib/BLI_float4.hh
+++ /dev/null
@@ -1,138 +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
-
-namespace blender {
-
-struct float4 {
- float x, y, z, w;
-
- float4() = default;
-
- float4(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}, w{ptr[3]}
- {
- }
-
- explicit float4(float value) : x(value), y(value), z(value), w(value)
- {
- }
-
- explicit float4(int value) : x(value), y(value), z(value), w(value)
- {
- }
-
- float4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w)
- {
- }
-
- operator float *()
- {
- return &x;
- }
-
- friend float4 operator+(const float4 &a, const float &b)
- {
- return {a.x + b, a.y + b, a.z + b, a.w + b};
- }
-
- operator const float *() const
- {
- return &x;
- }
-
- float4 &operator+=(const float4 &other)
- {
- x += other.x;
- y += other.y;
- z += other.z;
- w += other.w;
- return *this;
- }
-
- friend float4 operator-(const float4 &a, const float4 &b)
- {
- return {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w};
- }
-
- friend float4 operator-(const float4 &a, const float &b)
- {
- return {a.x - b, a.y - b, a.z - b, a.w - b};
- }
-
- friend float4 operator+(const float4 &a, const float4 &b)
- {
- return {a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
- }
-
- friend float4 operator/(const float4 &a, float f)
- {
- BLI_assert(f != 0.0f);
- return a * (1.0f / f);
- }
-
- float4 &operator*=(float factor)
- {
- x *= factor;
- y *= factor;
- z *= factor;
- w *= factor;
- return *this;
- }
-
- friend float4 operator*(const float4 &a, float b)
- {
- return {a.x * b, a.y * b, a.z * b, a.w * b};
- }
-
- friend float4 operator*(float a, const float4 &b)
- {
- return b * a;
- }
-
- float length() const
- {
- return len_v4(*this);
- }
-
- static float distance(const float4 &a, const float4 &b)
- {
- return (a - b).length();
- }
-
- static float4 safe_divide(const float4 &a, const float b)
- {
- return (b != 0.0f) ? a / b : float4(0.0f);
- }
-
- static float4 interpolate(const float4 &a, const float4 &b, float t)
- {
- return a * (1 - t) + b * t;
- }
-
- static float4 floor(const float4 &a)
- {
- return float4(floorf(a.x), floorf(a.y), floorf(a.z), floorf(a.w));
- }
-
- static float4 normalize(const float4 &a)
- {
- const float t = len_v4(a);
- return (t != 0.0f) ? a / t : float4(0.0f);
- }
-};
-
-} // namespace blender
diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh
index b7f839f4ddf..81c969d02d0 100644
--- a/source/blender/blenlib/BLI_float4x4.hh
+++ b/source/blender/blenlib/BLI_float4x4.hh
@@ -16,8 +16,9 @@
#pragma once
-#include "BLI_float3.hh"
#include "BLI_math_matrix.h"
+#include "BLI_math_vec_types.hh"
+#include "BLI_math_vector.h"
namespace blender {
@@ -63,7 +64,7 @@ struct float4x4 {
* Without the negation, the result would be a so called improper rotation. That means it
* contains a reflection. Such an improper rotation matrix could not be converted to another
* representation of a rotation such as euler angles. */
- const float3 cross = -float3::cross(forward, up);
+ const float3 cross = -math::cross(forward, up);
float4x4 matrix;
matrix.values[0][0] = forward.x;
diff --git a/source/blender/blenlib/BLI_function_ref.hh b/source/blender/blenlib/BLI_function_ref.hh
index 71be7d7f029..c762756b474 100644
--- a/source/blender/blenlib/BLI_function_ref.hh
+++ b/source/blender/blenlib/BLI_function_ref.hh
@@ -80,6 +80,8 @@
*
*/
+#include "BLI_memory_utils.hh"
+
namespace blender {
template<typename Function> class FunctionRef;
@@ -125,8 +127,8 @@ template<typename Ret, typename... Params> class FunctionRef<Ret(Params...)> {
* another lambda.
*/
template<typename Callable,
- std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Callable>>,
- FunctionRef>> * = nullptr>
+ BLI_ENABLE_IF((
+ !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Callable>>, FunctionRef>))>
FunctionRef(Callable &&callable)
: callback_(callback_fn<typename std::remove_reference_t<Callable>>),
callable_(reinterpret_cast<intptr_t>(&callable))
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 0194f9aad40..1c5adb8ee82 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -99,7 +99,7 @@ enum {
GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
GHashCmpFP cmpfp,
const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/**
* Wraps #BLI_ghash_new_ex with zero entries reserved.
*/
@@ -124,7 +124,7 @@ void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreef
/**
* Reserve given amount of entries (resize \a gh accordingly if needed).
*/
-void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve);
+void BLI_ghash_reserve(GHash *gh, unsigned int nentries_reserve);
/**
* Insert a key/value pair into the \a gh.
*
@@ -226,7 +226,7 @@ void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfree
void BLI_ghash_clear_ex(GHash *gh,
GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp,
- const unsigned int nentries_reserve);
+ unsigned int nentries_reserve);
/**
* Remove \a key from \a gh, returning the value or NULL if the key wasn't found.
*
@@ -372,7 +372,7 @@ typedef GHashIterState GSetIterState;
GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_new(GSetHashFP hashfp,
GSetCmpFP cmpfp,
const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
@@ -428,7 +428,7 @@ bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
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);
-void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, const unsigned int nentries_reserve);
+void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, unsigned int nentries_reserve);
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp);
/* When set's are used for key & value. */
@@ -450,7 +450,7 @@ void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
/* rely on inline api for now */
-/* so we can cast but compiler sees as different */
+/** Use a GSet specific type so we can cast but compiler sees as different */
typedef struct GSetIterator {
GHashIterator _ghi
#if defined(__GNUC__) && !defined(__clang__)
@@ -630,30 +630,30 @@ void BLI_ghashutil_pairfree(void *ptr);
* Wrapper GHash Creation Functions
*/
-GHash *BLI_ghash_ptr_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_ptr_new_ex(const char *info,
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GHash *BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_str_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_str_new_ex(const char *info,
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GHash *BLI_ghash_str_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_int_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_int_new_ex(const char *info,
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GHash *BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_pair_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_pair_new_ex(const char *info,
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GHash *BLI_ghash_pair_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_ptr_new_ex(const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_ptr_new(const char *info);
GSet *BLI_gset_str_new_ex(const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_str_new(const char *info);
-GSet *BLI_gset_pair_new_ex(const char *info, const unsigned int nentries_reserve)
- ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GSet *BLI_gset_pair_new_ex(const char *info,
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_pair_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_int_new_ex(const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+ unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/** \} */
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
index 8b32c09b56b..a35c743c80b 100644
--- a/source/blender/blenlib/BLI_gsqueue.h
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -31,7 +31,7 @@ extern "C" {
typedef struct _GSQueue GSQueue;
-GSQueue *BLI_gsqueue_new(const size_t elem_size);
+GSQueue *BLI_gsqueue_new(size_t elem_size);
/**
* Returns true if the queue is empty, false otherwise.
*/
diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh
index 11ff7d040aa..9132aacf7b9 100644
--- a/source/blender/blenlib/BLI_hash.hh
+++ b/source/blender/blenlib/BLI_hash.hh
@@ -243,6 +243,16 @@ uint64_t get_default_hash_3(const T1 &v1, const T2 &v2, const T3 &v3)
return h1 ^ (h2 * 19349669) ^ (h3 * 83492791);
}
+template<typename T1, typename T2, typename T3, typename T4>
+uint64_t get_default_hash_4(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4)
+{
+ const uint64_t h1 = get_default_hash(v1);
+ const uint64_t h2 = get_default_hash(v2);
+ const uint64_t h3 = get_default_hash(v3);
+ const uint64_t h4 = get_default_hash(v4);
+ return h1 ^ (h2 * 19349669) ^ (h3 * 83492791) ^ (h4 * 3632623);
+}
+
template<typename T> struct DefaultHash<std::unique_ptr<T>> {
uint64_t operator()(const std::unique_ptr<T> &value) const
{
diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh
index 665f44468db..cc6040d49db 100644
--- a/source/blender/blenlib/BLI_index_range.hh
+++ b/source/blender/blenlib/BLI_index_range.hh
@@ -48,7 +48,7 @@
* Ideally this could be could be even closer to Python's enumerate(). We might get that in the
* future with newer C++ versions.
*
- * One other important feature is the as_span method. This method returns an Span<int64_t>
+ * One other important feature is the as_span method. This method returns a Span<int64_t>
* that contains the interval as individual numbers.
*/
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index 2f41be369c1..cee9ec4c0a8 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -137,7 +137,7 @@ typedef void (*BVHTree_NearestProjectedCallback)(void *userdata,
int index,
const struct DistProjectedAABBPrecalc *precalc,
const float (*clip_plane)[4],
- const int clip_plane_len,
+ int clip_plane_len,
BVHTreeNearest *nearest);
/* callbacks to BLI_bvhtree_walk_dfs */
@@ -200,8 +200,8 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(const BVHTree *tree1,
uint *r_overlap_tot,
BVHTree_OverlapCallback callback,
void *userdata,
- const uint max_interactions,
- const int flag);
+ uint max_interactions,
+ int flag);
BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
const BVHTree *tree2,
unsigned int *r_overlap_tot,
@@ -248,7 +248,7 @@ int BLI_bvhtree_find_nearest(BVHTree *tree,
*/
int BLI_bvhtree_find_nearest_first(BVHTree *tree,
const float co[3],
- const float dist_sq,
+ float dist_sq,
BVHTree_NearestPointCallback callback,
void *userdata);
diff --git a/source/blender/blenlib/BLI_kdtree_impl.h b/source/blender/blenlib/BLI_kdtree_impl.h
index 26a22fc2ac4..b15ae4a8a24 100644
--- a/source/blender/blenlib/BLI_kdtree_impl.h
+++ b/source/blender/blenlib/BLI_kdtree_impl.h
@@ -47,12 +47,12 @@ int BLI_kdtree_nd_(find_nearest)(const KDTree *tree,
int BLI_kdtree_nd_(find_nearest_n)(const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest *r_nearest,
- const uint nearest_len_capacity) ATTR_NONNULL(1, 2, 3);
+ uint nearest_len_capacity) ATTR_NONNULL(1, 2, 3);
int BLI_kdtree_nd_(range_search)(const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest **r_nearest,
- const float range) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
+ float range) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
int BLI_kdtree_nd_(find_nearest_cb)(
const KDTree *tree,
@@ -68,18 +68,18 @@ void BLI_kdtree_nd_(range_search_cb)(
void *user_data);
int BLI_kdtree_nd_(calc_duplicates_fast)(const KDTree *tree,
- const float range,
+ float range,
bool use_index_order,
int *doubles);
int BLI_kdtree_nd_(deduplicate)(KDTree *tree);
-/* Versions of find/range search that take a squared distance callback to support bias. */
+/** Versions of find/range search that take a squared distance callback to support bias. */
int BLI_kdtree_nd_(find_nearest_n_with_len_squared_cb)(
const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest *r_nearest,
- const uint nearest_len_capacity,
+ uint nearest_len_capacity,
float (*len_sq_fn)(const float co_search[KD_DIMS],
const float co_test[KD_DIMS],
const void *user_data),
@@ -88,7 +88,7 @@ int BLI_kdtree_nd_(range_search_with_len_squared_cb)(
const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest **r_nearest,
- const float range,
+ float range,
float (*len_sq_fn)(const float co_search[KD_DIMS],
const float co_test[KD_DIMS],
const void *user_data),
diff --git a/source/blender/blenlib/BLI_lasso_2d.h b/source/blender/blenlib/BLI_lasso_2d.h
index 5f034bfdc1d..2e4a2ed22b4 100644
--- a/source/blender/blenlib/BLI_lasso_2d.h
+++ b/source/blender/blenlib/BLI_lasso_2d.h
@@ -29,22 +29,19 @@ extern "C" {
struct rcti;
-void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], const unsigned int mcoords_len);
-bool BLI_lasso_is_point_inside(const int mcoords[][2],
- const unsigned int mcoords_len,
- const int sx,
- const int sy,
- const int error_value);
+void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], unsigned int mcoords_len);
+bool BLI_lasso_is_point_inside(
+ const int mcoords[][2], unsigned int mcoords_len, int sx, int sy, 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,
+ unsigned int mcoords_len,
int x0,
int y0,
int x1,
int y1,
- const int error_value);
+ int error_value);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_linklist_lockfree.h b/source/blender/blenlib/BLI_linklist_lockfree.h
index 142fa1cf243..d2083bdd44e 100644
--- a/source/blender/blenlib/BLI_linklist_lockfree.h
+++ b/source/blender/blenlib/BLI_linklist_lockfree.h
@@ -48,18 +48,19 @@ typedef void (*LockfreeeLinkNodeFreeFP)(void *link);
/* NOTE: These functions are NOT safe for use from threads. */
/* NOTE: !!! I REPEAT: DO NOT USE THEM WITHOUT EXTERNAL LOCK !!! */
-/* Make list ready for lock-free access. */
+/** Make list ready for lock-free access. */
void BLI_linklist_lockfree_init(LockfreeLinkList *list);
-/* Completely free the whole list, it is NOT re-usable after this. */
+/** Completely free the whole list, it is NOT re-usable after this. */
void BLI_linklist_lockfree_free(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func);
-/* Remove all the elements from the list, keep it usable for further
- * inserts.
+/**
+ * Remove all the elements from the list, keep it usable for further inserts.
*/
void BLI_linklist_lockfree_clear(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func);
-/* Begin iteration of lock-free linked list, starting with a
+/**
+ * Begin iteration of lock-free linked list, starting with a
* first user=defined node. Will ignore the dummy node.
*/
LockfreeLinkNode *BLI_linklist_lockfree_begin(LockfreeLinkList *list);
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 7d808d339e9..f73d1f22502 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -44,7 +44,12 @@ int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_
*/
int BLI_findstringindex(const struct ListBase *listbase,
const char *id,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+
+/**
+ * Return a ListBase representing the entire list the given Link is in.
+ */
+ListBase BLI_listbase_from_link(struct Link *some_link);
/* Find forwards. */
@@ -59,29 +64,29 @@ void *BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED
*/
void *BLI_findstring(const struct ListBase *listbase,
const char *id,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ 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);
+ 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);
+ 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);
+ size_t bytes_size,
+ 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.
*
@@ -91,8 +96,8 @@ void *BLI_listbase_bytes_find(const ListBase *listbase,
*/
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);
+ size_t string_offset,
+ int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/* Find backwards. */
@@ -107,29 +112,29 @@ void *BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSE
*/
void *BLI_rfindstring(const struct ListBase *listbase,
const char *id,
- const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ 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);
+ 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);
+ 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);
+ size_t bytes_size,
+ int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
/**
* Removes and disposes of the entire contents of \a listbase using guardedalloc.
@@ -216,7 +221,7 @@ void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
* \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);
+ int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Returns the number of elements in \a listbase.
*/
@@ -279,6 +284,23 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
}
/**
+ * Equality check for ListBase.
+ *
+ * This only shallowly compares the ListBase itself (so the first/last
+ * pointers), and does not do any equality checks on the list items.
+ */
+BLI_INLINE bool BLI_listbase_equal(const struct ListBase *a, const struct ListBase *b)
+{
+ if (a == NULL) {
+ return b == NULL;
+ }
+ if (b == NULL) {
+ return false;
+ }
+ return a->first == b->first && a->last == b->last;
+}
+
+/**
* Create a generic list node containing link to provided data.
*/
struct LinkData *BLI_genericNodeN(void *data);
@@ -353,3 +375,10 @@ struct LinkData *BLI_genericNodeN(void *data);
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+BLI_INLINE bool operator==(const ListBase &a, const ListBase &b)
+{
+ return BLI_listbase_equal(&a, &b);
+}
+#endif
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 83822481112..f6462233106 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -76,8 +76,7 @@
#if defined(__GNUC__)
# define NAN_FLT __builtin_nanf("")
-#else
-/* evil quiet NaN definition */
+#else /* evil quiet NaN definition */
static const int NAN_INT = 0x7FC00000;
# define NAN_FLT (*((float *)(&NAN_INT)))
#endif
@@ -97,7 +96,8 @@ extern "C" {
/******************************* Float ******************************/
-/* powf is really slow for raising to integer powers. */
+/* `powf` is really slow for raising to integer powers. */
+
MINLINE float pow2f(float x);
MINLINE float pow3f(float x);
MINLINE float pow4f(float x);
@@ -183,7 +183,7 @@ MINLINE size_t clamp_z(size_t value, size_t min, size_t max);
*
* \param max_diff: the maximum absolute difference.
*/
-MINLINE int compare_ff(float a, float b, const float max_diff);
+MINLINE int compare_ff(float a, float b, float max_diff);
/**
* Almost-equal for IEEE floats, using their integer representation
* (mixing ULP and absolute difference methods).
@@ -195,10 +195,8 @@ MINLINE int compare_ff(float a, float b, const float max_diff);
*
* \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,
- const float thresh);
+MINLINE int compare_ff_relative(float a, float b, float max_diff, int max_ulps);
+MINLINE bool compare_threshold_relative(float value1, float value2, float thresh);
MINLINE float signf(float f);
MINLINE int signum_i_ex(float a, float eps);
@@ -213,13 +211,13 @@ 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);
+MINLINE int integer_digits_f(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);
+MINLINE int integer_digits_d(double d);
+MINLINE int integer_digits_i(int i);
/* These don't really fit anywhere but were being copied about a lot. */
diff --git a/source/blender/blenlib/BLI_math_bits.h b/source/blender/blenlib/BLI_math_bits.h
index e881f1a0e4e..70a54879446 100644
--- a/source/blender/blenlib/BLI_math_bits.h
+++ b/source/blender/blenlib/BLI_math_bits.h
@@ -28,24 +28,29 @@ extern "C" {
#endif
/* Search the value from LSB to MSB for a set bit. Returns index of this bit. */
+
MINLINE int bitscan_forward_i(int a);
MINLINE unsigned int bitscan_forward_uint(unsigned int a);
MINLINE unsigned int bitscan_forward_uint64(unsigned long long a);
/* Similar to above, but also clears the bit. */
+
MINLINE int bitscan_forward_clear_i(int *a);
MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a);
/* Search the value from MSB to LSB for a set bit. Returns index of this bit. */
+
MINLINE int bitscan_reverse_i(int a);
MINLINE unsigned int bitscan_reverse_uint(unsigned int a);
MINLINE unsigned int bitscan_reverse_uint64(unsigned long long a);
/* Similar to above, but also clears the bit. */
+
MINLINE int bitscan_reverse_clear_i(int *a);
MINLINE unsigned int bitscan_reverse_clear_uint(unsigned int *a);
/* NOTE: Those functions returns 2 to the power of index of highest order bit. */
+
MINLINE unsigned int highest_order_bit_uint(unsigned int n);
MINLINE unsigned short highest_order_bit_s(unsigned short n);
diff --git a/source/blender/blenlib/BLI_math_boolean.hh b/source/blender/blenlib/BLI_math_boolean.hh
index 20fd00b2aa4..8cf93c82dec 100644
--- a/source/blender/blenlib/BLI_math_boolean.hh
+++ b/source/blender/blenlib/BLI_math_boolean.hh
@@ -21,13 +21,11 @@
* \brief Math vector functions needed specifically for mesh intersect and boolean.
*/
-#include "BLI_double2.hh"
-#include "BLI_double3.hh"
+#include "BLI_math_vec_types.hh"
#ifdef WITH_GMP
# include "BLI_math_mpq.hh"
-# include "BLI_mpq2.hh"
-# include "BLI_mpq3.hh"
+# include "BLI_math_vec_mpq_types.hh"
#endif
namespace blender {
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 32424f37676..0798acbb790 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -107,7 +107,7 @@ MINLINE void linearrgb_to_srgb_v4(float srgb[4], const float linear[4]);
MINLINE void srgb_to_linearrgb_predivide_v4(float linear[4], const float srgb[4]);
MINLINE void linearrgb_to_srgb_predivide_v4(float srgb[4], const float linear[4]);
-MINLINE unsigned short to_srgb_table_lookup(const float f);
+MINLINE unsigned short to_srgb_table_lookup(float f);
MINLINE void linearrgb_to_srgb_ushort4(unsigned short srgb[4], const float linear[4]);
MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4]);
MINLINE void srgb_to_linearrgb_uchar4_predivide(float linear[4], const unsigned char srgb[4]);
@@ -182,7 +182,7 @@ void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4]);
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);
+MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], int limit);
/**
* Return triangle noise in [-0.5..1.5] range.
@@ -197,19 +197,12 @@ MINLINE void float_to_byte_dither_v3(
#define rgba_float_args_set_ch(col, r, g, b, a) \
rgba_float_args_set(col, (r) / 255.0f, (g) / 255.0f, (b) / 255.0f, (a) / 255.0f)
-MINLINE void rgba_uchar_args_set(unsigned char col[4],
- const unsigned char r,
- const unsigned char g,
- const unsigned char b,
- const unsigned char a);
-MINLINE void rgba_float_args_set(
- float col[4], const float r, const float g, const float b, const float a);
-MINLINE void rgba_uchar_args_test_set(unsigned char col[4],
- const unsigned char r,
- const unsigned char g,
- const unsigned char b,
- const unsigned char a);
-MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack);
+MINLINE void rgba_uchar_args_set(
+ unsigned char col[4], unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+MINLINE void rgba_float_args_set(float col[4], float r, float g, float b, float a);
+MINLINE void rgba_uchar_args_test_set(
+ unsigned char col[4], unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+MINLINE void cpack_cpy_3ub(unsigned char r_col[3], 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);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 55d118d17de..6d7159f73c6 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -372,8 +372,8 @@ void closest_on_tri_to_point_v3(
float ray_point_factor_v3_ex(const float p[3],
const float ray_origin[3],
const float ray_direction[3],
- const float epsilon,
- const float fallback);
+ float epsilon,
+ float fallback);
float ray_point_factor_v3(const float p[3],
const float ray_origin[3],
const float ray_direction[3]);
@@ -385,18 +385,12 @@ float ray_point_factor_v3(const float p[3],
* \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],
- const float epsilon,
- const float fallback);
+float line_point_factor_v3_ex(
+ const float p[3], const float l1[3], const float l2[3], float epsilon, float fallback);
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3]);
-float line_point_factor_v2_ex(const float p[2],
- const float l1[2],
- const float l2[2],
- const float epsilon,
- const float fallback);
+float line_point_factor_v2_ex(
+ const float p[2], const float l1[2], const float l2[2], float epsilon, float fallback);
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]);
/**
@@ -411,7 +405,7 @@ float line_plane_factor_v3(const float plane_co[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);
+void limit_dist_v3(float v1[3], float v2[3], float dist);
/** \} */
@@ -441,7 +435,9 @@ void isect_seg_seg_v3(const float a0[3],
float r_a[3],
float r_b[3]);
-/* intersect Line-Line, shorts */
+/**
+ * Intersect Line-Line, integer.
+ */
int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2]);
/**
* Get intersection point of two 2D segments.
@@ -460,7 +456,7 @@ int isect_seg_seg_v2_point_ex(const float v0[2],
const float v1[2],
const float v2[2],
const float v3[2],
- const float endpoint_bias,
+ float endpoint_bias,
float vi[2]);
int isect_seg_seg_v2_point(
const float v0[2], const float v1[2], const float v2[2], const float v3[2], float vi[2]);
@@ -502,13 +498,13 @@ int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
int isect_line_sphere_v3(const float l1[3],
const float l2[3],
const float sp[3],
- const float r,
+ float r,
float r_p1[3],
float r_p2[3]);
int isect_line_sphere_v2(const float l1[2],
const float l2[2],
const float sp[2],
- const float r,
+ float r,
float r_p1[2],
float r_p2[2]);
@@ -529,7 +525,7 @@ int isect_line_line_epsilon_v3(const float v1[3],
const float v4[3],
float i1[3],
float i2[3],
- const float epsilon);
+ float epsilon);
int isect_line_line_v3(const float v1[3],
const float v2[3],
const float v3[3],
@@ -556,7 +552,7 @@ bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
const float ray_direction_a[3],
const float ray_origin_b[3],
const float ray_direction_b[3],
- const float epsilon,
+ float epsilon,
float *r_lambda_a,
float *r_lambda_b);
bool isect_ray_ray_v3(const float ray_origin_a[3],
@@ -576,7 +572,7 @@ 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);
+ bool clip);
/**
* Check if a point is behind all planes.
@@ -586,7 +582,7 @@ 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]);
+bool isect_point_planes_v3_negated(const float (*planes)[4], int totplane, const float p[3]);
/**
* Intersect line/plane.
@@ -647,9 +643,9 @@ bool isect_plane_plane_v3(const float plane_a[4],
*/
bool isect_planes_v3_fn(
const float planes[][4],
- const int planes_len,
- const float eps_coplanar,
- const float eps_isect,
+ int planes_len,
+ float eps_coplanar,
+ float eps_isect,
void (*callback_fn)(const float co[3], int i, int j, int k, void *user_data),
void *user_data);
@@ -676,8 +672,8 @@ bool isect_line_segment_tri_epsilon_v3(const float p1[3],
const float v2[3],
float *r_lambda,
float r_uv[2],
- const float epsilon);
-bool isect_axial_line_segment_tri_v3(const int axis,
+ float epsilon);
+bool isect_axial_line_segment_tri_v3(int axis,
const float p1[3],
const float p2[3],
const float v0[3],
@@ -703,7 +699,7 @@ bool isect_ray_tri_threshold_v3(const float ray_origin[3],
const float v2[3],
float *r_lambda,
float r_uv[2],
- const float threshold);
+ float threshold);
bool isect_ray_tri_epsilon_v3(const float ray_origin[3],
const float ray_direction[3],
const float v0[3],
@@ -711,7 +707,7 @@ bool isect_ray_tri_epsilon_v3(const float ray_origin[3],
const float v2[3],
float *r_lambda,
float r_uv[2],
- const float epsilon);
+ float epsilon);
/**
* Intersect two triangles.
*
@@ -791,12 +787,12 @@ bool isect_ray_line_v3(const float ray_origin[3],
bool isect_point_poly_v2(const float pt[2],
const float verts[][2],
- const unsigned int nr,
- const bool use_holes);
+ unsigned int nr,
+ bool use_holes);
bool isect_point_poly_v2_int(const int pt[2],
const int verts[][2],
- const unsigned int nr,
- const bool use_holes);
+ unsigned int nr,
+ bool use_holes);
/**
* Point in quad - only convex quads.
@@ -821,8 +817,7 @@ bool isect_point_tri_v2_cw(const float pt[2],
* 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);
+int isect_point_tri_v2_int(int x1, int y1, int x2, int y2, int a, int b);
bool isect_point_tri_prism_v3(const float p[3],
const float v1[3],
const float v2[3],
@@ -888,13 +883,13 @@ bool isect_ray_aabb_v3_simple(const float orig[3],
* - 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,
+ int totplane,
const float bbmin[3],
const float bbmax[3]);
bool isect_sweeping_sphere_tri_v3(const float p1[3],
const float p2[3],
- const float radius,
+ float radius,
const float v0[3],
const float v1[3],
const float v2[3],
@@ -906,7 +901,7 @@ bool clip_segment_v3_plane(
bool clip_segment_v3_plane_n(const float p1[3],
const float p2[3],
const float plane_array[][4],
- const int plane_tot,
+ int plane_tot,
float r_p1[3],
float r_p2[3]);
@@ -926,23 +921,23 @@ void interp_weights_quad_v3(float w[4],
const float v3[3],
const float v4[3],
const float co[3]);
-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]);
+void interp_weights_poly_v3(float w[], float v[][3], int n, const float co[3]);
+void interp_weights_poly_v2(float w[], float v[][2], int n, const float co[2]);
-/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */
+/** `(x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t)`. */
void interp_cubic_v3(float x[3],
float v[3],
const float x1[3],
const float v1[3],
const float x2[3],
const float v2[3],
- const float t);
+ 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);
+int interp_sparse_array(float *array, int list_size, float skipval);
/**
* Given 2 triangles in 3D space, and a point in relation to the first triangle.
@@ -1079,34 +1074,34 @@ void polarview_m4(float mat[4][4], float dist, float azimuth, float incidence, f
* Matches `glFrustum` result.
*/
void perspective_m4(float mat[4][4],
- const float left,
- const float right,
- const float bottom,
- const float top,
- const float nearClip,
- const float farClip);
+ float left,
+ float right,
+ float bottom,
+ float top,
+ float nearClip,
+ float farClip);
void perspective_m4_fov(float mat[4][4],
- const float angle_left,
- const float angle_right,
- const float angle_up,
- const float angle_down,
- const float nearClip,
- const float farClip);
+ float angle_left,
+ float angle_right,
+ float angle_up,
+ float angle_down,
+ float nearClip,
+ float farClip);
/**
* Matches `glOrtho` result.
*/
void orthographic_m4(float mat[4][4],
- const float left,
- const float right,
- const float bottom,
- const float top,
- const float nearClip,
- const float farClip);
+ float left,
+ float right,
+ float bottom,
+ float top,
+ float nearClip,
+ 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);
+void window_translate_m4(float winmat[4][4], float perspmat[4][4], float x, float y);
/**
* Frustum planes extraction from a projection matrix
@@ -1147,10 +1142,10 @@ void projmat_dimensions_db(const float winmat[4][4],
*/
void projmat_from_subregion(const float projmat[4][4],
const int win_size[2],
- const int x_min,
- const int x_max,
- const int y_min,
- const int y_max,
+ int x_min,
+ int x_max,
+ int y_min,
+ int y_max,
float r_projmat[4][4]);
int box_clip_bounds_m4(float boundbox[2][3], const float bounds[4], float winmat[4][4]);
@@ -1162,13 +1157,13 @@ void box_minmax_bounds_m4(float min[3], float max[3], float boundbox[2][3], floa
/** \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);
+void map_to_tube(float *r_u, float *r_v, float x, float y, float z);
+void map_to_sphere(float *r_u, float *r_v, float x, float y, float z);
void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3]);
void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2],
const float co[3],
const float axis[3],
- const float angle);
+ float angle);
/** \} */
@@ -1198,11 +1193,8 @@ 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,
- float vdiffs[][3],
- const int nverts);
+void accumulate_vertex_normals_poly_v3(
+ float **vertnos, const float polyno[3], const float **vertcos, float vdiffs[][3], int nverts);
/** \} */
@@ -1244,7 +1236,7 @@ void tangent_from_uv_v3(const float uv1[2],
*
* pointers may be NULL if not needed
*/
-void vcloud_estimate_transform_v3(const int list_size,
+void vcloud_estimate_transform_v3(int list_size,
const float (*pos)[3],
const float *weight,
const float (*rpos)[3],
@@ -1267,14 +1259,14 @@ void vcloud_estimate_transform_v3(const int list_size,
MINLINE void zero_sh(float r[9]);
MINLINE void copy_sh_sh(float r[9], const float a[9]);
-MINLINE void mul_sh_fl(float r[9], const float f);
+MINLINE void mul_sh_fl(float r[9], float f);
MINLINE void add_sh_shsh(float r[9], const float a[9], const float b[9]);
MINLINE float dot_shsh(const float a[9], const float b[9]);
MINLINE float eval_shv3(float r[9], const float v[3]);
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);
+MINLINE void vec_fac_to_sh(float r[9], const float v[3], float f);
+MINLINE void madd_sh_shfl(float r[9], const float sh[9], float f);
/** \} */
@@ -1347,7 +1339,7 @@ MINLINE int min_axis_v3(const float vec[3]);
* (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);
+MINLINE int poly_to_tri_count(int poly_count, int corner_count);
/**
* Useful to calculate an even width shell, by taking the angle between 2 planes.
@@ -1355,7 +1347,7 @@ MINLINE int poly_to_tri_count(const int poly_count, const int corner_count);
* 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);
+MINLINE float shell_angle_to_dist(float angle);
/**
* Equivalent to `shell_angle_to_dist(angle_normalized_v3v3(a, b))`.
*/
@@ -1404,7 +1396,7 @@ float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
* 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);
+ const float v0[3], const float v1[3], const float v2[3], float dist1, float dist2);
/** \} */
diff --git a/source/blender/blenlib/BLI_math_interp.h b/source/blender/blenlib/BLI_math_interp.h
index 7179de12066..0af250064f6 100644
--- a/source/blender/blenlib/BLI_math_interp.h
+++ b/source/blender/blenlib/BLI_math_interp.h
@@ -81,10 +81,10 @@ void BLI_ewa_imp2radangle(
* 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,
- const int height,
- const bool intpol,
- const bool use_alpha,
+void BLI_ewa_filter(int width,
+ int height,
+ bool intpol,
+ bool use_alpha,
const float uv[2],
const float du[2],
const float dv[2],
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index cdbc0cb0283..03b6ff25a4f 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -56,16 +56,18 @@ void copy_m4_m2(float m1[4][4], const float m2[2][2]);
void copy_m4_m4_db(double m1[4][4], const double m2[4][4]);
/* double->float */
+
void copy_m3_m3d(float m1[3][3], const double m2[3][3]);
/* float->double */
+
void copy_m3d_m3(double m1[3][3], const float m2[3][3]);
void copy_m4d_m4(double m1[4][4], const float m2[4][4]);
void swap_m3m3(float m1[3][3], float m2[3][3]);
void swap_m4m4(float m1[4][4], float m2[4][4]);
-/* Build index shuffle matrix */
+/** Build index shuffle matrix. */
void shuffle_m4(float R[4][4], const int index[4]);
/** \} */
@@ -77,8 +79,8 @@ void shuffle_m4(float R[4][4], const int index[4]);
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]);
-void madd_m3_m3m3fl(float R[3][3], const float A[3][3], const float B[3][3], const float f);
-void madd_m4_m4m4fl(float R[4][4], const float A[4][4], const float B[4][4], const float f);
+void madd_m3_m3m3fl(float R[3][3], const float A[3][3], const float B[3][3], float f);
+void madd_m4_m4m4fl(float R[4][4], const float A[4][4], const float B[4][4], float f);
void sub_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
void sub_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
@@ -112,7 +114,8 @@ void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B
void mul_m4_m4_pre(float R[4][4], const float A[4][4]);
void mul_m4_m4_post(float R[4][4], const float B[4][4]);
-/* mul_m3_series */
+/* Implement #mul_m3_series macro. */
+
void _va_mul_m3_series_3(float R[3][3], const float M1[3][3], const float M2[3][3]) ATTR_NONNULL();
void _va_mul_m3_series_4(float R[3][3],
const float M1[3][3],
@@ -153,7 +156,9 @@ void _va_mul_m3_series_9(float R[3][3],
const float M6[3][3],
const float M7[3][3],
const float M8[3][3]) ATTR_NONNULL();
-/* mul_m4_series */
+
+/* Implement #mul_m4_series macro. */
+
void _va_mul_m4_series_3(float R[4][4], const float M1[4][4], const float M2[4][4]) ATTR_NONNULL();
void _va_mul_m4_series_4(float R[4][4],
const float M1[4][4],
@@ -247,8 +252,8 @@ void negate_m3(float R[3][3]);
void negate_mat3_m4(float R[4][4]);
void negate_m4(float R[4][4]);
-bool invert_m3_ex(float m[3][3], const float epsilon);
-bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], const float epsilon);
+bool invert_m3_ex(float m[3][3], float epsilon);
+bool invert_m3_m3_ex(float m1[3][3], const float m2[3][3], float epsilon);
bool invert_m3(float R[3][3]);
bool invert_m3_m3(float R[3][3], const float A[3][3]);
@@ -266,11 +271,13 @@ bool invert_m4_m4(float R[4][4], const float A[4][4]);
*/
bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]);
-/* double arithmetic (mixed float/double) */
+/* Double arithmetic (mixed float/double). */
+
void mul_m4_v4d(const float M[4][4], double r[4]);
void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]);
-/* double matrix functions (no mixing types) */
+/* Double matrix functions (no mixing types). */
+
void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]);
void mul_m3_v3_db(const double M[3][3], double r[3]);
@@ -282,7 +289,9 @@ void mul_m3_v3_db(const double M[3][3], double r[3]);
void transpose_m3(float R[3][3]);
void transpose_m3_m3(float R[3][3], const float M[3][3]);
-/* seems obscure but in-fact a common operation */
+/**
+ * \note Seems obscure but in-fact a common operation.
+ */
void transpose_m3_m4(float R[3][3], const float M[4][4]);
void transpose_m4(float R[4][4]);
void transpose_m4_m4(float R[4][4], const float M[4][4]);
@@ -334,8 +343,8 @@ void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize);
*/
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);
-bool orthogonalize_m4_zero_axes(float R[4][4], const float unit_length);
+bool orthogonalize_m3_zero_axes(float R[3][3], float unit_length);
+bool orthogonalize_m4_zero_axes(float R[4][4], float unit_length);
bool is_orthogonal_m3(const float mat[3][3]);
bool is_orthogonal_m4(const float mat[4][4]);
@@ -435,7 +444,7 @@ void translate_m4(float mat[4][4], float tx, float ty, float tz);
* #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);
+void rotate_m4(float mat[4][4], char axis, float angle);
/** Scale a matrix in-place. */
void rescale_m4(float mat[4][4], const float scale[3]);
/**
@@ -479,7 +488,7 @@ void loc_eul_size_to_mat4(float R[4][4],
* 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);
+ float R[4][4], const float loc[3], const float eul[3], const float size[3], short order);
/**
* Make a 4x4 matrix out of 3 transform components.
* Matrices are made in the order: `scale * rot * loc`
@@ -488,20 +497,11 @@ void loc_quat_size_to_mat4(float R[4][4],
const float loc[3],
const float quat[4],
const float size[3]);
-void loc_axisangle_size_to_mat4(float R[4][4],
- const float loc[3],
- const float axis[3],
- const float angle,
- const float size[3]);
-
-void blend_m3_m3m3(float out[3][3],
- const float dst[3][3],
- const float src[3][3],
- const float srcweight);
-void blend_m4_m4m4(float out[4][4],
- const float dst[4][4],
- const float src[4][4],
- const float srcweight);
+void loc_axisangle_size_to_mat4(
+ float R[4][4], const float loc[3], const float axis[3], float angle, const float size[3]);
+
+void blend_m3_m3m3(float out[3][3], const float dst[3][3], const float src[3][3], float srcweight);
+void blend_m4_m4m4(float out[4][4], const float dst[4][4], const float src[4][4], float srcweight);
/**
* A polar-decomposition-based interpolation between matrix A and matrix B.
@@ -519,7 +519,7 @@ void blend_m4_m4m4(float out[4][4],
* \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);
+void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], float t);
/**
* Complete transform matrix interpolation,
* based on polar-decomposition-based interpolation from #interp_m3_m3m3.
@@ -529,7 +529,7 @@ void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], con
* \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);
+void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], float t);
bool is_negative_m3(const float mat[3][3]);
bool is_negative_m4(const float mat[4][4]);
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 5e72d502262..c27cf71ce5f 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -57,7 +57,8 @@ void unit_axis_angle(float axis[3], float *angle);
void unit_qt(float q[4]);
void copy_qt_qt(float q[4], const float a[4]);
-/* arithmetic */
+/* Arithmetic. */
+
void mul_qt_qtqt(float q[4], const float a[4], const float b[4]);
/**
* \note
@@ -82,12 +83,12 @@ void mul_qt_v3(const float q[4], float r[3]);
/**
* Simple multiply.
*/
-void mul_qt_fl(float q[4], const float f);
+void mul_qt_fl(float q[4], float f);
/**
* Raise a unit quaternion to the specified power.
*/
-void pow_qt_fl_normalized(float q[4], const float f);
+void pow_qt_fl_normalized(float q[4], float f);
void sub_qt_qtqt(float q[4], const float a[4], const float b[4]);
@@ -106,7 +107,8 @@ float dot_qtqt(const float a[4], const float b[4]);
float normalize_qt(float q[4]);
float normalize_qt_qt(float r[4], const float q[4]);
-/* comparison */
+/* Comparison. */
+
bool is_zero_qt(const float q[4]);
/* interpolation */
@@ -118,11 +120,12 @@ bool is_zero_qt(const float q[4]);
* \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);
+void interp_dot_slerp(float t, float cosom, float r_w[2]);
+void interp_qt_qtqt(float q[4], const float a[4], const float b[4], float t);
+void add_qt_qtqt(float q[4], const float a[4], const float b[4], float t);
+
+/* Conversion. */
-/* conversion */
void quat_to_mat3(float mat[3][3], const float q[4]);
void quat_to_mat4(float mat[4][4], const float q[4]);
@@ -149,7 +152,7 @@ void tri_to_quat_ex(float quat[4],
* \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);
+void vec_to_quat(float q[4], const float vec[3], short axis, short upflag);
/**
* Calculate a rotation matrix from 2 normalized vectors.
* \note `v1` and `v2` must be normalized.
@@ -188,7 +191,8 @@ float angle_signed_qtqt(const float q1[4], const float q2[4]);
*/
void mat3_to_quat_is_ok(float q[4], const float mat[3][3]);
-/* other */
+/* Other. */
+
void print_qt(const char *str, const float q[4]);
#define print_qt_id(q) print_qt(STRINGIFY(q), q)
@@ -199,13 +203,14 @@ void print_qt(const char *str, const float q[4]);
/** \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);
+/* Conversion. */
+
+void axis_angle_normalized_to_quat(float r[4], const float axis[3], float angle);
+void axis_angle_to_quat(float r[4], const float axis[3], 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);
+void axis_angle_to_mat3(float R[3][3], const float axis[3], float angle);
/**
* axis angle to 3x3 matrix
*
@@ -217,13 +222,13 @@ void axis_angle_to_mat3(float R[3][3], const float axis[3], const float 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);
+ float angle_sin,
+ float angle_cos);
+void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], 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);
+void axis_angle_to_mat4(float R[4][4], const float axis[3], float angle);
/**
* 3x3 matrix to axis angle.
@@ -243,17 +248,17 @@ void mat4_to_axis_angle(float axis[3], float *angle, const float M[4][4]);
*/
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);
+void angle_to_mat2(float R[2][2], 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);
+void axis_angle_to_mat3_single(float R[3][3], char axis, 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_mat4_single(float R[4][4], char axis, float angle);
-void axis_angle_to_quat_single(float q[4], const char axis, const float angle);
+void axis_angle_to_quat_single(float q[4], char axis, float angle);
/** \} */
@@ -271,34 +276,27 @@ void expmap_to_quat(float r[4], const float expmap[3]);
/** \name XYZ Eulers
* \{ */
-/* XYZ order. */
void eul_to_quat(float quat[4], const float eul[3]);
-/* XYZ order */
void eul_to_mat3(float mat[3][3], const float eul[3]);
-/* XYZ order */
void eul_to_mat4(float mat[4][4], const float eul[3]);
-/* XYZ order */
void mat3_normalized_to_eul(float eul[3], const float mat[3][3]);
-/* XYZ order */
void mat4_normalized_to_eul(float eul[3], const float mat[4][4]);
void mat3_to_eul(float eul[3], const float mat[3][3]);
void mat4_to_eul(float eul[3], const float mat[4][4]);
-/* XYZ order */
void quat_to_eul(float eul[3], const float quat[4]);
-/* XYZ order */
void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]);
-/* order independent! */
-void compatible_eul(float eul[3], const float old[3]);
+void rotate_eul(float eul[3], char axis, float angle);
+
+/* Order independent. */
-/* XYZ order */
-void rotate_eul(float eul[3], const char axis, const float angle);
+void compatible_eul(float eul[3], const float old[3]);
-void add_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
-void sub_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
+void add_eul_euleul(float r_eul[3], float a[3], float b[3], short order);
+void sub_eul_euleul(float r_eul[3], float a[3], float b[3], short order);
/** \} */
@@ -323,67 +321,58 @@ typedef enum eEulerRotationOrders {
/**
* Construct quaternion from Euler angles (in radians).
*/
-void eulO_to_quat(float quat[4], const float eul[3], const short order);
+void eulO_to_quat(float quat[4], const float eul[3], 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);
+void eulO_to_mat3(float mat[3][3], const float eul[3], 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);
+void eulO_to_mat4(float mat[4][4], const float eul[3], short order);
/**
* Euler Rotation to Axis Angle.
*/
-void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const short order);
+void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], 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);
+void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], 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]);
+void mat3_normalized_to_eulO(float eul[3], 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]);
+void mat4_normalized_to_eulO(float eul[3], short order, const float mat[4][4]);
+void mat3_to_eulO(float eul[3], short order, const float mat[3][3]);
+void mat4_to_eulO(float eul[3], 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]);
+void quat_to_eulO(float eul[3], 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);
+void axis_angle_to_eulO(float eul[3], short order, const float axis[3], 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,
+ short order,
const float mat[3][3]);
void mat4_normalized_to_compatible_eulO(float eul[3],
const float old[3],
- const short order,
+ short order,
const float mat[4][4]);
-void mat3_to_compatible_eulO(float eul[3],
- const float old[3],
- const short order,
- const float mat[3][3]);
-void mat4_to_compatible_eulO(float eul[3],
- const float old[3],
- const short order,
- const float mat[4][4]);
-void quat_to_compatible_eulO(float eul[3],
- const float old[3],
- const short order,
- const float quat[4]);
-
-void rotate_eulO(float eul[3], const short order, char axis, float angle);
+void mat3_to_compatible_eulO(float eul[3], const float old[3], short order, const float mat[3][3]);
+void mat4_to_compatible_eulO(float eul[3], const float old[3], short order, const float mat[4][4]);
+void quat_to_compatible_eulO(float eul[3], const float old[3], short order, const float quat[4]);
+
+void rotate_eulO(float eul[3], short order, char axis, float angle);
/** \} */
diff --git a/source/blender/blenlib/BLI_math_solvers.h b/source/blender/blenlib/BLI_math_solvers.h
index 32d4577899c..ca413d2b49c 100644
--- a/source/blender/blenlib/BLI_math_solvers.h
+++ b/source/blender/blenlib/BLI_math_solvers.h
@@ -77,7 +77,7 @@ void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3
* \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);
+ const float *a, const float *b, const float *c, const float *d, float *r_x, int count);
/**
* \brief Solve a possibly cyclic tridiagonal system using the Sherman-Morrison formula.
*
@@ -85,7 +85,7 @@ bool BLI_tridiagonal_solve(
* \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);
+ const float *a, const float *b, const float *c, const float *d, float *r_x, int count);
/**
* Generic 3 variable Newton's method solver.
diff --git a/source/blender/blenlib/BLI_math_statistics.h b/source/blender/blenlib/BLI_math_statistics.h
index e4524b49f3f..586c82a8844 100644
--- a/source/blender/blenlib/BLI_math_statistics.h
+++ b/source/blender/blenlib/BLI_math_statistics.h
@@ -51,11 +51,11 @@ extern "C" {
* (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,
+void BLI_covariance_m_vn_ex(int n,
const float *cos_vn,
- const int nbr_cos_vn,
+ int nbr_cos_vn,
const float *center,
- const bool use_sample_correction,
+ bool use_sample_correction,
float *r_covmat);
/**
* \brief Compute the covariance matrix of given set of 3D coordinates.
@@ -66,8 +66,8 @@ void BLI_covariance_m_vn_ex(const int n,
* \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,
+ int nbr_cos_v3,
+ bool use_sample_correction,
float r_covmat[3][3],
float r_center[3]);
diff --git a/source/blender/blenlib/BLI_math_vec_mpq_types.hh b/source/blender/blenlib/BLI_math_vec_mpq_types.hh
new file mode 100644
index 00000000000..392c647fe0d
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_vec_mpq_types.hh
@@ -0,0 +1,92 @@
+/*
+ * 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 bli
+ */
+
+#include "BLI_math_vec_types.hh"
+
+#ifdef WITH_GMP
+
+# include "BLI_math_mpq.hh"
+
+namespace blender {
+
+using mpq2 = vec_base<mpq_class, 2>;
+using mpq3 = vec_base<mpq_class, 3>;
+
+namespace math {
+
+uint64_t hash_mpq_class(const mpq_class &value);
+
+template<> inline uint64_t vector_hash(const mpq2 &vec)
+{
+ return hash_mpq_class(vec.x) ^ (hash_mpq_class(vec.y) * 33);
+}
+
+template<> inline uint64_t vector_hash(const mpq3 &vec)
+{
+ return hash_mpq_class(vec.x) ^ (hash_mpq_class(vec.y) * 33) ^ (hash_mpq_class(vec.z) * 33 * 37);
+}
+
+/**
+ * Cannot do this exactly in rational arithmetic!
+ * Approximate by going in and out of doubles.
+ */
+template<> inline mpq_class length(const mpq2 &a)
+{
+ return mpq_class(sqrt(length_squared(a).get_d()));
+}
+
+/**
+ * Cannot do this exactly in rational arithmetic!
+ * Approximate by going in and out of doubles.
+ */
+template<> inline mpq_class length(const mpq3 &a)
+{
+ return mpq_class(sqrt(length_squared(a).get_d()));
+}
+
+/**
+ * The buffer avoids allocating a temporary variable.
+ */
+inline mpq_class distance_squared_with_buffer(const mpq3 &a, const mpq3 &b, mpq3 &buffer)
+{
+ buffer = a;
+ buffer -= b;
+ return dot(buffer, buffer);
+}
+
+/**
+ * The buffer avoids allocating a temporary variable.
+ */
+inline mpq_class dot_with_buffer(const mpq3 &a, const mpq3 &b, mpq3 &buffer)
+{
+ buffer = a;
+ buffer *= b;
+ buffer.x += buffer.y;
+ buffer.x += buffer.z;
+ return buffer.x;
+}
+
+} // namespace math
+
+} // namespace blender
+
+#endif /* WITH_GMP */
diff --git a/source/blender/blenlib/BLI_math_vec_types.hh b/source/blender/blenlib/BLI_math_vec_types.hh
new file mode 100644
index 00000000000..52aacd294e4
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_vec_types.hh
@@ -0,0 +1,566 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2022, Blender Foundation.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ */
+
+#include <array>
+#include <cmath>
+#include <iostream>
+#include <type_traits>
+
+#include "BLI_math_vector.hh"
+#include "BLI_utildefines.h"
+
+namespace blender {
+
+/* clang-format off */
+template<typename T>
+using as_uint_type = std::conditional_t<sizeof(T) == sizeof(uint8_t), uint8_t,
+ std::conditional_t<sizeof(T) == sizeof(uint16_t), uint16_t,
+ std::conditional_t<sizeof(T) == sizeof(uint32_t), uint32_t,
+ std::conditional_t<sizeof(T) == sizeof(uint64_t), uint64_t, void>>>>;
+/* clang-format on */
+
+template<typename T, int Size> struct vec_struct_base {
+ std::array<T, Size> values;
+};
+
+template<typename T> struct vec_struct_base<T, 2> {
+ T x, y;
+};
+
+template<typename T> struct vec_struct_base<T, 3> {
+ T x, y, z;
+};
+
+template<typename T> struct vec_struct_base<T, 4> {
+ T x, y, z, w;
+};
+
+template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> {
+
+ static constexpr int type_length = Size;
+
+ using base_type = T;
+ using uint_type = vec_base<as_uint_type<T>, Size>;
+
+ vec_base() = default;
+
+ explicit vec_base(uint value)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(value);
+ }
+ }
+
+ explicit vec_base(int value)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(value);
+ }
+ }
+
+ explicit vec_base(float value)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(value);
+ }
+ }
+
+ explicit vec_base(double value)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(value);
+ }
+ }
+
+/* Workaround issue with template BLI_ENABLE_IF((Size == 2)) not working. */
+#define BLI_ENABLE_IF_VEC(_size, _test) int S = _size, BLI_ENABLE_IF((S _test))
+
+ template<BLI_ENABLE_IF_VEC(Size, == 2)> vec_base(T _x, T _y)
+ {
+ (*this)[0] = _x;
+ (*this)[1] = _y;
+ }
+
+ template<BLI_ENABLE_IF_VEC(Size, == 3)> vec_base(T _x, T _y, T _z)
+ {
+ (*this)[0] = _x;
+ (*this)[1] = _y;
+ (*this)[2] = _z;
+ }
+
+ template<BLI_ENABLE_IF_VEC(Size, == 4)> vec_base(T _x, T _y, T _z, T _w)
+ {
+ (*this)[0] = _x;
+ (*this)[1] = _y;
+ (*this)[2] = _z;
+ (*this)[3] = _w;
+ }
+
+ /** Mixed scalar-vector constructors. */
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 3)>
+ constexpr vec_base(const vec_base<U, 2> &xy, T z)
+ : vec_base(static_cast<T>(xy.x), static_cast<T>(xy.y), z)
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 3)>
+ constexpr vec_base(T x, const vec_base<U, 2> &yz)
+ : vec_base(x, static_cast<T>(yz.x), static_cast<T>(yz.y))
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(vec_base<U, 3> xyz, T w)
+ : vec_base(
+ static_cast<T>(xyz.x), static_cast<T>(xyz.y), static_cast<T>(xyz.z), static_cast<T>(w))
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(T x, vec_base<U, 3> yzw)
+ : vec_base(
+ static_cast<T>(x), static_cast<T>(yzw.x), static_cast<T>(yzw.y), static_cast<T>(yzw.z))
+ {
+ }
+
+ template<typename U, typename V, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(vec_base<U, 2> xy, vec_base<V, 2> zw)
+ : vec_base(
+ static_cast<T>(xy.x), static_cast<T>(xy.y), static_cast<T>(zw.x), static_cast<T>(zw.y))
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(vec_base<U, 2> xy, T z, T w)
+ : vec_base(static_cast<T>(xy.x), static_cast<T>(xy.y), static_cast<T>(z), static_cast<T>(w))
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(T x, vec_base<U, 2> yz, T w)
+ : vec_base(static_cast<T>(x), static_cast<T>(yz.x), static_cast<T>(yz.y), static_cast<T>(w))
+ {
+ }
+
+ template<typename U, BLI_ENABLE_IF_VEC(Size, == 4)>
+ vec_base(T x, T y, vec_base<U, 2> zw)
+ : vec_base(static_cast<T>(x), static_cast<T>(y), static_cast<T>(zw.x), static_cast<T>(zw.y))
+ {
+ }
+
+ /** Masking. */
+
+ template<typename U, int OtherSize, BLI_ENABLE_IF(OtherSize > Size)>
+ explicit vec_base(const vec_base<U, OtherSize> &other)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(other[i]);
+ }
+ }
+
+#undef BLI_ENABLE_IF_VEC
+
+ /** Conversion from pointers (from C-style vectors). */
+
+ vec_base(const T *ptr)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = ptr[i];
+ }
+ }
+
+ vec_base(const T (*ptr)[Size]) : vec_base(static_cast<const T *>(ptr[0]))
+ {
+ }
+
+ /** Conversion from other vector types. */
+
+ template<typename U> explicit vec_base(const vec_base<U, Size> &vec)
+ {
+ for (int i = 0; i < Size; i++) {
+ (*this)[i] = static_cast<T>(vec[i]);
+ }
+ }
+
+ /** C-style pointer dereference. */
+
+ operator const T *() const
+ {
+ return reinterpret_cast<const T *>(this);
+ }
+
+ operator T *()
+ {
+ return reinterpret_cast<T *>(this);
+ }
+
+ /** Array access. */
+
+ const T &operator[](int index) const
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < Size);
+ return reinterpret_cast<const T *>(this)[index];
+ }
+
+ T &operator[](int index)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < Size);
+ return reinterpret_cast<T *>(this)[index];
+ }
+
+ /** Internal Operators Macro. */
+
+#define BLI_INT_OP(_T) template<typename U = _T, BLI_ENABLE_IF((std::is_integral_v<U>))>
+
+#define BLI_VEC_OP_IMPL(_result, _i, _op) \
+ vec_base _result; \
+ for (int _i = 0; _i < Size; _i++) { \
+ _op; \
+ } \
+ return _result;
+
+#define BLI_VEC_OP_IMPL_SELF(_i, _op) \
+ for (int _i = 0; _i < Size; _i++) { \
+ _op; \
+ } \
+ return *this;
+
+ /** Arithmetic operators. */
+
+ friend vec_base operator+(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] + b[i]);
+ }
+
+ friend vec_base operator+(const vec_base &a, const T &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] + b);
+ }
+
+ friend vec_base operator+(const T &a, const vec_base &b)
+ {
+ return b + a;
+ }
+
+ vec_base &operator+=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] += b[i]);
+ }
+
+ vec_base &operator+=(const T &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] += b);
+ }
+
+ friend vec_base operator-(const vec_base &a)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = -a[i]);
+ }
+
+ friend vec_base operator-(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] - b[i]);
+ }
+
+ friend vec_base operator-(const vec_base &a, const T &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] - b);
+ }
+
+ friend vec_base operator-(const T &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a - b[i]);
+ }
+
+ vec_base &operator-=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] -= b[i]);
+ }
+
+ vec_base &operator-=(const T &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] -= b);
+ }
+
+ friend vec_base operator*(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] * b[i]);
+ }
+
+ friend vec_base operator*(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] * b);
+ }
+
+ friend vec_base operator*(T a, const vec_base &b)
+ {
+ return b * a;
+ }
+
+ vec_base &operator*=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] *= b);
+ }
+
+ vec_base &operator*=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] *= b[i]);
+ }
+
+ friend vec_base operator/(const vec_base &a, const vec_base &b)
+ {
+ BLI_assert(!math::is_any_zero(b));
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] / b[i]);
+ }
+
+ friend vec_base operator/(const vec_base &a, T b)
+ {
+ BLI_assert(b != T(0));
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] / b);
+ }
+
+ friend vec_base operator/(T a, const vec_base &b)
+ {
+ BLI_assert(!math::is_any_zero(b));
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a / b[i]);
+ }
+
+ vec_base &operator/=(T b)
+ {
+ BLI_assert(b != T(0));
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] /= b);
+ }
+
+ vec_base &operator/=(const vec_base &b)
+ {
+ BLI_assert(!math::is_any_zero(b));
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] /= b[i]);
+ }
+
+ /** Binary operators. */
+
+ BLI_INT_OP(T) friend vec_base operator&(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] & b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator&(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] & b);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator&(T a, const vec_base &b)
+ {
+ return b & a;
+ }
+
+ BLI_INT_OP(T) vec_base &operator&=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] &= b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator&=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] &= b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator|(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] | b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator|(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] | b);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator|(T a, const vec_base &b)
+ {
+ return b | a;
+ }
+
+ BLI_INT_OP(T) vec_base &operator|=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] |= b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator|=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] |= b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator^(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] ^ b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator^(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] ^ b);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator^(T a, const vec_base &b)
+ {
+ return b ^ a;
+ }
+
+ BLI_INT_OP(T) vec_base &operator^=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] ^= b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator^=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] ^= b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator~(const vec_base &a)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = ~a[i]);
+ }
+
+ /** Bit-shift operators. */
+
+ BLI_INT_OP(T) friend vec_base operator<<(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] << b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator<<(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] << b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator<<=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] <<= b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator<<=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] <<= b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator>>(const vec_base &a, const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] >> b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator>>(const vec_base &a, T b)
+ {
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] >> b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator>>=(T b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] >>= b);
+ }
+
+ BLI_INT_OP(T) vec_base &operator>>=(const vec_base &b)
+ {
+ BLI_VEC_OP_IMPL_SELF(i, (*this)[i] >>= b[i]);
+ }
+
+ /** Modulo operators. */
+
+ BLI_INT_OP(T) friend vec_base operator%(const vec_base &a, const vec_base &b)
+ {
+ BLI_assert(!math::is_any_zero(b));
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] % b[i]);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator%(const vec_base &a, T b)
+ {
+ BLI_assert(b != 0);
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] % b);
+ }
+
+ BLI_INT_OP(T) friend vec_base operator%(T a, const vec_base &b)
+ {
+ BLI_assert(!math::is_any_zero(b));
+ BLI_VEC_OP_IMPL(ret, i, ret[i] = a % b[i]);
+ }
+
+#undef BLI_INT_OP
+#undef BLI_VEC_OP_IMPL
+#undef BLI_VEC_OP_IMPL_SELF
+
+ /** Compare. */
+
+ friend bool operator==(const vec_base &a, const vec_base &b)
+ {
+ for (int i = 0; i < Size; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ friend bool operator!=(const vec_base &a, const vec_base &b)
+ {
+ return !(a == b);
+ }
+
+ /** Misc. */
+
+ uint64_t hash() const
+ {
+ return math::vector_hash(*this);
+ }
+
+ friend std::ostream &operator<<(std::ostream &stream, const vec_base &v)
+ {
+ stream << "(";
+ for (int i = 0; i < Size; i++) {
+ stream << v[i];
+ if (i != Size - 1) {
+ stream << ", ";
+ }
+ }
+ stream << ")";
+ return stream;
+ }
+};
+
+using int2 = vec_base<int32_t, 2>;
+using int3 = vec_base<int32_t, 3>;
+using int4 = vec_base<int32_t, 4>;
+
+using uint2 = vec_base<uint32_t, 2>;
+using uint3 = vec_base<uint32_t, 3>;
+using uint4 = vec_base<uint32_t, 4>;
+
+using float2 = vec_base<float, 2>;
+using float3 = vec_base<float, 3>;
+using float4 = vec_base<float, 4>;
+
+using double2 = vec_base<double, 2>;
+using double3 = vec_base<double, 3>;
+using double4 = vec_base<double, 4>;
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 8f955076baf..1ed8d4fc005 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -64,9 +64,9 @@ MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]);
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]);
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]);
-MINLINE void copy_v2_uchar(unsigned char r[2], const unsigned char a);
-MINLINE void copy_v3_uchar(unsigned char r[3], const unsigned char a);
-MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a);
+MINLINE void copy_v2_uchar(unsigned char r[2], unsigned char a);
+MINLINE void copy_v3_uchar(unsigned char r[3], unsigned char a);
+MINLINE void copy_v4_uchar(unsigned char r[4], unsigned char a);
/* char */
@@ -79,7 +79,9 @@ MINLINE void copy_v4_v4_char(char r[4], const char a[4]);
MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
MINLINE void copy_v4_v4_short(short r[4], const short a[4]);
+
/* int */
+
MINLINE void zero_v3_int(int r[3]);
MINLINE void copy_v2_v2_int(int r[2], const int a[2]);
MINLINE void copy_v3_v3_int(int r[3], const int a[3]);
@@ -143,7 +145,6 @@ MINLINE void add_v4_v4(float r[4], const float a[4]);
MINLINE void add_v4_v4v4(float r[4], const float a[4], const float b[4]);
MINLINE void add_v3fl_v3fl_v3i(float r[3], const float a[3], const int b[3]);
-MINLINE void add_v3fl_v3fl_v3s(float r[3], const float a[3], const short b[3]);
MINLINE void sub_v2_v2(float r[2], const float a[2]);
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2]);
@@ -301,18 +302,18 @@ 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);
+MINLINE float normalize_v2_length(float r[2], 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);
+MINLINE float normalize_v2_v2_length(float r[2], const float a[2], float unit_scale);
+MINLINE float normalize_v3_length(float r[3], 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);
+MINLINE float normalize_v3_v3_length(float r[3], const float a[3], float unit_scale);
+MINLINE double normalize_v3_length_db(double n[3], double unit_scale);
+MINLINE double normalize_v3_v3_length_db(double r[3], const double a[3], double unit_scale);
MINLINE float normalize_v2(float r[2]);
MINLINE float normalize_v2_v2(float r[2], const float a[2]);
@@ -327,16 +328,16 @@ MINLINE double normalize_v3_db(double n[3]);
/** \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);
+void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t);
+void interp_v2_v2v2_db(double target[2], const double a[2], const double b[2], 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);
+void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t);
+void interp_v3_v3v3_db(double target[3], const double a[3], const double b[3], double t);
/**
* Weight 3 vectors,
* 'w' must be unit length but is not a vector, just 3 weights.
@@ -353,7 +354,7 @@ void interp_v3_v3v3v3v3(float p[3],
const float v3[3],
const float v4[3],
const float w[4]);
-void interp_v4_v4v4(float r[4], const float a[4], const float b[4], const float t);
+void interp_v4_v4v4(float r[4], const float a[4], const float b[4], float t);
void interp_v4_v4v4v4(
float p[4], const float v1[4], const float v2[4], const float v3[4], const float w[3]);
void interp_v4_v4v4v4v4(float p[4],
@@ -371,34 +372,34 @@ void interp_v3_v3v3v3_uv(
*
* \return success
*/
-bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], const float t)
+bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], 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)
+bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], 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);
+void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], float t);
+void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[2], float t);
void interp_v2_v2v2v2v2_cubic(float p[2],
const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2],
- const float u);
+ float u);
-void interp_v3_v3v3_char(char target[3], const char a[3], const char b[3], const float t);
+void interp_v3_v3v3_char(char target[3], const char a[3], const char b[3], float t);
void interp_v3_v3v3_uchar(unsigned char target[3],
const unsigned char a[3],
const unsigned char b[3],
- const float t);
-void interp_v4_v4v4_char(char target[4], const char a[4], const char b[4], const float t);
+ float t);
+void interp_v4_v4v4_char(char target[4], const char a[4], const char b[4], float t);
void interp_v4_v4v4_uchar(unsigned char target[4],
const unsigned char a[4],
const unsigned char b[4],
- const float t);
+ float t);
void mid_v3_v3v3(float r[3], const float a[3], const float b[3]);
void mid_v2_v2v2(float r[2], const float a[2], const float b[2]);
@@ -406,7 +407,7 @@ void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float
void mid_v2_v2v2v2(float v[2], const float v1[2], const float v2[2], const float v3[2]);
void mid_v3_v3v3v3v3(
float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
-void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr);
+void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], unsigned int nbr);
/**
* Specialized function for calculating normals.
@@ -459,36 +460,24 @@ MINLINE bool equals_v2v2_int(const int v1[2], const int v2[2]) ATTR_WARN_UNUSED_
MINLINE bool equals_v3v3_int(const int v1[3], const int v2[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool equals_v4v4_int(const int v1[4], const int v2[4]) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool compare_v2v2(const float a[2],
- const float b[2],
- const float limit) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool compare_v3v3(const float a[3],
- const float b[3],
- const float limit) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool compare_v4v4(const float a[4],
- const float b[4],
- const float limit) ATTR_WARN_UNUSED_RESULT;
-
-MINLINE bool compare_v2v2_relative(const float a[2],
- const float b[2],
- const float limit,
- const int max_ulps) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool compare_v3v3_relative(const float a[3],
- const float b[3],
- const float limit,
- const int max_ulps) ATTR_WARN_UNUSED_RESULT;
-MINLINE bool compare_v4v4_relative(const float a[4],
- const float b[4],
- const float limit,
- const int max_ulps) ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_v2v2(const float a[2], const float b[2], float limit) ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_v3v3(const float a[3], const float b[3], float limit) ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_v4v4(const float a[4], const float b[4], float limit) ATTR_WARN_UNUSED_RESULT;
+
+MINLINE bool compare_v2v2_relative(const float a[2], const float b[2], float limit, int max_ulps)
+ ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_v3v3_relative(const float a[3], const float b[3], float limit, int max_ulps)
+ ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_v4v4_relative(const float a[4], const float b[4], float limit, int max_ulps)
+ ATTR_WARN_UNUSED_RESULT;
MINLINE bool compare_len_v3v3(const float a[3],
const float b[3],
- const float limit) ATTR_WARN_UNUSED_RESULT;
+ float limit) ATTR_WARN_UNUSED_RESULT;
MINLINE bool compare_size_v3v3(const float a[3],
const float b[3],
- const float limit) ATTR_WARN_UNUSED_RESULT;
+ float limit) ATTR_WARN_UNUSED_RESULT;
/**
* <pre>
@@ -656,16 +645,13 @@ void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const floa
/**
* 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);
+void rotate_v2_v2fl(float r[2], const float p[2], float angle);
+void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], 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);
+void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], float angle);
/** \} */
@@ -676,7 +662,7 @@ void rotate_normalized_v3_v3v3fl(float out[3],
void print_v2(const char *str, const float v[2]);
void print_v3(const char *str, const float v[3]);
void print_v4(const char *str, const float v[4]);
-void print_vn(const char *str, const float v[], const int n);
+void print_vn(const char *str, const float v[], int n);
#define print_v2_id(v) print_v2(STRINGIFY(v), v)
#define print_v3_id(v) print_v3(STRINGIFY(v), v)
@@ -695,14 +681,14 @@ 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);
+void dist_ensure_v3_v3fl(float v1[3], const float v2[3], float dist);
+void dist_ensure_v2_v2fl(float v1[2], const float v2[2], float dist);
void axis_sort_v3(const float axis_values[3], int r_axis_order[3]);
-MINLINE void clamp_v2(float vec[2], const float min, const float max);
-MINLINE void clamp_v3(float vec[3], const float min, const float max);
-MINLINE void clamp_v4(float vec[4], const float min, const float max);
+MINLINE void clamp_v2(float vec[2], float min, float max);
+MINLINE void clamp_v3(float vec[3], float min, float max);
+MINLINE void clamp_v4(float vec[4], float min, float max);
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]);
@@ -719,57 +705,42 @@ MINLINE void clamp_v4_v4v4(float vec[4], const float min[4], const float max[4])
double dot_vn_vn(const float *array_src_a,
const float *array_src_b,
- const int size) ATTR_WARN_UNUSED_RESULT;
-double len_squared_vn(const float *array, const int size) ATTR_WARN_UNUSED_RESULT;
-float normalize_vn_vn(float *array_tar, const float *array_src, const int size);
-float normalize_vn(float *array_tar, const int size);
-void range_vn_i(int *array_tar, const int size, const int start);
-void range_vn_u(unsigned int *array_tar, const int size, const unsigned int start);
-void range_vn_fl(float *array_tar, const int size, const float start, const float step);
-void negate_vn(float *array_tar, const int size);
-void negate_vn_vn(float *array_tar, const float *array_src, const int size);
-void mul_vn_vn(float *array_tar, const float *array_src, const int size);
-void mul_vn_vnvn(float *array_tar,
- const float *array_src_a,
- const float *array_src_b,
- const int size);
-void mul_vn_fl(float *array_tar, const int size, const float f);
-void mul_vn_vn_fl(float *array_tar, const float *array_src, const int size, const float f);
-void add_vn_vn(float *array_tar, const float *array_src, const int size);
-void add_vn_vnvn(float *array_tar,
- const float *array_src_a,
- const float *array_src_b,
- const int size);
-void madd_vn_vn(float *array_tar, const float *array_src, const float f, const int size);
-void madd_vn_vnvn(float *array_tar,
- const float *array_src_a,
- const float *array_src_b,
- const float f,
- const int size);
-void sub_vn_vn(float *array_tar, const float *array_src, const int size);
-void sub_vn_vnvn(float *array_tar,
- const float *array_src_a,
- const float *array_src_b,
- const int size);
-void msub_vn_vn(float *array_tar, const float *array_src, const float f, const int size);
-void msub_vn_vnvn(float *array_tar,
- const float *array_src_a,
- const float *array_src_b,
- const float f,
- const int size);
-void interp_vn_vn(float *array_tar, const float *array_src, const float t, const int size);
-void copy_vn_i(int *array_tar, const int size, const int val);
-void copy_vn_short(short *array_tar, const int size, const short val);
-void copy_vn_ushort(unsigned short *array_tar, const int size, const unsigned short val);
-void copy_vn_uchar(unsigned char *array_tar, const int size, const unsigned char val);
-void copy_vn_fl(float *array_tar, const int size, const float val);
-
-void add_vn_vn_d(double *array_tar, const double *array_src, const int size);
+ int size) ATTR_WARN_UNUSED_RESULT;
+double len_squared_vn(const float *array, int size) ATTR_WARN_UNUSED_RESULT;
+float normalize_vn_vn(float *array_tar, const float *array_src, int size);
+float normalize_vn(float *array_tar, int size);
+void range_vn_i(int *array_tar, int size, int start);
+void range_vn_u(unsigned int *array_tar, int size, unsigned int start);
+void range_vn_fl(float *array_tar, int size, float start, float step);
+void negate_vn(float *array_tar, int size);
+void negate_vn_vn(float *array_tar, const float *array_src, int size);
+void mul_vn_vn(float *array_tar, const float *array_src, int size);
+void mul_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size);
+void mul_vn_fl(float *array_tar, int size, float f);
+void mul_vn_vn_fl(float *array_tar, const float *array_src, int size, float f);
+void add_vn_vn(float *array_tar, const float *array_src, int size);
+void add_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size);
+void madd_vn_vn(float *array_tar, const float *array_src, float f, int size);
+void madd_vn_vnvn(
+ float *array_tar, const float *array_src_a, const float *array_src_b, float f, int size);
+void sub_vn_vn(float *array_tar, const float *array_src, int size);
+void sub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size);
+void msub_vn_vn(float *array_tar, const float *array_src, float f, int size);
+void msub_vn_vnvn(
+ float *array_tar, const float *array_src_a, const float *array_src_b, float f, int size);
+void interp_vn_vn(float *array_tar, const float *array_src, float t, int size);
+void copy_vn_i(int *array_tar, int size, int val);
+void copy_vn_short(short *array_tar, int size, short val);
+void copy_vn_ushort(unsigned short *array_tar, int size, unsigned short val);
+void copy_vn_uchar(unsigned char *array_tar, int size, unsigned char val);
+void copy_vn_fl(float *array_tar, int size, float val);
+
+void add_vn_vn_d(double *array_tar, const double *array_src, int size);
void add_vn_vnvn_d(double *array_tar,
const double *array_src_a,
const double *array_src_b,
- const int size);
-void mul_vn_db(double *array_tar, const int size, const double f);
+ int size);
+void mul_vn_db(double *array_tar, int size, double f);
/** \} */
diff --git a/source/blender/blenlib/BLI_math_vector.hh b/source/blender/blenlib/BLI_math_vector.hh
new file mode 100644
index 00000000000..1d60447445e
--- /dev/null
+++ b/source/blender/blenlib/BLI_math_vector.hh
@@ -0,0 +1,404 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2022, Blender Foundation.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ */
+
+#include <cmath>
+#include <type_traits>
+
+#include "BLI_math_base_safe.h"
+#include "BLI_math_vector.h"
+#include "BLI_span.hh"
+#include "BLI_utildefines.h"
+
+#ifdef WITH_GMP
+# include "BLI_math_mpq.hh"
+#endif
+
+namespace blender::math {
+
+#ifndef NDEBUG
+# define BLI_ASSERT_UNIT(v) \
+ { \
+ const float _test_unit = length_squared(v); \
+ BLI_assert(!(std::abs(_test_unit - 1.0f) >= BLI_ASSERT_UNIT_EPSILON) || \
+ !(std::abs(_test_unit) >= BLI_ASSERT_UNIT_EPSILON)); \
+ } \
+ (void)0
+#else
+# define BLI_ASSERT_UNIT(v) (void)(v)
+#endif
+
+#define bT typename T::base_type
+
+#ifdef WITH_GMP
+# define BLI_ENABLE_IF_FLT_VEC(T) \
+ BLI_ENABLE_IF((std::is_floating_point_v<typename T::base_type> || \
+ std::is_same_v<typename T::base_type, mpq_class>))
+#else
+# define BLI_ENABLE_IF_FLT_VEC(T) BLI_ENABLE_IF((std::is_floating_point_v<typename T::base_type>))
+#endif
+
+#define BLI_ENABLE_IF_INT_VEC(T) BLI_ENABLE_IF((std::is_integral_v<typename T::base_type>))
+
+template<typename T> inline bool is_zero(const T &a)
+{
+ for (int i = 0; i < T::type_length; i++) {
+ if (a[i] != bT(0)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template<typename T> inline bool is_any_zero(const T &a)
+{
+ for (int i = 0; i < T::type_length; i++) {
+ if (a[i] == bT(0)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template<typename T> inline T abs(const T &a)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = a[i] >= 0 ? a[i] : -a[i];
+ }
+ return result;
+}
+
+template<typename T> inline T min(const T &a, const T &b)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = a[i] < b[i] ? a[i] : b[i];
+ }
+ return result;
+}
+
+template<typename T> inline T max(const T &a, const T &b)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = a[i] > b[i] ? a[i] : b[i];
+ }
+ return result;
+}
+
+template<typename T> inline T clamp(const T &a, const T &min_v, const T &max_v)
+{
+ T result = a;
+ for (int i = 0; i < T::type_length; i++) {
+ CLAMP(result[i], min_v[i], max_v[i]);
+ }
+ return result;
+}
+
+template<typename T> inline T clamp(const T &a, const bT &min_v, const bT &max_v)
+{
+ T result = a;
+ for (int i = 0; i < T::type_length; i++) {
+ CLAMP(result[i], min_v, max_v);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T mod(const T &a, const T &b)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ BLI_assert(b[i] != 0);
+ result[i] = std::fmod(a[i], b[i]);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T mod(const T &a, bT b)
+{
+ BLI_assert(b != 0);
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = std::fmod(a[i], b);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_mod(const T &a, const T &b)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = (b[i] != 0) ? std::fmod(a[i], b[i]) : 0;
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_mod(const T &a, bT b)
+{
+ if (b == 0) {
+ return T(0.0f);
+ }
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = std::fmod(a[i], b);
+ }
+ return result;
+}
+
+template<typename T> inline void min_max(const T &vector, T &min_vec, T &max_vec)
+{
+ min_vec = min(vector, min_vec);
+ max_vec = max(vector, max_vec);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_divide(const T &a, const T &b)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = (b[i] == 0) ? 0 : a[i] / b[i];
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T safe_divide(const T &a, const bT b)
+{
+ return (b != 0) ? a / b : T(0.0f);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T floor(const T &a)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = std::floor(a[i]);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T ceil(const T &a)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = std::ceil(a[i]);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T fract(const T &a)
+{
+ T result;
+ for (int i = 0; i < T::type_length; i++) {
+ result[i] = a[i] - std::floor(a[i]);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT dot(const T &a, const T &b)
+{
+ bT result = a[0] * b[0];
+ for (int i = 1; i < T::type_length; i++) {
+ result += a[i] * b[i];
+ }
+ return result;
+}
+
+template<typename T> inline bT length_manhattan(const T &a)
+{
+ bT result = std::abs(a[0]);
+ for (int i = 1; i < T::type_length; i++) {
+ result += std::abs(a[i]);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT length_squared(const T &a)
+{
+ return dot(a, a);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT length(const T &a)
+{
+ return std::sqrt(length_squared(a));
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT distance_manhattan(const T &a, const T &b)
+{
+ return length_manhattan(a - b);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT distance_squared(const T &a, const T &b)
+{
+ return length_squared(a - b);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline bT distance(const T &a, const T &b)
+{
+ return length(a - b);
+}
+
+template<typename T> uint64_t vector_hash(const T &vec)
+{
+ BLI_STATIC_ASSERT(T::type_length <= 4, "Longer types need to implement vector_hash themself.");
+ const typename T::uint_type &uvec = *reinterpret_cast<const typename T::uint_type *>(&vec);
+ uint64_t result;
+ result = uvec[0] * uint64_t(435109);
+ if constexpr (T::type_length > 1) {
+ result ^= uvec[1] * uint64_t(380867);
+ }
+ if constexpr (T::type_length > 2) {
+ result ^= uvec[2] * uint64_t(1059217);
+ }
+ if constexpr (T::type_length > 3) {
+ result ^= uvec[3] * uint64_t(2002613);
+ }
+ return result;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T reflect(const T &incident, const T &normal)
+{
+ BLI_ASSERT_UNIT(normal);
+ return incident - 2.0 * dot(normal, incident) * normal;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
+inline T refract(const T &incident, const T &normal, const bT eta)
+{
+ float dot_ni = dot(normal, incident);
+ float k = 1.0f - eta * eta * (1.0f - dot_ni * dot_ni);
+ if (k < 0.0f) {
+ return T(0.0f);
+ }
+ return eta * incident - (eta * dot_ni + sqrt(k)) * normal;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T project(const T &p, const T &v_proj)
+{
+ if (UNLIKELY(is_zero(v_proj))) {
+ return T(0.0f);
+ }
+ return v_proj * (dot(p, v_proj) / dot(v_proj, v_proj));
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
+inline T normalize_and_get_length(const T &v, bT &out_length)
+{
+ out_length = length_squared(v);
+ /* A larger value causes normalize errors in a scaled down models with camera extreme close. */
+ constexpr bT threshold = std::is_same_v<bT, double> ? 1.0e-70 : 1.0e-35f;
+ if (out_length > threshold) {
+ out_length = sqrt(out_length);
+ return v / out_length;
+ }
+ /* Either the vector is small or one of it's values contained `nan`. */
+ out_length = 0.0;
+ return T(0.0);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T normalize(const T &v)
+{
+ bT len;
+ return normalize_and_get_length(v, len);
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T), BLI_ENABLE_IF((T::type_length == 3))>
+inline T cross(const T &a, const T &b)
+{
+ return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
+}
+
+template<typename T,
+ BLI_ENABLE_IF((std::is_same_v<bT, float>)),
+ BLI_ENABLE_IF((T::type_length == 3))>
+inline T cross_high_precision(const T &a, const T &b)
+{
+ return {(float)((double)a.y * b.z - (double)a.z * b.y),
+ (float)((double)a.z * b.x - (double)a.x * b.z),
+ (float)((double)a.x * b.y - (double)a.y * b.x)};
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T), BLI_ENABLE_IF((T::type_length == 3))>
+inline T cross_poly(Span<T> poly)
+{
+ /* Newell's Method. */
+ int nv = static_cast<int>(poly.size());
+ if (nv < 3) {
+ return T(0, 0, 0);
+ }
+ const T *v_prev = &poly[nv - 1];
+ const T *v_curr = &poly[0];
+ T n(0, 0, 0);
+ for (int i = 0; i < nv;) {
+ n[0] = n[0] + ((*v_prev)[1] - (*v_curr)[1]) * ((*v_prev)[2] + (*v_curr)[2]);
+ n[1] = n[1] + ((*v_prev)[2] - (*v_curr)[2]) * ((*v_prev)[0] + (*v_curr)[0]);
+ n[2] = n[2] + ((*v_prev)[0] - (*v_curr)[0]) * ((*v_prev)[1] + (*v_curr)[1]);
+ v_prev = v_curr;
+ ++i;
+ if (i < nv) {
+ v_curr = &poly[i];
+ }
+ }
+ return n;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T interpolate(const T &a, const T &b, bT t)
+{
+ return a * (1 - t) + b * t;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)> inline T midpoint(const T &a, const T &b)
+{
+ return (a + b) * 0.5;
+}
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
+inline T faceforward(const T &vector, const T &incident, const T &reference)
+{
+ return (dot(reference, incident) < 0) ? vector : -vector;
+}
+
+template<typename T> inline int dominant_axis(const T &a)
+{
+ T b = abs(a);
+ return ((b.x > b.y) ? ((b.x > b.z) ? 0 : 2) : ((b.y > b.z) ? 1 : 2));
+}
+
+/** Intersections. */
+
+template<typename T> struct isect_result {
+ enum {
+ LINE_LINE_COLINEAR = -1,
+ LINE_LINE_NONE = 0,
+ LINE_LINE_EXACT = 1,
+ LINE_LINE_CROSS = 2,
+ } kind;
+ bT lambda;
+};
+
+template<typename T, BLI_ENABLE_IF_FLT_VEC(T)>
+isect_result<T> isect_seg_seg(const T &v1, const T &v2, const T &v3, const T &v4);
+
+#undef BLI_ENABLE_IF_FLT_VEC
+#undef BLI_ENABLE_IF_INT_VEC
+#undef bT
+
+} // namespace blender::math
diff --git a/source/blender/blenlib/BLI_memarena.h b/source/blender/blenlib/BLI_memarena.h
index 4ac4712bc8c..bcfe2efc5e5 100644
--- a/source/blender/blenlib/BLI_memarena.h
+++ b/source/blender/blenlib/BLI_memarena.h
@@ -38,13 +38,13 @@ extern "C" {
struct MemArena;
typedef struct MemArena MemArena;
-struct MemArena *BLI_memarena_new(const size_t bufsize,
+struct MemArena *BLI_memarena_new(size_t bufsize,
const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
ATTR_NONNULL(2) ATTR_MALLOC;
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1);
void BLI_memarena_use_malloc(struct MemArena *ma) ATTR_NONNULL(1);
void BLI_memarena_use_calloc(struct MemArena *ma) ATTR_NONNULL(1);
-void BLI_memarena_use_align(struct MemArena *ma, const size_t align) ATTR_NONNULL(1);
+void BLI_memarena_use_align(struct MemArena *ma, size_t align) ATTR_NONNULL(1);
void *BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2);
void *BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/blenlib/BLI_memory_utils.h b/source/blender/blenlib/BLI_memory_utils.h
index 79e25e26040..09d8f646905 100644
--- a/source/blender/blenlib/BLI_memory_utils.h
+++ b/source/blender/blenlib/BLI_memory_utils.h
@@ -29,7 +29,7 @@ extern "C" {
/* it may be defined already */
#ifndef __BLI_UTILDEFINES_H__
-bool BLI_memory_is_zero(const void *arr, const size_t size);
+bool BLI_memory_is_zero(const void *arr, size_t size);
#endif
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index 14eca49d126..9a5be79b61e 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -498,6 +498,12 @@ inline constexpr bool is_span_convertible_pointer_v =
std::is_same_v<To, const void *>);
/**
+ * Same as #std::is_same_v but allows for checking multiple types at the same time.
+ */
+template<typename T, typename... Args>
+inline constexpr bool is_same_any_v = (std::is_same_v<T, Args> || ...);
+
+/**
* Inline buffers for small-object-optimization should be disable by default. Otherwise we might
* get large unexpected allocations on the stack.
*/
diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h
index d6abae36e00..caf946cabe3 100644
--- a/source/blender/blenlib/BLI_mempool.h
+++ b/source/blender/blenlib/BLI_mempool.h
@@ -56,13 +56,13 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1, 2);
* \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);
+void BLI_mempool_clear_ex(BLI_mempool *pool, 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).
+ * Free the mempool itself (and all elements).
*/
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1);
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1);
@@ -103,14 +103,14 @@ void BLI_mempool_set_memory_debug(void);
* \note this may easy to produce bugs with.
*/
-/* Private structure. */
+/** \note Private structure. */
typedef struct BLI_mempool_iter {
BLI_mempool *pool;
struct BLI_mempool_chunk *curchunk;
unsigned int curindex;
} BLI_mempool_iter;
-/* flag */
+/** #BLI_mempool.flag */
enum {
BLI_MEMPOOL_NOP = 0,
/** allow iterating on this mempool.
diff --git a/source/blender/blenlib/BLI_mesh_intersect.hh b/source/blender/blenlib/BLI_mesh_intersect.hh
index 4aaed814bba..0ebee6f16a8 100644
--- a/source/blender/blenlib/BLI_mesh_intersect.hh
+++ b/source/blender/blenlib/BLI_mesh_intersect.hh
@@ -28,12 +28,11 @@
# include <iostream>
# include "BLI_array.hh"
-# include "BLI_double3.hh"
-# include "BLI_float3.hh"
# include "BLI_index_range.hh"
# include "BLI_map.hh"
# include "BLI_math_mpq.hh"
-# include "BLI_mpq3.hh"
+# include "BLI_math_vec_mpq_types.hh"
+# include "BLI_math_vec_types.hh"
# include "BLI_span.hh"
# include "BLI_utility_mixins.hh"
# include "BLI_vector.hh"
@@ -91,7 +90,7 @@ struct Plane {
Plane() = default;
Plane(const mpq3 &norm_exact, const mpq_class &d_exact);
- Plane(const double3 &norm, const double d);
+ Plane(const double3 &norm, double d);
/** Test equality on the exact fields. */
bool operator==(const Plane &other) const;
diff --git a/source/blender/blenlib/BLI_mpq2.hh b/source/blender/blenlib/BLI_mpq2.hh
deleted file mode 100644
index 18bc8821d9c..00000000000
--- a/source/blender/blenlib/BLI_mpq2.hh
+++ /dev/null
@@ -1,184 +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
-
-/** \file
- * \ingroup bli
- */
-
-#ifdef WITH_GMP
-
-# include "BLI_math_mpq.hh"
-# include "BLI_mpq3.hh"
-
-namespace blender {
-
-struct mpq2 {
- mpq_class x, y;
-
- mpq2() = default;
-
- mpq2(const mpq_class *ptr) : x{ptr[0]}, y{ptr[1]}
- {
- }
-
- mpq2(mpq_class x, mpq_class y) : x(x), y(y)
- {
- }
-
- mpq2(const mpq2 &other) : x(other.x), y(other.y)
- {
- }
-
- mpq2(mpq2 &&other) noexcept : x(std::move(other.x)), y(std::move(other.y))
- {
- }
-
- ~mpq2() = default;
-
- mpq2 &operator=(const mpq2 &other)
- {
- if (this != &other) {
- x = other.x;
- y = other.y;
- }
- return *this;
- }
-
- mpq2 &operator=(mpq2 &&other) noexcept
- {
- x = std::move(other.x);
- y = std::move(other.y);
- return *this;
- }
-
- mpq2(const mpq3 &other) : x(other.x), y(other.y)
- {
- }
-
- operator mpq_class *()
- {
- return &x;
- }
-
- operator const mpq_class *() const
- {
- return &x;
- }
-
- /**
- * Cannot do this exactly in rational arithmetic!
- * Approximate by going in and out of doubles.
- */
- mpq_class length() const
- {
- mpq_class lsquared = dot(*this, *this);
- return mpq_class(sqrt(lsquared.get_d()));
- }
-
- friend mpq2 operator+(const mpq2 &a, const mpq2 &b)
- {
- return {a.x + b.x, a.y + b.y};
- }
-
- friend mpq2 operator-(const mpq2 &a, const mpq2 &b)
- {
- return {a.x - b.x, a.y - b.y};
- }
-
- friend mpq2 operator*(const mpq2 &a, mpq_class b)
- {
- return {a.x * b, a.y * b};
- }
-
- friend mpq2 operator/(const mpq2 &a, mpq_class b)
- {
- BLI_assert(b != 0);
- return {a.x / b, a.y / b};
- }
-
- friend mpq2 operator*(mpq_class a, const mpq2 &b)
- {
- return b * a;
- }
-
- friend bool operator==(const mpq2 &a, const mpq2 &b)
- {
- return a.x == b.x && a.y == b.y;
- }
-
- friend bool operator!=(const mpq2 &a, const mpq2 &b)
- {
- return a.x != b.x || a.y != b.y;
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const mpq2 &v)
- {
- stream << "(" << v.x << ", " << v.y << ")";
- return stream;
- }
-
- static mpq_class dot(const mpq2 &a, const mpq2 &b)
- {
- return a.x * b.x + a.y * b.y;
- }
-
- static mpq2 interpolate(const mpq2 &a, const mpq2 &b, mpq_class t)
- {
- return a * (1 - t) + b * t;
- }
-
- static mpq2 abs(const mpq2 &a)
- {
- mpq_class abs_x = (a.x >= 0) ? a.x : -a.x;
- mpq_class abs_y = (a.y >= 0) ? a.y : -a.y;
- return mpq2(abs_x, abs_y);
- }
-
- static mpq_class distance(const mpq2 &a, const mpq2 &b)
- {
- return (a - b).length();
- }
-
- static mpq_class distance_squared(const mpq2 &a, const mpq2 &b)
- {
- mpq2 diff = a - b;
- return dot(diff, diff);
- }
-
- struct isect_result {
- enum {
- LINE_LINE_COLINEAR = -1,
- LINE_LINE_NONE = 0,
- LINE_LINE_EXACT = 1,
- LINE_LINE_CROSS = 2,
- } kind;
- mpq_class lambda;
- };
-
- static isect_result isect_seg_seg(const mpq2 &v1,
- const mpq2 &v2,
- const mpq2 &v3,
- const mpq2 &v4);
-
- /** There is a sensible use for hashing on exact arithmetic types. */
- uint64_t hash() const;
-};
-
-} // namespace blender
-
-#endif /* WITH_GMP */
diff --git a/source/blender/blenlib/BLI_mpq3.hh b/source/blender/blenlib/BLI_mpq3.hh
deleted file mode 100644
index b9eda2ad7e1..00000000000
--- a/source/blender/blenlib/BLI_mpq3.hh
+++ /dev/null
@@ -1,297 +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
-
-/** \file
- * \ingroup bli
- */
-
-#ifdef WITH_GMP
-
-# include <iostream>
-
-# include "BLI_math.h"
-# include "BLI_math_mpq.hh"
-# include "BLI_span.hh"
-
-namespace blender {
-
-struct mpq3 {
- mpq_class x, y, z;
-
- mpq3() = default;
-
- mpq3(const mpq_class *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}
- {
- }
-
- mpq3(const mpq_class (*ptr)[3]) : mpq3((const mpq_class *)ptr)
- {
- }
-
- explicit mpq3(mpq_class value) : x(value), y(value), z(value)
- {
- }
-
- explicit mpq3(int value) : x(value), y(value), z(value)
- {
- }
-
- mpq3(mpq_class x, mpq_class y, mpq_class z) : x{x}, y{y}, z{z}
- {
- }
-
- operator const mpq_class *() const
- {
- return &x;
- }
-
- operator mpq_class *()
- {
- return &x;
- }
-
- /* Cannot do this exactly in rational arithmetic!
- * Approximate by going in and out of doubles.
- */
- mpq_class normalize_and_get_length()
- {
- double dv[3] = {x.get_d(), y.get_d(), z.get_d()};
- double len = normalize_v3_db(dv);
- this->x = mpq_class(dv[0]);
- this->y = mpq_class(dv[1]);
- this->z = mpq_class(dv[2]);
- return len;
- }
-
- mpq3 normalized() const
- {
- double dv[3] = {x.get_d(), y.get_d(), z.get_d()};
- double dr[3];
- normalize_v3_v3_db(dr, dv);
- return mpq3(mpq_class(dr[0]), mpq_class(dr[1]), mpq_class(dr[2]));
- }
-
- /* Cannot do this exactly in rational arithmetic!
- * Approximate by going in and out of double.
- */
- mpq_class length() const
- {
- mpq_class lsquared = this->length_squared();
- double dsquared = lsquared.get_d();
- double d = sqrt(dsquared);
- return mpq_class(d);
- }
-
- mpq_class length_squared() const
- {
- return x * x + y * y + z * z;
- }
-
- void reflect(const mpq3 &normal)
- {
- *this = this->reflected(normal);
- }
-
- mpq3 reflected(const mpq3 &normal) const
- {
- mpq3 result;
- const mpq_class dot2 = 2 * dot(*this, normal);
- result.x = this->x - (dot2 * normal.x);
- result.y = this->y - (dot2 * normal.y);
- result.z = this->z - (dot2 * normal.z);
- return result;
- }
-
- static mpq3 safe_divide(const mpq3 &a, const mpq3 &b)
- {
- mpq3 result;
- result.x = (b.x == 0) ? mpq_class(0) : a.x / b.x;
- result.y = (b.y == 0) ? mpq_class(0) : a.y / b.y;
- result.z = (b.z == 0) ? mpq_class(0) : a.z / b.z;
- return result;
- }
-
- void invert()
- {
- x = -x;
- y = -y;
- z = -z;
- }
-
- friend mpq3 operator+(const mpq3 &a, const mpq3 &b)
- {
- return mpq3(a.x + b.x, a.y + b.y, a.z + b.z);
- }
-
- void operator+=(const mpq3 &b)
- {
- this->x += b.x;
- this->y += b.y;
- this->z += b.z;
- }
-
- friend mpq3 operator-(const mpq3 &a, const mpq3 &b)
- {
- return mpq3(a.x - b.x, a.y - b.y, a.z - b.z);
- }
-
- friend mpq3 operator-(const mpq3 &a)
- {
- return mpq3(-a.x, -a.y, -a.z);
- }
-
- void operator-=(const mpq3 &b)
- {
- this->x -= b.x;
- this->y -= b.y;
- this->z -= b.z;
- }
-
- void operator*=(mpq_class scalar)
- {
- this->x *= scalar;
- this->y *= scalar;
- this->z *= scalar;
- }
-
- void operator*=(const mpq3 &other)
- {
- this->x *= other.x;
- this->y *= other.y;
- this->z *= other.z;
- }
-
- friend mpq3 operator*(const mpq3 &a, const mpq3 &b)
- {
- return {a.x * b.x, a.y * b.y, a.z * b.z};
- }
-
- friend mpq3 operator*(const mpq3 &a, const mpq_class &b)
- {
- return mpq3(a.x * b, a.y * b, a.z * b);
- }
-
- friend mpq3 operator*(const mpq_class &a, const mpq3 &b)
- {
- return mpq3(a * b.x, a * b.y, a * b.z);
- }
-
- friend mpq3 operator/(const mpq3 &a, const mpq_class &b)
- {
- BLI_assert(b != 0);
- return mpq3(a.x / b, a.y / b, a.z / b);
- }
-
- friend bool operator==(const mpq3 &a, const mpq3 &b)
- {
- return a.x == b.x && a.y == b.y && a.z == b.z;
- }
-
- friend bool operator!=(const mpq3 &a, const mpq3 &b)
- {
- return a.x != b.x || a.y != b.y || a.z != b.z;
- }
-
- friend std::ostream &operator<<(std::ostream &stream, const mpq3 &v)
- {
- stream << "(" << v.x << ", " << v.y << ", " << v.z << ")";
- return stream;
- }
-
- static mpq_class dot(const mpq3 &a, const mpq3 &b)
- {
- return a.x * b.x + a.y * b.y + a.z * b.z;
- }
-
- static mpq_class dot_with_buffer(const mpq3 &a, const mpq3 &b, mpq3 &buffer)
- {
- buffer = a;
- buffer *= b;
- buffer.x += buffer.y;
- buffer.x += buffer.z;
- return buffer.x;
- }
-
- static mpq3 cross(const mpq3 &a, const mpq3 &b)
- {
- return mpq3(a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]);
- }
-
- static mpq3 cross_high_precision(const mpq3 &a, const mpq3 &b)
- {
- return cross(a, b);
- }
-
- static mpq3 project(const mpq3 &a, const mpq3 &b)
- {
- const mpq_class mul = mpq3::dot(a, b) / mpq3::dot(b, b);
- return mpq3(mul * b[0], mul * b[1], mul * b[2]);
- }
-
- static mpq_class distance(const mpq3 &a, const mpq3 &b)
- {
- mpq3 diff(a.x - b.x, a.y - b.y, a.z - b.z);
- return diff.length();
- }
-
- static mpq_class distance_squared(const mpq3 &a, const mpq3 &b)
- {
- mpq3 diff(a.x - b.x, a.y - b.y, a.z - b.z);
- return mpq3::dot(diff, diff);
- }
-
- static mpq_class distance_squared_with_buffer(const mpq3 &a, const mpq3 &b, mpq3 &buffer)
- {
- buffer = a;
- buffer -= b;
- return mpq3::dot(buffer, buffer);
- }
-
- static mpq3 interpolate(const mpq3 &a, const mpq3 &b, mpq_class t)
- {
- mpq_class s = 1 - t;
- return mpq3(a.x * s + b.x * t, a.y * s + b.y * t, a.z * s + b.z * t);
- }
-
- static mpq3 abs(const mpq3 &a)
- {
- mpq_class abs_x = (a.x >= 0) ? a.x : -a.x;
- mpq_class abs_y = (a.y >= 0) ? a.y : -a.y;
- mpq_class abs_z = (a.z >= 0) ? a.z : -a.z;
- return mpq3(abs_x, abs_y, abs_z);
- }
-
- static int dominant_axis(const mpq3 &a)
- {
- mpq_class x = (a.x >= 0) ? a.x : -a.x;
- mpq_class y = (a.y >= 0) ? a.y : -a.y;
- mpq_class z = (a.z >= 0) ? a.z : -a.z;
- return ((x > y) ? ((x > z) ? 0 : 2) : ((y > z) ? 1 : 2));
- }
-
- static mpq3 cross_poly(Span<mpq3> poly);
-
- /** There is a sensible use for hashing on exact arithmetic types. */
- uint64_t hash() const;
-};
-
-uint64_t hash_mpq_class(const mpq_class &value);
-
-} // namespace blender
-
-#endif /* WITH_GMP */
diff --git a/source/blender/blenlib/BLI_noise.hh b/source/blender/blenlib/BLI_noise.hh
index 44af2c44f00..297c65c250a 100644
--- a/source/blender/blenlib/BLI_noise.hh
+++ b/source/blender/blenlib/BLI_noise.hh
@@ -16,9 +16,7 @@
#pragma once
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
-#include "BLI_float4.hh"
+#include "BLI_math_vec_types.hh"
namespace blender::noise {
@@ -133,12 +131,8 @@ float3 perlin_float3_fractal_distorted(float4 position,
* \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);
+float musgrave_ridged_multi_fractal(
+ float co, float H, float lacunarity, float octaves, float offset, float gain);
/**
* 2D Ridged Multi-fractal Terrain
*
@@ -147,12 +141,8 @@ float musgrave_ridged_multi_fractal(const float co,
* \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);
+float musgrave_ridged_multi_fractal(
+ const float2 co, float H, float lacunarity, float octaves, float offset, float gain);
/**
* 3D Ridged Multi-fractal Terrain
*
@@ -161,12 +151,8 @@ float musgrave_ridged_multi_fractal(const float2 co,
* \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);
+float musgrave_ridged_multi_fractal(
+ const float3 co, float H, float lacunarity, float octaves, float offset, float gain);
/**
* 4D Ridged Multi-fractal Terrain
*
@@ -175,12 +161,8 @@ float musgrave_ridged_multi_fractal(const float3 co,
* \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,
- const float octaves,
- const float offset,
- const float gain);
+float musgrave_ridged_multi_fractal(
+ const float4 co, float H, float lacunarity, float octaves, float offset, float gain);
/**
* 1D Hybrid Additive/Multiplicative Multi-fractal Terrain
@@ -190,12 +172,8 @@ float musgrave_ridged_multi_fractal(const float4 co,
* \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);
+float musgrave_hybrid_multi_fractal(
+ float co, float H, float lacunarity, float octaves, float offset, float gain);
/**
* 2D Hybrid Additive/Multiplicative Multi-fractal Terrain
*
@@ -204,12 +182,8 @@ float musgrave_hybrid_multi_fractal(const float co,
* \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);
+float musgrave_hybrid_multi_fractal(
+ const float2 co, float H, float lacunarity, float octaves, float offset, float gain);
/**
* 3D Hybrid Additive/Multiplicative Multi-fractal Terrain
*
@@ -218,12 +192,8 @@ float musgrave_hybrid_multi_fractal(const float2 co,
* \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);
+float musgrave_hybrid_multi_fractal(
+ const float3 co, float H, float lacunarity, float octaves, float offset, float gain);
/**
* 4D Hybrid Additive/Multiplicative Multi-fractal Terrain
*
@@ -232,12 +202,8 @@ float musgrave_hybrid_multi_fractal(const float3 co,
* \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,
- const float octaves,
- const float offset,
- const float gain);
+float musgrave_hybrid_multi_fractal(
+ const float4 co, float H, float lacunarity, float octaves, float offset, float gain);
/**
* 1D Musgrave fBm
@@ -246,7 +212,7 @@ float musgrave_hybrid_multi_fractal(const float4 co,
* \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);
+float musgrave_fBm(float co, float H, float lacunarity, float octaves);
/**
* 2D Musgrave fBm
@@ -255,7 +221,7 @@ float musgrave_fBm(const float co, const float H, const float lacunarity, const
* \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);
+float musgrave_fBm(const float2 co, float H, float lacunarity, float octaves);
/**
* 3D Musgrave fBm
*
@@ -263,7 +229,7 @@ float musgrave_fBm(const float2 co, const float H, const float lacunarity, const
* \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);
+float musgrave_fBm(const float3 co, float H, float lacunarity, float octaves);
/**
* 4D Musgrave fBm
*
@@ -271,7 +237,7 @@ float musgrave_fBm(const float3 co, const float H, const float lacunarity, const
* \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);
+float musgrave_fBm(const float4 co, float H, float lacunarity, float octaves);
/**
* 1D Musgrave Multi-fractal
@@ -280,10 +246,7 @@ float musgrave_fBm(const float4 co, const float H, const float lacunarity, const
* \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);
+float musgrave_multi_fractal(float co, float H, float lacunarity, float octaves);
/**
* 2D Musgrave Multi-fractal
*
@@ -291,10 +254,7 @@ float musgrave_multi_fractal(const float co,
* \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);
+float musgrave_multi_fractal(const float2 co, float H, float lacunarity, float octaves);
/**
* 3D Musgrave Multi-fractal
*
@@ -302,10 +262,7 @@ float musgrave_multi_fractal(const float2 co,
* \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);
+float musgrave_multi_fractal(const float3 co, float H, float lacunarity, float octaves);
/**
* 4D Musgrave Multi-fractal
*
@@ -313,10 +270,7 @@ float musgrave_multi_fractal(const float3 co,
* \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);
+float musgrave_multi_fractal(const float4 co, float H, float lacunarity, float octaves);
/**
* 1D Musgrave Heterogeneous Terrain
@@ -326,11 +280,7 @@ float musgrave_multi_fractal(const float4 co,
* \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);
+float musgrave_hetero_terrain(float co, float H, float lacunarity, float octaves, float offset);
/**
* 2D Musgrave Heterogeneous Terrain
*
@@ -339,11 +289,8 @@ float musgrave_hetero_terrain(const float co,
* \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);
+float musgrave_hetero_terrain(
+ const float2 co, float H, float lacunarity, float octaves, float offset);
/**
* 3D Musgrave Heterogeneous Terrain
*
@@ -352,11 +299,8 @@ float musgrave_hetero_terrain(const float2 co,
* \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);
+float musgrave_hetero_terrain(
+ const float3 co, float H, float lacunarity, float octaves, float offset);
/**
* 4D Musgrave Heterogeneous Terrain
*
@@ -365,11 +309,8 @@ float musgrave_hetero_terrain(const float3 co,
* \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,
- const float octaves,
- const float offset);
+float musgrave_hetero_terrain(
+ const float4 co, float H, float lacunarity, float octaves, float offset);
/** \} */
@@ -377,93 +318,87 @@ float musgrave_hetero_terrain(const float4 co,
/** \name Voronoi Noise
* \{ */
-void voronoi_f1(
- const float w, const float randomness, float *r_distance, float3 *r_color, float *r_w);
-void voronoi_smooth_f1(const float w,
- const float smoothness,
- const float randomness,
- float *r_distance,
- float3 *r_color,
- float *r_w);
-void voronoi_f2(
- const float w, const float randomness, float *r_distance, float3 *r_color, float *r_w);
-void voronoi_distance_to_edge(const float w, const float randomness, float *r_distance);
-void voronoi_n_sphere_radius(const float w, const float randomness, float *r_radius);
+void voronoi_f1(float w, float randomness, float *r_distance, float3 *r_color, float *r_w);
+void voronoi_smooth_f1(
+ float w, float smoothness, float randomness, float *r_distance, float3 *r_color, float *r_w);
+void voronoi_f2(float w, float randomness, float *r_distance, float3 *r_color, float *r_w);
+void voronoi_distance_to_edge(float w, float randomness, float *r_distance);
+void voronoi_n_sphere_radius(float w, float randomness, float *r_radius);
void voronoi_f1(const float2 coord,
- const float exponent,
- const float randomness,
- const int metric,
+ float exponent,
+ float randomness,
+ int metric,
float *r_distance,
float3 *r_color,
float2 *r_position);
void voronoi_smooth_f1(const float2 coord,
- const float smoothness,
- const float exponent,
- const float randomness,
- const int metric,
+ float smoothness,
+ float exponent,
+ float randomness,
+ int metric,
float *r_distance,
float3 *r_color,
float2 *r_position);
void voronoi_f2(const float2 coord,
- const float exponent,
- const float randomness,
- const int metric,
+ float exponent,
+ float randomness,
+ int metric,
float *r_distance,
float3 *r_color,
float2 *r_position);
-void voronoi_distance_to_edge(const float2 coord, const float randomness, float *r_distance);
-void voronoi_n_sphere_radius(const float2 coord, const float randomness, float *r_radius);
+void voronoi_distance_to_edge(const float2 coord, float randomness, float *r_distance);
+void voronoi_n_sphere_radius(const float2 coord, float randomness, float *r_radius);
void voronoi_f1(const float3 coord,
- const float exponent,
- const float randomness,
- const int metric,
+ float exponent,
+ float randomness,
+ int metric,
float *r_distance,
float3 *r_color,
float3 *r_position);
void voronoi_smooth_f1(const float3 coord,
- const float smoothness,
- const float exponent,
- const float randomness,
- const int metric,
+ float smoothness,
+ float exponent,
+ float randomness,
+ int metric,
float *r_distance,
float3 *r_color,
float3 *r_position);
void voronoi_f2(const float3 coord,
- const float exponent,
- const float randomness,
- const int metric,
+ float exponent,
+ float randomness,
+ int metric,
float *r_distance,
float3 *r_color,
float3 *r_position);
-void voronoi_distance_to_edge(const float3 coord, const float randomness, float *r_distance);
-void voronoi_n_sphere_radius(const float3 coord, const float randomness, float *r_radius);
+void voronoi_distance_to_edge(const float3 coord, float randomness, float *r_distance);
+void voronoi_n_sphere_radius(const float3 coord, float randomness, float *r_radius);
void voronoi_f1(const float4 coord,
- const float exponent,
- const float randomness,
- const int metric,
+ float exponent,
+ float randomness,
+ int metric,
float *r_distance,
float3 *r_color,
float4 *r_position);
void voronoi_smooth_f1(const float4 coord,
- const float smoothness,
- const float exponent,
- const float randomness,
- const int metric,
+ float smoothness,
+ float exponent,
+ float randomness,
+ int metric,
float *r_distance,
float3 *r_color,
float4 *r_position);
void voronoi_f2(const float4 coord,
- const float exponent,
- const float randomness,
- const int metric,
+ float exponent,
+ float randomness,
+ int metric,
float *r_distance,
float3 *r_color,
float4 *r_position);
-void voronoi_distance_to_edge(const float4 coord, const float randomness, float *r_distance);
-void voronoi_n_sphere_radius(const float4 coord, const float randomness, float *r_radius);
+void voronoi_distance_to_edge(const float4 coord, float randomness, float *r_distance);
+void voronoi_n_sphere_radius(const float4 coord, float randomness, float *r_radius);
/** \} */
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index 9e2970f6013..658cc0c3825 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -75,16 +75,15 @@ bool BLI_make_existing_file(const char *name);
* - 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);
+void BLI_split_dirfile(const char *string, char *dir, char *file, size_t dirlen, 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);
+void BLI_split_dir_part(const char *string, char *dir, 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);
+void BLI_split_file_part(const char *string, char *file, 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.
@@ -94,7 +93,7 @@ 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)
+void BLI_path_append(char *__restrict dst, size_t maxlen, const char *__restrict file)
ATTR_NONNULL();
/**
* Simple appending of filename to dir, does not check for valid path!
@@ -104,7 +103,7 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__re
* that de-duplicates separators and can handle an arbitrary number of paths.
*/
void BLI_join_dirfile(char *__restrict dst,
- const size_t maxlen,
+ size_t maxlen,
const char *__restrict dir,
const char *__restrict file) ATTR_NONNULL();
/**
@@ -114,7 +113,7 @@ void BLI_join_dirfile(char *__restrict dst,
* \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, ...)
+size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path_first, ...)
ATTR_NONNULL(1, 3) ATTR_SENTINEL(0);
/**
* Like Python's `os.path.basename()`
@@ -133,7 +132,7 @@ const char *BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_
* 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 index,
int *__restrict r_offset,
int *__restrict r_len) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
@@ -142,7 +141,11 @@ 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.
+ * \return pointer to the leftmost path separator in string (or NULL when not found).
+ */
+const char *BLI_path_slash_find(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+/**
+ * \return pointer to the rightmost path separator in string (or NULL when not found).
*/
const char *BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
/**
@@ -155,21 +158,17 @@ int BLI_path_slash_ensure(char *string) ATTR_NONNULL();
*/
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);
+bool BLI_path_program_extensions_add_win32(char *name, size_t maxlen);
#endif
/**
* Search for a binary (executable)
*/
-bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name);
+bool BLI_path_program_search(char *fullname, size_t maxlen, const char *name);
/**
* \return true when `str` end with `ext` (case insensitive).
@@ -207,6 +206,10 @@ bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR
* 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,
@@ -250,6 +253,10 @@ void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2);
/**
* Make given name safe to be used in paths.
*
+ * \param allow_tokens: Permit the usage of '<' and '>' characters. This can be
+ * leveraged by higher layers to support "virtual filenames" which contain
+ * substitution markers delineated between the two characters.
+ *
* \return true if \a fname was changed, false otherwise.
*
* For now, simply replaces reserved chars (as listed in
@@ -269,7 +276,9 @@ void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2);
* \note On Windows, it also checks for forbidden names
* (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
*/
+bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens) ATTR_NONNULL(1);
bool BLI_filename_make_safe(char *fname) ATTR_NONNULL(1);
+
/**
* Make given path OS-safe.
*
@@ -318,20 +327,32 @@ 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.
+ * \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();
+bool BLI_path_abs_from_cwd(char *path, 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.
diff --git a/source/blender/blenlib/BLI_polyfill_2d.h b/source/blender/blenlib/BLI_polyfill_2d.h
index d16c102ec86..25a624ba005 100644
--- a/source/blender/blenlib/BLI_polyfill_2d.h
+++ b/source/blender/blenlib/BLI_polyfill_2d.h
@@ -30,8 +30,8 @@ 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,
+ unsigned int coords_tot,
+ int coords_sign,
unsigned int (*r_tris)[3],
struct MemArena *arena);
@@ -50,8 +50,8 @@ void BLI_polyfill_calc_arena(const float (*coords)[2],
* 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,
+ unsigned int coords_tot,
+ int coords_sign,
unsigned int (*r_tris)[3]);
/* default size of polyfill arena */
diff --git a/source/blender/blenlib/BLI_polyfill_2d_beautify.h b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
index b0b97336a3b..3a94ef46aca 100644
--- a/source/blender/blenlib/BLI_polyfill_2d_beautify.h
+++ b/source/blender/blenlib/BLI_polyfill_2d_beautify.h
@@ -34,7 +34,7 @@ struct MemArena;
* 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 coords_tot,
unsigned int (*tris)[3],
/* structs for reuse */
@@ -60,7 +60,7 @@ float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2],
const float v3[2],
const float v4[2],
- const bool lock_degenerate,
+ bool lock_degenerate,
float *r_area);
#define BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4) \
BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false, NULL)
diff --git a/source/blender/blenlib/BLI_quadric.h b/source/blender/blenlib/BLI_quadric.h
index fdb7d1e67ac..03642023986 100644
--- a/source/blender/blenlib/BLI_quadric.h
+++ b/source/blender/blenlib/BLI_quadric.h
@@ -31,20 +31,23 @@ typedef struct Quadric {
double a2, ab, ac, ad, b2, bc, bd, c2, cd, d2;
} Quadric;
-/* conversion */
+/* Conversion. */
+
void BLI_quadric_from_plane(Quadric *q, const double v[4]);
void BLI_quadric_to_vector_v3(const Quadric *q, double v[3]);
void BLI_quadric_clear(Quadric *q);
-/* math */
+/* Math operations. */
+
void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b);
void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b);
-void BLI_quadric_mul(Quadric *a, const double scalar);
+void BLI_quadric_mul(Quadric *a, double scalar);
+
+/* Solve. */
-/* solve */
double BLI_quadric_evaluate(const Quadric *q, const double v[3]);
-bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon);
+bool BLI_quadric_optimize(const Quadric *q, double v[3], double epsilon);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_rand.hh b/source/blender/blenlib/BLI_rand.hh
index cc9e9b374d7..667d6df8996 100644
--- a/source/blender/blenlib/BLI_rand.hh
+++ b/source/blender/blenlib/BLI_rand.hh
@@ -20,9 +20,8 @@
#pragma once
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index f4b1d051d16..b8906a97977 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -101,16 +101,13 @@ void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y);
void BLI_rctf_resize(struct rctf *rect, float x, float y);
void BLI_rctf_resize_x(struct rctf *rect, float x);
void BLI_rctf_resize_y(struct rctf *rect, float y);
-void BLI_rcti_scale(rcti *rect, const float scale);
-void BLI_rctf_scale(rctf *rect, const float scale);
-void BLI_rctf_pad_y(struct rctf *rect,
- const float boundary_size,
- const float pad_min,
- const float pad_max);
+void BLI_rcti_scale(rcti *rect, float scale);
+void BLI_rctf_scale(rctf *rect, float scale);
+void BLI_rctf_pad_y(struct rctf *rect, float boundary_size, float pad_min, float pad_max);
void BLI_rctf_interp(struct rctf *rect,
const struct rctf *rect_a,
const struct rctf *rect_b,
- const float fac);
+ float fac);
// 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]);
@@ -124,7 +121,7 @@ bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2]);
*/
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);
+bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, float limit);
bool BLI_rcti_compare(const struct rcti *rect_a, const struct rcti *rect_b);
bool BLI_rctf_isect(const struct rctf *src1, const struct rctf *src2, struct rctf *dest);
bool BLI_rcti_isect(const struct rcti *src1, const struct rcti *src2, struct rcti *dest);
@@ -132,28 +129,28 @@ bool BLI_rctf_isect_rect_x(const struct rctf *src1, const struct rctf *src2, flo
bool BLI_rctf_isect_rect_y(const struct rctf *src1, const struct rctf *src2, float range_y[2]);
bool BLI_rcti_isect_rect_x(const struct rcti *src1, const struct rcti *src2, int range_x[2]);
bool BLI_rcti_isect_rect_y(const struct rcti *src1, const struct rcti *src2, int range_y[2]);
-bool BLI_rcti_isect_x(const rcti *rect, const int x);
-bool BLI_rcti_isect_y(const rcti *rect, const int y);
-bool BLI_rcti_isect_pt(const struct rcti *rect, const int x, const int y);
+bool BLI_rcti_isect_x(const rcti *rect, int x);
+bool BLI_rcti_isect_y(const rcti *rect, int y);
+bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y);
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2]);
-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_x(const rctf *rect, float x);
+bool BLI_rctf_isect_y(const rctf *rect, float y);
+bool BLI_rctf_isect_pt(const struct rctf *rect, float x, 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);
+int BLI_rcti_length_x(const rcti *rect, 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);
+int BLI_rcti_length_y(const rcti *rect, int y);
+float BLI_rctf_length_x(const rctf *rect, float x);
+float BLI_rctf_length_y(const rctf *rect, float y);
bool BLI_rcti_isect_segment(const struct rcti *rect, const int s1[2], const int s2[2]);
bool BLI_rctf_isect_segment(const struct rctf *rect, const float s1[2], const float s2[2]);
-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_isect_circle(const struct rcti *rect, const float xy[2], float radius);
+bool BLI_rctf_isect_circle(const struct rctf *rect, const float xy[2], float radius);
bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b);
/**
* is \a rct_b inside \a rct_a
@@ -169,7 +166,7 @@ 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 BLI_rctf_rotate_expand(rctf *dst, const rctf *src, float angle);
void print_rctf(const char *str, const struct rctf *rect);
void print_rcti(const char *str, const struct rcti *rect);
diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h
index 744d30397d4..eca3c00017c 100644
--- a/source/blender/blenlib/BLI_scanfill.h
+++ b/source/blender/blenlib/BLI_scanfill.h
@@ -91,6 +91,7 @@ typedef struct ScanFillFace {
} ScanFillFace;
/* scanfill.c */
+
struct ScanFillVert *BLI_scanfill_vert_add(ScanFillContext *sf_ctx, const float vec[3]);
struct ScanFillEdge *BLI_scanfill_edge_add(ScanFillContext *sf_ctx,
struct ScanFillVert *v1,
@@ -113,10 +114,8 @@ enum {
BLI_SCANFILL_CALC_LOOSE = (1 << 4),
};
void BLI_scanfill_begin(ScanFillContext *sf_ctx);
-unsigned int BLI_scanfill_calc(ScanFillContext *sf_ctx, const int flag);
-unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx,
- const int flag,
- const float nor_proj[3]);
+unsigned int BLI_scanfill_calc(ScanFillContext *sf_ctx, int flag);
+unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, int flag, const float nor_proj[3]);
void BLI_scanfill_end(ScanFillContext *sf_ctx);
void BLI_scanfill_begin_arena(ScanFillContext *sf_ctx, struct MemArena *arena);
diff --git a/source/blender/blenlib/BLI_serialize.hh b/source/blender/blenlib/BLI_serialize.hh
index 051731ab801..05606794994 100644
--- a/source/blender/blenlib/BLI_serialize.hh
+++ b/source/blender/blenlib/BLI_serialize.hh
@@ -36,7 +36,7 @@
* - DoubleValue: for double precision floating point numbers
* - BooleanValue: for boolean values
* - ArrayValue: An array of any supported value.
- * - ObjectValue: A key value pair where keys are std::string.
+ * - DictionaryValue: A key value pair where keys are std::string.
* - NullValue: for null values.
*
* # Basic usage
@@ -92,12 +92,12 @@ enum class eValueType {
Null,
Boolean,
Double,
- Object,
+ Dictionary,
};
class Value;
class StringValue;
-class ObjectValue;
+class DictionaryValue;
template<typename T, eValueType V> class PrimitiveValue;
using IntValue = PrimitiveValue<int64_t, eValueType::Int>;
using DoubleValue = PrimitiveValue<double, eValueType::Double>;
@@ -122,8 +122,8 @@ using ArrayValue = ContainerValue<Vector<std::shared_ptr<Value>>, eValueType::Ar
* - `NullValue`: represents nothing (null pointer or optional).
* - `BooleanValue`: contains a boolean (true/false).
* - `DoubleValue`: contains a double precision floating point number.
- * - `ObjectValue`: represents an object (key value pairs where keys are strings and values can be
- * of different types.
+ * - `DictionaryValue`: represents an object (key value pairs where keys are strings and values can
+ * be of different types.
*
*/
class Value {
@@ -174,10 +174,10 @@ class Value {
const ArrayValue *as_array_value() const;
/**
- * Casts to an ObjectValue.
+ * Casts to an DictionaryValue.
* Will return nullptr when it is a different type.
*/
- const ObjectValue *as_object_value() const;
+ const DictionaryValue *as_dictionary_value() const;
};
/**
@@ -228,7 +228,7 @@ class StringValue : public Value {
/**
* Template for arrays and objects.
*
- * Both ArrayValue and ObjectValue store their values in an array.
+ * Both ArrayValue and DictionaryValue store their values in an array.
*/
template<
/** The container type where the elements are stored in. */
@@ -264,18 +264,19 @@ class ContainerValue : public Value {
};
/**
- * Internal storage type for ObjectValue.
+ * Internal storage type for DictionaryValue.
*
* The elements are stored as an key value pair. The value is a shared pointer so it can be shared
- * when using `ObjectValue::create_lookup`.
+ * when using `DictionaryValue::create_lookup`.
*/
-using ObjectElementType = std::pair<std::string, std::shared_ptr<Value>>;
+using DictionaryElementType = std::pair<std::string, std::shared_ptr<Value>>;
/**
* Object is a key-value container where the key must be a std::string.
* Internally it is stored in a blender::Vector to ensure the order of keys.
*/
-class ObjectValue : public ContainerValue<Vector<ObjectElementType>, eValueType::Object> {
+class DictionaryValue
+ : public ContainerValue<Vector<DictionaryElementType>, eValueType::Dictionary> {
public:
using LookupValue = std::shared_ptr<Value>;
using Lookup = Map<std::string, LookupValue>;
diff --git a/source/blender/blenlib/BLI_session_uuid.h b/source/blender/blenlib/BLI_session_uuid.h
index 887044e9b54..29e291add5a 100644
--- a/source/blender/blenlib/BLI_session_uuid.h
+++ b/source/blender/blenlib/BLI_session_uuid.h
@@ -33,18 +33,19 @@ extern "C" {
#include "DNA_session_uuid_types.h"
-/* Generate new UUID which is unique throughout the Blender session. */
+/** Generate new UUID which is unique throughout the Blender session. */
SessionUUID BLI_session_uuid_generate(void);
-/* Check whether the UUID is properly generated. */
+/** Check whether the UUID is properly generated. */
bool BLI_session_uuid_is_generated(const SessionUUID *uuid);
-/* Check whether two UUIDs are identical. */
+/** Check whether two UUIDs are identical. */
bool BLI_session_uuid_is_equal(const SessionUUID *lhs, const SessionUUID *rhs);
uint64_t BLI_session_uuid_hash_uint64(const SessionUUID *uuid);
/* Utility functions to make it possible to create GHash/GSet with UUID as a key. */
+
uint BLI_session_uuid_ghash_hash(const void *uuid_v);
bool BLI_session_uuid_ghash_compare(const void *lhs_v, const void *rhs_v);
diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h
index 9492a252fed..9c274d25fba 100644
--- a/source/blender/blenlib/BLI_smallhash.h
+++ b/source/blender/blenlib/BLI_smallhash.h
@@ -53,7 +53,7 @@ typedef struct {
unsigned int i;
} SmallHashIter;
-void BLI_smallhash_init_ex(SmallHash *sh, const unsigned int nentries_reserve) ATTR_NONNULL(1);
+void BLI_smallhash_init_ex(SmallHash *sh, 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!
@@ -61,7 +61,7 @@ void BLI_smallhash_init(SmallHash *sh) ATTR_NONNULL(1);
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.
+ * Inserts a new value to a key that may already be in #GHash.
*
* Avoids #BLI_smallhash_remove, #BLI_smallhash_insert calls (double lookups)
*
diff --git a/source/blender/blenlib/BLI_sort.h b/source/blender/blenlib/BLI_sort.h
index 969816086e2..31a052eb79d 100644
--- a/source/blender/blenlib/BLI_sort.h
+++ b/source/blender/blenlib/BLI_sort.h
@@ -30,7 +30,7 @@
# define BLI_qsort_r qsort_r
#endif
-/* Quick sort re-entrant */
+/** Quick sort (re-entrant). */
typedef int (*BLI_sort_cmp_t)(const void *a, const void *b, void *ctx);
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index 5b7981e0302..b4497977815 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -62,7 +62,7 @@
* then the function has to specify whether the referenced array is expected to be initialized or
* not.
*
- * Since the arrays are only referenced, it is generally unsafe to store an Span. When you
+ * Since the arrays are only referenced, it is generally unsafe to store a Span. When you
* store one, you should know who owns the memory.
*
* Instances of Span and MutableSpan are small and should be passed by value.
@@ -109,7 +109,7 @@ template<typename T> class Span {
BLI_assert(size >= 0);
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<U, T>))>
constexpr Span(const U *start, int64_t size) : data_(static_cast<const T *>(start)), size_(size)
{
BLI_assert(size >= 0);
@@ -144,7 +144,7 @@ template<typename T> class Span {
* Support implicit conversions like the one below:
* Span<T *> -> Span<const T *>
*/
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<U, T>))>
constexpr Span(Span<U> span) : data_(static_cast<const T *>(span.data())), size_(span.size())
{
}
@@ -501,7 +501,7 @@ template<typename T> class MutableSpan {
* Support implicit conversions like the one below:
* MutableSpan<T *> -> MutableSpan<const T *>
*/
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<U, T>))>
constexpr MutableSpan(MutableSpan<U> span)
: data_(static_cast<T *>(span.data())), size_(span.size())
{
@@ -512,7 +512,7 @@ template<typename T> class MutableSpan {
return Span<T>(data_, size_);
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
constexpr operator Span<U>() const
{
return Span<U>(static_cast<const U *>(data_), size_);
@@ -599,6 +599,11 @@ template<typename T> class MutableSpan {
return MutableSpan(data_ + start, new_size);
}
+ constexpr MutableSpan slice(IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
+
/**
* Returns a new MutableSpan with n elements removed from the beginning. This invokes
* undefined behavior when n is negative.
diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h
index 653f5f61c9e..eb4e69a42d4 100644
--- a/source/blender/blenlib/BLI_stack.h
+++ b/source/blender/blenlib/BLI_stack.h
@@ -28,13 +28,13 @@ extern "C" {
typedef struct BLI_Stack BLI_Stack;
-BLI_Stack *BLI_stack_new_ex(const size_t elem_size,
+BLI_Stack *BLI_stack_new_ex(size_t elem_size,
const char *description,
- const size_t chunk_size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ 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
+BLI_Stack *BLI_stack_new(size_t elem_size, const char *description) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/**
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index 91cc7b23a5f..8177545911c 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -42,8 +42,7 @@ extern "C" {
* \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();
+char *BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Duplicates the cstring \a str into a newly mallocN'd
@@ -74,8 +73,7 @@ char *BLI_strdupcat(const char *__restrict str1,
* the size of dst)
* \retval Returns dst
*/
-char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
- ATTR_NONNULL();
+char *BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL();
/**
* Like BLI_strncpy but ensures dst is always padded by given char,
@@ -89,7 +87,7 @@ char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t
*/
char *BLI_strncpy_ensure_pad(char *__restrict dst,
const char *__restrict src,
- const char pad,
+ char pad,
size_t maxncpy) ATTR_NONNULL();
/**
@@ -107,7 +105,7 @@ char *BLI_strncpy_ensure_pad(char *__restrict dst,
*/
size_t BLI_strncpy_rlen(char *__restrict dst,
const char *__restrict src,
- const size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -186,7 +184,7 @@ void BLI_str_replace_char(char *str, char src, char dst) ATTR_NONNULL();
* \note Larger tables should use a hash table.
*/
bool BLI_str_replace_table_exact(char *string,
- const size_t string_len,
+ size_t string_len,
const char *replace_table[][2],
int replace_table_len);
@@ -235,7 +233,7 @@ char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT
*
* \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)
+size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy)
ATTR_NONNULL();
/**
* This roughly matches C and Python's string escaping with double quotes - `"`.
@@ -251,9 +249,9 @@ size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const si
*/
size_t BLI_str_unescape_ex(char *__restrict dst,
const char *__restrict src,
- const size_t src_maxncpy,
+ size_t src_maxncpy,
/* Additional arguments. */
- const size_t dst_maxncpy,
+ size_t dst_maxncpy,
bool *r_is_complete) ATTR_NONNULL();
/**
* See #BLI_str_unescape_ex doc-string.
@@ -265,7 +263,7 @@ size_t BLI_str_unescape_ex(char *__restrict dst,
*
* \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 BLI_str_unescape(char *__restrict dst, const char *__restrict src, size_t src_maxncpy)
ATTR_NONNULL();
/**
@@ -306,8 +304,7 @@ size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) ATTR_NONNULL();
* \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();
+void BLI_str_format_byte_unit(char dst[15], long long int bytes, 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.
@@ -354,17 +351,16 @@ int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESU
* 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();
+int BLI_strcmp_ignore_pad(const char *str1, const char *str2, 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();
+size_t BLI_strnlen(const char *str, 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();
+void BLI_str_tolower_ascii(char *str, size_t len) ATTR_NONNULL();
+void BLI_str_toupper_ascii(char *str, size_t len) ATTR_NONNULL();
/**
* Strip white-space from end of the string.
*/
@@ -378,7 +374,7 @@ void BLI_str_rstrip(char *str) ATTR_NONNULL();
* \param pad:
* \return The number of zeros stripped.
*/
-int BLI_str_rstrip_float_zero(char *str, const char pad) ATTR_NONNULL();
+int BLI_str_rstrip_float_zero(char *str, char pad) ATTR_NONNULL();
/**
* Return index of a string in a string array.
@@ -390,7 +386,7 @@ int BLI_str_rstrip_float_zero(char *str, const char pad) ATTR_NONNULL();
*/
int BLI_str_index_in_array_n(const char *__restrict str,
const char **__restrict str_array,
- const int str_array_len) ATTR_NONNULL();
+ int str_array_len) ATTR_NONNULL();
/**
* Return index of a string in a string array.
*
@@ -461,14 +457,14 @@ size_t BLI_str_partition_ex(const char *str,
const char delim[],
const char **sep,
const char **suf,
- const bool from_right) ATTR_NONNULL(1, 3, 4, 5);
+ bool from_right) ATTR_NONNULL(1, 3, 4, 5);
-int BLI_string_max_possible_word_count(const int str_len);
+int BLI_string_max_possible_word_count(int str_len);
bool BLI_string_has_word_prefix(const char *haystack, const char *needle, size_t needle_len);
bool BLI_string_all_words_matched(const char *name,
const char *str,
int (*words)[2],
- const int words_len);
+ int words_len);
/**
* Find the ranges needed to split \a str into its individual words.
@@ -481,8 +477,8 @@ bool BLI_string_all_words_matched(const char *name,
* \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,
+ size_t len,
+ char delim,
int r_words[][2],
int words_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh
index dc73208350f..e3dd8afd588 100644
--- a/source/blender/blenlib/BLI_string_ref.hh
+++ b/source/blender/blenlib/BLI_string_ref.hh
@@ -64,7 +64,7 @@ class StringRefBase {
const char *data_;
int64_t size_;
- constexpr StringRefBase(const char *data, const int64_t size);
+ constexpr StringRefBase(const char *data, int64_t size);
public:
/* Similar to string_view::npos, but signed. */
@@ -84,12 +84,12 @@ class StringRefBase {
constexpr IndexRange index_range() const;
void unsafe_copy(char *dst) const;
- void copy(char *dst, const int64_t dst_size) const;
+ void copy(char *dst, int64_t dst_size) const;
template<size_t N> void copy(char (&dst)[N]) const;
constexpr bool startswith(StringRef prefix) const;
constexpr bool endswith(StringRef suffix) const;
- constexpr StringRef substr(int64_t start, const int64_t size) const;
+ constexpr StringRef substr(int64_t start, int64_t size) const;
constexpr const char &front() const;
constexpr const char &back() const;
@@ -123,11 +123,11 @@ class StringRefNull : public StringRefBase {
public:
constexpr StringRefNull();
- constexpr StringRefNull(const char *str, const int64_t size);
+ constexpr StringRefNull(const char *str, int64_t size);
StringRefNull(const char *str);
StringRefNull(const std::string &str);
- constexpr char operator[](const int64_t index) const;
+ constexpr char operator[](int64_t index) const;
constexpr const char *c_str() const;
};
@@ -139,14 +139,14 @@ class StringRef : public StringRefBase {
constexpr StringRef();
constexpr StringRef(StringRefNull other);
constexpr StringRef(const char *str);
- constexpr StringRef(const char *str, const int64_t length);
+ constexpr StringRef(const char *str, int64_t length);
constexpr StringRef(const char *begin, const char *one_after_end);
constexpr StringRef(std::string_view view);
StringRef(const std::string &str);
- constexpr StringRef drop_prefix(const int64_t n) const;
+ constexpr StringRef drop_prefix(int64_t n) const;
constexpr StringRef drop_known_prefix(StringRef prefix) const;
- constexpr StringRef drop_suffix(const int64_t n) const;
+ constexpr StringRef drop_suffix(int64_t n) const;
constexpr char operator[](int64_t index) const;
};
@@ -337,6 +337,18 @@ constexpr int64_t StringRefBase::find(StringRef str, int64_t pos) const
return index_or_npos_to_int64(std::string_view(*this).find(str, static_cast<size_t>(pos)));
}
+constexpr int64_t StringRefBase::rfind(char c, int64_t pos) const
+{
+ BLI_assert(pos >= 0);
+ return index_or_npos_to_int64(std::string_view(*this).rfind(c, static_cast<size_t>(pos)));
+}
+
+constexpr int64_t StringRefBase::rfind(StringRef str, int64_t pos) const
+{
+ BLI_assert(pos >= 0);
+ return index_or_npos_to_int64(std::string_view(*this).rfind(str, static_cast<size_t>(pos)));
+}
+
constexpr int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const
{
BLI_assert(pos >= 0);
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index 72bddb322db..108a2f5fc7d 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -110,14 +110,12 @@ size_t BLI_str_utf8_from_unicode_len(unsigned int c) ATTR_WARN_UNUSED_RESULT;
*
* \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_from_unicode(unsigned int c, char *outbuf, size_t outbuf_len) ATTR_NONNULL(2);
size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w,
const char *__restrict src_c,
- const size_t maxncpy) ATTR_NONNULL(1, 2);
-size_t BLI_str_utf32_as_utf8(char *__restrict dst,
- const char32_t *__restrict src,
- const size_t maxncpy) ATTR_NONNULL(1, 2);
+ size_t maxncpy) ATTR_NONNULL(1, 2);
+size_t BLI_str_utf32_as_utf8(char *__restrict dst, const char32_t *__restrict src, size_t maxncpy)
+ ATTR_NONNULL(1, 2);
/**
* \return The UTF-32 len in UTF-8.
*/
@@ -162,21 +160,20 @@ size_t BLI_wstrlen_utf8(const wchar_t *src) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RES
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)
+size_t BLI_strnlen_utf8_ex(const char *strc, 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_strnlen_utf8(const char *strc, size_t maxlen) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst,
const wchar_t *__restrict src,
- const size_t maxncpy) ATTR_NONNULL(1, 2);
+ size_t maxncpy) ATTR_NONNULL(1, 2);
size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst,
const char *__restrict src,
- const size_t maxncpy) ATTR_NONNULL(1, 2);
+ size_t maxncpy) ATTR_NONNULL(1, 2);
/**
* Count columns that character/string occupies (based on `wcwidth.co`).
@@ -202,8 +199,7 @@ size_t BLI_str_partition_ex_utf8(const char *str,
const unsigned int delim[],
const char **sep,
const char **suf,
- const bool from_right) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL(1, 3, 4, 5);
+ bool from_right) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 3, 4, 5);
int BLI_str_utf8_offset_to_index(const char *str, int offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h
index ce4d0afb933..818bfe8182b 100644
--- a/source/blender/blenlib/BLI_string_utils.h
+++ b/source/blender/blenlib/BLI_string_utils.h
@@ -50,18 +50,18 @@ typedef bool (*UniquenameCheckCallback)(void *arg, const char *name);
* \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);
+size_t BLI_split_name_num(char *left, int *nr, const char *name, 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);
+void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, 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);
+void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, size_t str_len);
/**
* Join strings, return newly allocated string.
@@ -126,8 +126,8 @@ char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
*/
size_t BLI_string_flip_side_name(char *r_name,
const char *from_name,
- const bool strip_number,
- const size_t name_len);
+ bool strip_number,
+ size_t name_len);
/**
* Ensures name is unique (according to criteria specified by caller in unique_check callback),
diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h
index 2740e3740f2..95327ff33b8 100644
--- a/source/blender/blenlib/BLI_sys_types.h
+++ b/source/blender/blenlib/BLI_sys_types.h
@@ -72,8 +72,8 @@ typedef uint64_t u_int64_t;
#include <stddef.h> /* size_t define */
#ifndef __cplusplus
+/* The <uchar.h> standard header is missing on some systems. */
# if defined(__APPLE__) || defined(__NetBSD__)
-/* The <uchar.h> standard header is missing on macOS. */
typedef unsigned int char32_t;
# else
# include <uchar.h>
diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h
index 0d5b2e6e2df..2e5e07d8407 100644
--- a/source/blender/blenlib/BLI_system.h
+++ b/source/blender/blenlib/BLI_system.h
@@ -30,7 +30,7 @@ int BLI_cpu_support_sse2(void);
int BLI_cpu_support_sse41(void);
void BLI_system_backtrace(FILE *fp);
-/* Get CPU brand, result is to be MEM_freeN()-ed. */
+/** Get CPU brand, result is to be MEM_freeN()-ed. */
char *BLI_cpu_brand_string(void);
/**
@@ -45,15 +45,19 @@ char *BLI_cpu_brand_string(void);
*/
void BLI_hostname_get(char *buffer, size_t bufsize);
-/* Get maximum addressable memory in megabytes. */
+/** Get maximum addressable memory in megabytes. */
size_t BLI_system_memory_max_in_megabytes(void);
+/** Get maximum addressable memory in megabytes (clamped to #INT_MAX). */
int BLI_system_memory_max_in_megabytes_int(void);
/* For `getpid`. */
#ifdef WIN32
# define BLI_SYSTEM_PID_H <process.h>
-/* void* since we really do not want to drag Windows.h in to get the proper typedef. */
+/**
+ * \note Use `void *` for `exception` since we really do not want to drag Windows.h
+ * in to get the proper `typedef`.
+ */
void BLI_windows_handle_exception(void *exception);
#else
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index a67de2e2910..e487f8acd98 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -157,7 +157,7 @@ typedef struct TaskParallelTLS {
} TaskParallelTLS;
typedef void (*TaskParallelRangeFunc)(void *__restrict userdata,
- const int iter,
+ int iter,
const TaskParallelTLS *__restrict tls);
typedef void (*TaskParallelInitFunc)(const void *__restrict userdata, void *__restrict chunk);
@@ -210,8 +210,8 @@ typedef struct TaskParallelSettings {
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings);
-void BLI_task_parallel_range(const int start,
- const int stop,
+void BLI_task_parallel_range(int start,
+ int stop,
void *userdata,
TaskParallelRangeFunc func,
const TaskParallelSettings *settings);
@@ -262,8 +262,8 @@ typedef void (*TaskParallelIteratorFunc)(void *__restrict userdata,
void BLI_task_parallel_iterator(void *userdata,
TaskParallelIteratorIterFunc iter_func,
void *init_item,
- const int init_index,
- const int tot_items,
+ int init_index,
+ int tot_items,
TaskParallelIteratorFunc func,
const TaskParallelSettings *settings);
@@ -303,7 +303,7 @@ void BLI_task_parallel_mempool(struct BLI_mempool *mempool,
TaskParallelMempoolFunc func,
const TaskParallelSettings *settings);
-/* TODO(sergey): Think of a better place for this. */
+/** TODO(sergey): Think of a better place for this. */
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
{
memset(settings, 0, sizeof(*settings));
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 6e60430ea38..60ed5f0544a 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -31,7 +31,7 @@
extern "C" {
#endif
-/* for tables, button in UI, etc */
+/** For tables, button in UI, etc. */
#define BLENDER_MAX_THREADS 1024
struct ListBase;
@@ -167,7 +167,7 @@ typedef pthread_cond_t ThreadCondition;
void BLI_condition_init(ThreadCondition *cond);
void BLI_condition_wait(ThreadCondition *cond, ThreadMutex *mutex);
-void BLI_condition_wait_global_mutex(ThreadCondition *cond, const int type);
+void BLI_condition_wait_global_mutex(ThreadCondition *cond, int type);
void BLI_condition_notify_one(ThreadCondition *cond);
void BLI_condition_notify_all(ThreadCondition *cond);
void BLI_condition_end(ThreadCondition *cond);
@@ -210,13 +210,6 @@ void BLI_thread_queue_nowait(ThreadQueue *queue);
# define BLI_thread_local_set(name, value) name = value
#endif /* defined(__APPLE__) */
-/* **** 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);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_timecode.h b/source/blender/blenlib/BLI_timecode.h
index 4eec8aef245..1cd18dc86ab 100644
--- a/source/blender/blenlib/BLI_timecode.h
+++ b/source/blender/blenlib/BLI_timecode.h
@@ -42,11 +42,11 @@ extern "C" {
* \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 fps,
- const short timecode_style) ATTR_NONNULL();
+ size_t maxncpy,
+ int brevity_level,
+ float time_seconds,
+ double fps,
+ short timecode_style) ATTR_NONNULL();
/**
* Generate time string and store in \a str
@@ -56,9 +56,8 @@ size_t BLI_timecode_string_from_time(char *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();
+size_t BLI_timecode_string_from_time_simple(char *str, size_t maxncpy, double time_seconds)
+ ATTR_NONNULL();
/**
* Generate time string and store in \a str
@@ -73,9 +72,9 @@ size_t BLI_timecode_string_from_time_simple(char *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,
- const float time_seconds) ATTR_NONNULL();
+ size_t maxncpy,
+ int brevity_level,
+ float time_seconds) ATTR_NONNULL();
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_timer.h b/source/blender/blenlib/BLI_timer.h
index c219b5502f3..b1cc8d5514f 100644
--- a/source/blender/blenlib/BLI_timer.h
+++ b/source/blender/blenlib/BLI_timer.h
@@ -29,8 +29,11 @@
extern "C" {
#endif
-/* ret < 0: the timer will be removed.
- * ret >= 0: the timer will be called again in ret seconds */
+/**
+ * \return A value of:
+ * - < 0: the timer will be removed.
+ * - >= 0: the timer will be called again in this number of seconds.
+ */
typedef double (*BLI_timer_func)(uintptr_t uuid, void *user_data);
typedef void (*BLI_timer_data_free)(uintptr_t uuid, void *user_data);
@@ -45,10 +48,10 @@ void BLI_timer_register(uintptr_t uuid,
bool BLI_timer_is_registered(uintptr_t uuid);
-/* Returns False when the timer does not exist (anymore). */
+/** Returns False when the timer does not exist (anymore). */
bool BLI_timer_unregister(uintptr_t uuid);
-/* Execute all registered functions that are due. */
+/** Execute all registered functions that are due. */
void BLI_timer_execute(void);
void BLI_timer_free(void);
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 1b9457496ef..c4b31810669 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -638,7 +638,7 @@ extern "C" {
/**
* 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);
+extern bool BLI_memory_is_zero(const void *arr, size_t arr_size);
#endif
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member) \
@@ -651,11 +651,12 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
/** \name String Macros
* \{ */
-/* Macro to convert a value to string in the pre-processor:
+/* Macro to convert a value to string in the preprocessor:
* - `STRINGIFY_ARG`: gives the argument as a string
* - `STRINGIFY_APPEND`: appends any argument 'b' onto the string argument 'a',
- * used by `STRINGIFY` because some preprocessors warn about zero arguments
+ * used by `STRINGIFY` because some preprocessors warn about zero arguments.
* - `STRINGIFY`: gives the argument's value as a string. */
+
#define STRINGIFY_ARG(x) "" #x
#define STRINGIFY_APPEND(a, b) "" a #b
#define STRINGIFY(x) STRINGIFY_APPEND("", x)
@@ -839,6 +840,15 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
/** No-op for expressions we don't want to instantiate, but must remain valid. */
#define EXPR_NOP(expr) (void)(0 ? ((void)(expr), 1) : 0)
+/**
+ * Utility macro that wraps `std::enable_if` to make it a bit easier to use and less verbose for
+ * SFINAE in common cases.
+ *
+ * \note Often one has to invoke this macro with double parenthesis. That's because the condition
+ * often contains a comma and angle brackets are not recognized as parenthesis by the preprocessor.
+ */
+#define BLI_ENABLE_IF(condition) typename std::enable_if_t<(condition)> * = nullptr
+
/** \} */
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index d2b94a6d8ef..1b10a4c0897 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -163,7 +163,7 @@ class Vector {
/**
* Create a vector from a span. The values in the vector are copy constructed.
*/
- template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
Vector(Span<U> values, Allocator allocator = {}) : Vector(NoExceptConstructor(), allocator)
{
const int64_t size = values.size();
@@ -178,7 +178,7 @@ class Vector {
* This allows you to write code like:
* Vector<int> vec = {3, 4, 5};
*/
- template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
Vector(const std::initializer_list<U> &values) : Vector(Span<U>(values))
{
}
@@ -187,9 +187,7 @@ class Vector {
{
}
- template<typename U,
- size_t N,
- typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr>
+ template<typename U, size_t N, BLI_ENABLE_IF((std::is_convertible_v<U, T>))>
Vector(const std::array<U, N> &values) : Vector(Span(values))
{
}
@@ -197,7 +195,7 @@ class Vector {
template<typename InputIt,
/* This constructor should not be called with e.g. Vector(3, 10), because that is
* expected to produce the vector (10, 10, 10). */
- typename std::enable_if_t<!std::is_convertible_v<InputIt, int>> * = nullptr>
+ BLI_ENABLE_IF((!std::is_convertible_v<InputIt, int>))>
Vector(InputIt first, InputIt last, Allocator allocator = {})
: Vector(NoExceptConstructor(), allocator)
{
@@ -326,13 +324,13 @@ class Vector {
return MutableSpan<T>(begin_, this->size());
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
operator Span<U>() const
{
return Span<U>(begin_, this->size());
}
- template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr>
+ template<typename U, BLI_ENABLE_IF((is_span_convertible_pointer_v<T, U>))>
operator MutableSpan<U>()
{
return MutableSpan<U>(begin_, this->size());
@@ -637,7 +635,7 @@ class Vector {
* Insert values at the beginning of the vector. The has to move all the other elements, so it
* has a linear running time.
*/
- void prepend(const T &&value)
+ void prepend(const T &value)
{
this->insert(0, value);
}
diff --git a/source/blender/blenlib/BLI_vector_set.hh b/source/blender/blenlib/BLI_vector_set.hh
index 567e4fd8128..0aac96f93bc 100644
--- a/source/blender/blenlib/BLI_vector_set.hh
+++ b/source/blender/blenlib/BLI_vector_set.hh
@@ -263,7 +263,7 @@ class VectorSet {
}
/**
- * Get an Span referencing the keys vector. The referenced memory buffer is only valid as
+ * Get a Span referencing the keys vector. The referenced memory buffer is only valid as
* long as the vector set is not changed.
*
* The keys must not be changed, because this would change their hash value.
@@ -465,6 +465,14 @@ class VectorSet {
}
/**
+ * Get an index range containing all valid indices for this array.
+ */
+ IndexRange index_range() const
+ {
+ return IndexRange(this->size());
+ }
+
+ /**
* Print common statistics like size and collision count. This is useful for debugging purposes.
*/
void print_stats(StringRef name = "") const
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index 5103ac4b668..231ce1bdd67 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -44,7 +44,7 @@
namespace blender {
-/* Forward declarations for generic virtual arrays. */
+/** Forward declarations for generic virtual arrays. */
namespace fn {
class GVArray;
class GVMutableArray;
@@ -79,7 +79,7 @@ template<typename T> class VArrayImpl {
* Get the element at #index. This does not return a reference, because the value may be computed
* on the fly.
*/
- virtual T get(const int64_t index) const = 0;
+ virtual T get(int64_t index) const = 0;
/**
* Return true when the virtual array is a plain array internally.
@@ -194,7 +194,7 @@ template<typename T> class VArrayImpl {
}
};
-/* Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */
+/** Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */
template<typename T> class VMutableArrayImpl : public VArrayImpl<T> {
public:
using VArrayImpl<T>::VArrayImpl;
@@ -202,7 +202,7 @@ template<typename T> class VMutableArrayImpl : public VArrayImpl<T> {
/**
* Assign the provided #value to the #index.
*/
- virtual void set(const int64_t index, T value) = 0;
+ virtual void set(int64_t index, T value) = 0;
/**
* Copy all elements from the provided span into the virtual array.
@@ -477,9 +477,9 @@ template<typename T> struct VArrayAnyExtraInfo {
template<typename StorageT> static VArrayAnyExtraInfo get()
{
/* These are the only allowed types in the #Any. */
- static_assert(std::is_base_of_v<VArrayImpl<T>, StorageT> ||
- std::is_same_v<StorageT, const VArrayImpl<T> *> ||
- std::is_same_v<StorageT, std::shared_ptr<const VArrayImpl<T>>>);
+ static_assert(
+ std::is_base_of_v<VArrayImpl<T>, StorageT> ||
+ is_same_any_v<StorageT, const VArrayImpl<T> *, std::shared_ptr<const VArrayImpl<T>>>);
/* Depending on how the virtual array implementation is stored in the #Any, a different
* #get_varray function is required. */
diff --git a/source/blender/blenlib/BLI_virtual_vector_array.hh b/source/blender/blenlib/BLI_virtual_vector_array.hh
index ab5afd2d80a..7960c6b1420 100644
--- a/source/blender/blenlib/BLI_virtual_vector_array.hh
+++ b/source/blender/blenlib/BLI_virtual_vector_array.hh
@@ -29,7 +29,7 @@
namespace blender {
-/* A readonly virtual array of vectors. */
+/** A read-only virtual array of vectors. */
template<typename T> class VVectorArray {
protected:
int64_t size_;
@@ -82,9 +82,9 @@ template<typename T> class VVectorArray {
}
protected:
- virtual int64_t get_vector_size_impl(const int64_t index) const = 0;
+ virtual int64_t get_vector_size_impl(int64_t index) const = 0;
- virtual T get_vector_element_impl(const int64_t index, const int64_t index_in_vetor) const = 0;
+ virtual T get_vector_element_impl(int64_t index, int64_t index_in_vetor) const = 0;
virtual bool is_single_vector_impl() const
{
diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h
index cbf1716602a..2ea557e971a 100644
--- a/source/blender/blenlib/BLI_winstuff.h
+++ b/source/blender/blenlib/BLI_winstuff.h
@@ -88,7 +88,7 @@ typedef SSIZE_T ssize_t;
# endif
#endif
-/* Directory reading compatibility with UNIX. */
+/** Directory reading compatibility with UNIX. */
struct dirent {
int d_ino;
int d_off;
@@ -96,7 +96,7 @@ struct dirent {
char *d_name;
};
-/* intentionally opaque to users */
+/** Intentionally opaque to users. */
typedef struct __dirstream DIR;
DIR *opendir(const char *path);
@@ -105,7 +105,8 @@ int closedir(DIR *dp);
const char *dirname(char *path);
/* Windows utility functions. */
-bool BLI_windows_register_blend_extension(const bool background);
+
+bool BLI_windows_register_blend_extension(bool background);
void BLI_windows_get_default_root_dir(char root_dir[4]);
int BLI_windows_get_executable_dir(char *str);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 29493c799b3..e9446f36c83 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -25,7 +25,6 @@ set(INC
../../../intern/atomic
../../../intern/eigen
../../../intern/guardedalloc
- ../../../intern/numaapi/include
../../../extern/wcwidth
../../../extern/json/include
)
@@ -76,6 +75,7 @@ set(SRC
intern/endian_switch.c
intern/expr_pylike_eval.c
intern/fileops.c
+ intern/fileops.cc
intern/filereader_file.c
intern/filereader_gzip.c
intern/filereader_memory.c
@@ -126,8 +126,8 @@ set(SRC
intern/resource_scope.cc
intern/scanfill.c
intern/scanfill_utils.c
- intern/session_uuid.c
intern/serialize.cc
+ intern/session_uuid.c
intern/smallhash.c
intern/sort.c
intern/sort_utils.c
@@ -192,8 +192,6 @@ set(SRC
BLI_dlrbTree.h
BLI_dot_export.hh
BLI_dot_export_attribute_enums.hh
- BLI_double2.hh
- BLI_double3.hh
BLI_dynlib.h
BLI_dynstr.h
BLI_easing.h
@@ -204,11 +202,9 @@ set(SRC
BLI_enumerable_thread_specific.hh
BLI_expr_pylike_eval.h
BLI_fileops.h
+ BLI_fileops.hh
BLI_fileops_types.h
BLI_filereader.h
- BLI_float2.hh
- BLI_float3.hh
- BLI_float4.hh
BLI_float4x4.hh
BLI_fnmatch.h
BLI_function_ref.hh
@@ -256,6 +252,8 @@ set(SRC
BLI_math_solvers.h
BLI_math_statistics.h
BLI_math_time.h
+ BLI_math_vec_mpq_types.hh
+ BLI_math_vec_types.hh
BLI_math_vector.h
BLI_memarena.h
BLI_memblock.h
@@ -266,8 +264,6 @@ set(SRC
BLI_mesh_boolean.hh
BLI_mesh_intersect.hh
BLI_mmap.h
- BLI_mpq2.hh
- BLI_mpq3.hh
BLI_multi_value_map.hh
BLI_noise.h
BLI_noise.hh
@@ -282,10 +278,10 @@ set(SRC
BLI_rect.h
BLI_resource_scope.hh
BLI_scanfill.h
+ BLI_serialize.hh
BLI_session_uuid.h
BLI_set.hh
BLI_set_slots.hh
- BLI_serialize.hh
BLI_simd.h
BLI_smallhash.h
BLI_sort.h
@@ -332,7 +328,6 @@ set(SRC
set(LIB
bf_intern_eigen
bf_intern_guardedalloc
- bf_intern_numaapi
extern_wcwidth
${ZLIB_LIBRARIES}
@@ -421,6 +416,7 @@ if(WITH_GTESTS)
tests/BLI_disjoint_set_test.cc
tests/BLI_edgehash_test.cc
tests/BLI_expr_pylike_eval_test.cc
+ tests/BLI_fileops_test.cc
tests/BLI_function_ref_test.cc
tests/BLI_ghash_test.cc
tests/BLI_hash_mm2a_test.cc
@@ -443,6 +439,7 @@ if(WITH_GTESTS)
tests/BLI_math_rotation_test.cc
tests/BLI_math_solvers_test.cc
tests/BLI_math_time_test.cc
+ tests/BLI_math_vec_types_test.cc
tests/BLI_math_vector_test.cc
tests/BLI_memiter_test.cc
tests/BLI_memory_utils_test.cc
@@ -452,12 +449,12 @@ if(WITH_GTESTS)
tests/BLI_path_util_test.cc
tests/BLI_polyfill_2d_test.cc
tests/BLI_ressource_strings.h
+ tests/BLI_serialize_test.cc
tests/BLI_session_uuid_test.cc
tests/BLI_set_test.cc
tests/BLI_span_test.cc
tests/BLI_stack_cxx_test.cc
tests/BLI_stack_test.cc
- tests/BLI_serialize_test.cc
tests/BLI_string_ref_test.cc
tests/BLI_string_search_test.cc
tests/BLI_string_test.cc
diff --git a/source/blender/blenlib/intern/BLI_mempool_private.h b/source/blender/blenlib/intern/BLI_mempool_private.h
index 90569d87c41..03b0b11297b 100644
--- a/source/blender/blenlib/intern/BLI_mempool_private.h
+++ b/source/blender/blenlib/intern/BLI_mempool_private.h
@@ -54,8 +54,9 @@ typedef struct ParallelMempoolTaskData {
*
* 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();
+ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool,
+ size_t num_iter) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
void mempool_iter_threadsafe_destroy(ParallelMempoolTaskData *iter_arr) ATTR_NONNULL();
/**
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index 08696c9168d..825682736e8 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -439,7 +439,7 @@ static void bchunk_list_ensure_min_size_last(const BArrayInfo *info,
if (data_merge_len <= info->chunk_byte_size_max) {
/* we have enough space to merge */
- /* remove last from linklist */
+ /* Remove last from the linked-list. */
BLI_assert(chunk_list->chunk_refs.last != chunk_list->chunk_refs.first);
cref->prev->next = NULL;
chunk_list->chunk_refs.last = cref->prev;
diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc
index 53e881a9fc7..842e6cb6135 100644
--- a/source/blender/blenlib/intern/delaunay_2d.cc
+++ b/source/blender/blenlib/intern/delaunay_2d.cc
@@ -25,11 +25,10 @@
#include <sstream>
#include "BLI_array.hh"
-#include "BLI_double2.hh"
#include "BLI_linklist.h"
#include "BLI_math_boolean.hh"
#include "BLI_math_mpq.hh"
-#include "BLI_mpq2.hh"
+#include "BLI_math_vec_mpq_types.hh"
#include "BLI_set.hh"
#include "BLI_task.hh"
#include "BLI_vector.hh"
@@ -38,6 +37,8 @@
namespace blender::meshintersect {
+using namespace blender::math;
+
/* Throughout this file, template argument T will be an
* arithmetic-like type, like float, double, or mpq_class. */
@@ -788,11 +789,11 @@ bool in_line<mpq_class>(const FatCo<mpq_class> &a,
}
vec2<mpq_class> exact_ab = b.exact - a.exact;
vec2<mpq_class> exact_ac = c.exact - a.exact;
- if (vec2<mpq_class>::dot(exact_ab, exact_ac) < 0) {
+ if (dot(exact_ab, exact_ac) < 0) {
return false;
}
vec2<mpq_class> exact_bc = c.exact - b.exact;
- return vec2<mpq_class>::dot(exact_bc, exact_ac) >= 0;
+ return dot(exact_bc, exact_ac) >= 0;
}
#endif
@@ -801,11 +802,11 @@ bool in_line<double>(const FatCo<double> &a, const FatCo<double> &b, const FatCo
{
vec2<double> ab = b.approx - a.approx;
vec2<double> ac = c.approx - a.approx;
- if (vec2<double>::dot(ab, ac) < 0) {
+ if (dot(ab, ac) < 0) {
return false;
}
vec2<double> bc = c.approx - b.approx;
- return vec2<double>::dot(bc, ac) >= 0;
+ return dot(bc, ac) >= 0;
}
template<> CDTVert<double>::CDTVert(const vec2<double> &pt)
@@ -1081,7 +1082,7 @@ template<typename T> CDTEdge<T> *CDTArrangement<T>::split_edge(SymEdge<T> *se, T
SymEdge<T> *sesymprev = prev(sesym);
SymEdge<T> *sesymprevsym = sym(sesymprev);
SymEdge<T> *senext = se->next;
- CDTVert<T> *v = this->add_vert(vec2<T>::interpolate(*a, *b, lambda));
+ CDTVert<T> *v = this->add_vert(interpolate(*a, *b, lambda));
CDTEdge<T> *e = this->add_edge(v, se->next->vert, se->face, sesym->face);
sesym->vert = v;
SymEdge<T> *newse = &e->symedges[0];
@@ -1704,16 +1705,16 @@ void fill_crossdata_for_intersect(const FatCo<T> &curco,
BLI_assert(se_vcva->vert == vc && se_vcva->next->vert == va);
BLI_assert(se_vcvb->vert == vc && se_vcvb->next->vert == vb);
UNUSED_VARS_NDEBUG(vc);
- auto isect = vec2<T>::isect_seg_seg(va->co.exact, vb->co.exact, curco.exact, v2->co.exact);
+ auto isect = isect_seg_seg<vec2<T>>(va->co.exact, vb->co.exact, curco.exact, v2->co.exact);
T &lambda = isect.lambda;
switch (isect.kind) {
- case vec2<T>::isect_result::LINE_LINE_CROSS: {
+ case isect_result<vec2<T>>::LINE_LINE_CROSS: {
#ifdef WITH_GMP
if (!std::is_same<T, mpq_class>::value) {
#else
if (true) {
#endif
- double len_ab = vec2<double>::distance(va->co.approx, vb->co.approx);
+ double len_ab = distance(va->co.approx, vb->co.approx);
if (lambda * len_ab <= epsilon) {
fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next);
}
@@ -1735,7 +1736,7 @@ void fill_crossdata_for_intersect(const FatCo<T> &curco,
}
break;
}
- case vec2<T>::isect_result::LINE_LINE_EXACT: {
+ case isect_result<vec2<T>>::LINE_LINE_EXACT: {
if (lambda == 0) {
fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next);
}
@@ -1750,7 +1751,7 @@ void fill_crossdata_for_intersect(const FatCo<T> &curco,
}
break;
}
- case vec2<T>::isect_result::LINE_LINE_NONE: {
+ case isect_result<vec2<T>>::LINE_LINE_NONE: {
#ifdef WITH_GMP
if (std::is_same<T, mpq_class>::value) {
BLI_assert(false);
@@ -1766,9 +1767,9 @@ void fill_crossdata_for_intersect(const FatCo<T> &curco,
}
break;
}
- case vec2<T>::isect_result::LINE_LINE_COLINEAR: {
- if (vec2<double>::distance_squared(va->co.approx, v2->co.approx) <=
- vec2<double>::distance_squared(vb->co.approx, v2->co.approx)) {
+ case isect_result<vec2<T>>::LINE_LINE_COLINEAR: {
+ if (distance_squared(va->co.approx, v2->co.approx) <=
+ distance_squared(vb->co.approx, v2->co.approx)) {
fill_crossdata_for_through_vert(va, se_vcva, cd, cd_next);
}
else {
@@ -1845,7 +1846,7 @@ void get_next_crossing_from_edge(CrossData<T> *cd,
{
CDTVert<T> *va = cd->in->vert;
CDTVert<T> *vb = cd->in->next->vert;
- vec2<T> curco = vec2<T>::interpolate(va->co.exact, vb->co.exact, cd->lambda);
+ vec2<T> curco = interpolate(va->co.exact, vb->co.exact, cd->lambda);
FatCo<T> fat_curco(curco);
SymEdge<T> *se_ac = sym(cd->in)->next;
CDTVert<T> *vc = se_ac->next->vert;
@@ -2386,7 +2387,7 @@ template<typename T> void remove_non_constraint_edges_leave_valid_bmesh(CDT_stat
dissolvable_edges[i].e = e;
const vec2<double> &co1 = e->symedges[0].vert->co.approx;
const vec2<double> &co2 = e->symedges[1].vert->co.approx;
- dissolvable_edges[i].len_squared = vec2<double>::distance_squared(co1, co2);
+ dissolvable_edges[i].len_squared = distance_squared(co1, co2);
i++;
}
}
@@ -2569,18 +2570,18 @@ template<typename T> void detect_holes(CDT_state<T> *cdt_state)
if (e->symedges[0].face->visit_index == e->symedges[1].face->visit_index) {
continue; /* Don't count hits on edges between faces in same region. */
}
- auto isect = vec2<T>::isect_seg_seg(ray_end.exact,
+ auto isect = isect_seg_seg<vec2<T>>(ray_end.exact,
mid.exact,
e->symedges[0].vert->co.exact,
e->symedges[1].vert->co.exact);
switch (isect.kind) {
- case vec2<T>::isect_result::LINE_LINE_CROSS: {
+ case isect_result<vec2<T>>::LINE_LINE_CROSS: {
hits++;
break;
}
- case vec2<T>::isect_result::LINE_LINE_EXACT:
- case vec2<T>::isect_result::LINE_LINE_NONE:
- case vec2<T>::isect_result::LINE_LINE_COLINEAR:
+ case isect_result<vec2<T>>::LINE_LINE_EXACT:
+ case isect_result<vec2<T>>::LINE_LINE_NONE:
+ case isect_result<vec2<T>>::LINE_LINE_COLINEAR:
break;
}
}
diff --git a/source/blender/blenlib/intern/fileops.cc b/source/blender/blenlib/intern/fileops.cc
new file mode 100644
index 00000000000..5ceedbd8cb5
--- /dev/null
+++ b/source/blender/blenlib/intern/fileops.cc
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_fileops.hh"
+
+#ifdef WIN32
+# include "utfconv.h"
+#endif
+
+namespace blender {
+fstream::fstream(const char *filepath, std::ios_base::openmode mode)
+{
+ this->open(filepath, mode);
+}
+
+fstream::fstream(const std::string &filepath, std::ios_base::openmode mode)
+{
+ this->open(filepath, mode);
+}
+
+void fstream::open(StringRefNull filepath, ios_base::openmode mode)
+{
+#ifdef WIN32
+ const char *filepath_cstr = filepath.c_str();
+ UTF16_ENCODE(filepath_cstr);
+ std::wstring filepath_wstr(filepath_cstr_16);
+ std::fstream::open(filepath_wstr.c_str(), mode);
+ UTF16_UN_ENCODE(filepath_cstr);
+#else
+ std::fstream::open(filepath, mode);
+#endif
+}
+
+} // namespace blender
diff --git a/source/blender/blenlib/intern/kdtree_impl.h b/source/blender/blenlib/intern/kdtree_impl.h
index 0b47be1f7ea..c0e740b39b3 100644
--- a/source/blender/blenlib/intern/kdtree_impl.h
+++ b/source/blender/blenlib/intern/kdtree_impl.h
@@ -594,7 +594,7 @@ int BLI_kdtree_nd_(find_nearest_n_with_len_squared_cb)(
int BLI_kdtree_nd_(find_nearest_n)(const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest r_nearest[],
- const uint nearest_len_capacity)
+ uint nearest_len_capacity)
{
return BLI_kdtree_nd_(find_nearest_n_with_len_squared_cb)(
tree, co, r_nearest, nearest_len_capacity, NULL, NULL);
@@ -726,7 +726,7 @@ int BLI_kdtree_nd_(range_search_with_len_squared_cb)(
int BLI_kdtree_nd_(range_search)(const KDTree *tree,
const float co[KD_DIMS],
KDTreeNearest **r_nearest,
- const float range)
+ float range)
{
return BLI_kdtree_nd_(range_search_with_len_squared_cb)(tree, co, r_nearest, range, NULL, NULL);
}
diff --git a/source/blender/blenlib/intern/list_sort_impl.h b/source/blender/blenlib/intern/list_sort_impl.h
index 71f7f0e29a8..626956e2fb6 100644
--- a/source/blender/blenlib/intern/list_sort_impl.h
+++ b/source/blender/blenlib/intern/list_sort_impl.h
@@ -34,7 +34,7 @@
* - `SORT_IMPL_LINKTYPE`:
* Struct type for sorting.
* - `SORT_IMPL_LINKTYPE_DATA`:
- * Data pointer or leave undefined to pass the link its self.
+ * Data pointer or leave undefined to pass the link itself.
* - `SORT_IMPL_FUNC`:
* Function name of the sort function.
*
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index a166c846ea7..513b08a589d 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -749,6 +749,26 @@ int BLI_findstringindex(const ListBase *listbase, const char *id, const int offs
return -1;
}
+ListBase BLI_listbase_from_link(Link *some_link)
+{
+ ListBase list = {some_link, some_link};
+ if (some_link == NULL) {
+ return list;
+ }
+
+ /* Find the first element. */
+ while (((Link *)list.first)->prev != NULL) {
+ list.first = ((Link *)list.first)->prev;
+ }
+
+ /* Find the last element. */
+ while (((Link *)list.last)->next != NULL) {
+ list.last = ((Link *)list.last)->next;
+ }
+
+ return list;
+}
+
void BLI_duplicatelist(ListBase *dst, const ListBase *src)
{
struct Link *dst_link, *src_link;
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 53cf2d61963..cfcc54b1136 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -398,7 +398,7 @@ MINLINE float fractf(float a)
return a - floorf(a);
}
-/* Adapted from godot-engine math_funcs.h. */
+/* Adapted from `godot-engine` math_funcs.h. */
MINLINE float wrapf(float value, float max, float min)
{
float range = max - min;
@@ -722,15 +722,15 @@ MINLINE int integer_digits_i(const int i)
#ifdef BLI_HAVE_SSE2
-/* Calculate initial guess for arg^exp based on float representation
+/**
+ * Calculate initial guess for `arg^exp` based on float representation
* This method gives a constant bias, which can be easily compensated by
* multiplying with bias_coeff.
- * Gives better results for exponents near 1 (e. g. 4/5).
+ * Gives better results for exponents near 1 (e.g. `4/5`).
* exp = exponent, encoded as uint32_t
- * e2coeff = 2^(127/exponent - 127) * bias_coeff^(1/exponent), encoded as
- * uint32_t
+ * `e2coeff = 2^(127/exponent - 127) * bias_coeff^(1/exponent)`, encoded as `uint32_t`.
*
- * We hope that exp and e2coeff gets properly inlined
+ * We hope that exp and e2coeff gets properly inlined.
*/
MALWAYS_INLINE __m128 _bli_math_fastpow(const int exp, const int e2coeff, const __m128 arg)
{
@@ -742,7 +742,7 @@ MALWAYS_INLINE __m128 _bli_math_fastpow(const int exp, const int e2coeff, const
return ret;
}
-/* Improve x ^ 1.0f/5.0f solution with Newton-Raphson method */
+/** Improve `x ^ 1.0f/5.0f` solution with Newton-Raphson method */
MALWAYS_INLINE __m128 _bli_math_improve_5throot_solution(const __m128 old_result, const __m128 x)
{
__m128 approx2 = _mm_mul_ps(old_result, old_result);
@@ -752,7 +752,7 @@ MALWAYS_INLINE __m128 _bli_math_improve_5throot_solution(const __m128 old_result
return _mm_mul_ps(summ, _mm_set1_ps(1.0f / 5.0f));
}
-/* Calculate powf(x, 2.4). Working domain: 1e-10 < x < 1e+10 */
+/** Calculate `powf(x, 2.4)`. Working domain: `1e-10 < x < 1e+10`. */
MALWAYS_INLINE __m128 _bli_math_fastpow24(const __m128 arg)
{
/* max, avg and |avg| errors were calculated in gcc without FMA instructions
diff --git a/source/blender/blenlib/intern/math_boolean.cc b/source/blender/blenlib/intern/math_boolean.cc
index c16755868aa..0bae3c23f79 100644
--- a/source/blender/blenlib/intern/math_boolean.cc
+++ b/source/blender/blenlib/intern/math_boolean.cc
@@ -18,15 +18,10 @@
* \ingroup bli
*/
-#include "BLI_double2.hh"
-#include "BLI_double3.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_hash.hh"
#include "BLI_math_boolean.hh"
#include "BLI_math_mpq.hh"
-#include "BLI_mpq2.hh"
-#include "BLI_mpq3.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c
index 53257cc9285..73ecb2cf798 100644
--- a/source/blender/blenlib/intern/math_color_blend_inline.c
+++ b/source/blender/blenlib/intern/math_color_blend_inline.c
@@ -382,7 +382,7 @@ MINLINE void blend_color_pinlight_byte(uchar dst[4], const uchar src1[4], const
else {
temp = min_ii(2 * src2[i], src1[i]);
}
- dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
+ dst[i] = (uchar)((min_ii(temp, 255) * fac + src1[i] * mfac) / 255);
}
}
else {
@@ -473,7 +473,7 @@ MINLINE void blend_color_exclusion_byte(uchar dst[4], const uchar src1[4], const
int i = 3;
while (i--) {
- const int temp = 127 - ((2 * (src1[i] - 127) * (src2[i] - 127)) / 255);
+ const int temp = 127 - min_ii(((2 * (src1[i] - 127) * (src2[i] - 127)) / 255), 127);
dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
}
}
@@ -896,15 +896,9 @@ MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], cons
int i = 3;
while (i--) {
- float temp;
-
- if (src1[i] < 0.5f) {
- temp = (src2[i] + 0.5f) * src1[i];
- }
- else {
- temp = 1.0f - ((1.0f - (src2[i] + 0.5f)) * (1.0f - src1[i]));
- }
- dst[i] = (temp * fac + src1[i] * mfac);
+ float screen = 1.0f - (1.0f - src1[i]) * (1.0f - src2[i]);
+ float soft_light = ((1.0f - src1[i]) * src2[i] + screen) * src1[i];
+ dst[i] = src1[i] * mfac + soft_light * fac;
}
}
else {
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index febe1568176..a7f229e7147 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -261,7 +261,7 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
}
/* -------------------------------------------------------------------- */
-/** \name RGB/Grayscale Functions
+/** \name RGB/Gray-Scale Functions
*
* \warning
* These are only an approximation,
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index a155877513a..3800fc58a5b 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -3720,7 +3720,7 @@ void barycentric_weights_v2_quad(const float v1[2],
/* NOTE(campbell): fabsf() here is not needed for convex quads
* (and not used in #interp_weights_poly_v2).
* But in the case of concave/bow-tie quads for the mask rasterizer it
- * gives unreliable results without adding absf(). If this becomes an issue for more general
+ * gives unreliable results without adding `absf()`. If this becomes an issue for more general
* usage we could have this optional or use a different function. */
#define MEAN_VALUE_HALF_TAN_V2(_area, i1, i2) \
((_area = cross_v2v2(dirs[i1], dirs[i2])) != 0.0f ? \
diff --git a/source/blender/blenlib/intern/math_vec.cc b/source/blender/blenlib/intern/math_vec.cc
index 223c0e273f0..6fab6c9a383 100644
--- a/source/blender/blenlib/intern/math_vec.cc
+++ b/source/blender/blenlib/intern/math_vec.cc
@@ -18,89 +18,83 @@
* \ingroup bli
*/
-#include "BLI_double2.hh"
-#include "BLI_double3.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_hash.hh"
-#include "BLI_math_mpq.hh"
-#include "BLI_mpq2.hh"
-#include "BLI_mpq3.hh"
+#include "BLI_math_vec_mpq_types.hh"
+#include "BLI_math_vector.hh"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
-namespace blender {
+namespace blender::math {
-float2::isect_result float2::isect_seg_seg(const float2 &v1,
- const float2 &v2,
- const float2 &v3,
- const float2 &v4)
+template<>
+isect_result<float2> isect_seg_seg(const float2 &v1,
+ const float2 &v2,
+ const float2 &v3,
+ const float2 &v4)
{
- float2::isect_result ans;
+ isect_result<float2> ans;
float div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
if (div == 0.0f) {
ans.lambda = 0.0f;
- ans.mu = 0.0f;
- ans.kind = float2::isect_result::LINE_LINE_COLINEAR;
+ ans.kind = isect_result<float2>::LINE_LINE_COLINEAR;
}
else {
ans.lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
- ans.mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
- if (ans.lambda >= 0.0f && ans.lambda <= 1.0f && ans.mu >= 0.0f && ans.mu <= 1.0f) {
- if (ans.lambda == 0.0f || ans.lambda == 1.0f || ans.mu == 0.0f || ans.mu == 1.0f) {
- ans.kind = float2::isect_result::LINE_LINE_EXACT;
+ float mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
+ if (ans.lambda >= 0.0f && ans.lambda <= 1.0f && mu >= 0.0f && mu <= 1.0f) {
+ if (ans.lambda == 0.0f || ans.lambda == 1.0f || mu == 0.0f || mu == 1.0f) {
+ ans.kind = isect_result<float2>::LINE_LINE_EXACT;
}
else {
- ans.kind = float2::isect_result::LINE_LINE_CROSS;
+ ans.kind = isect_result<float2>::LINE_LINE_CROSS;
}
}
else {
- ans.kind = float2::isect_result::LINE_LINE_NONE;
+ ans.kind = isect_result<float2>::LINE_LINE_NONE;
}
}
return ans;
}
-double2::isect_result double2::isect_seg_seg(const double2 &v1,
- const double2 &v2,
- const double2 &v3,
- const double2 &v4)
+template<>
+isect_result<double2> isect_seg_seg(const double2 &v1,
+ const double2 &v2,
+ const double2 &v3,
+ const double2 &v4)
{
- double2::isect_result ans;
+ isect_result<double2> ans;
double div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
if (div == 0.0) {
ans.lambda = 0.0;
- ans.kind = double2::isect_result::LINE_LINE_COLINEAR;
+ ans.kind = isect_result<double2>::LINE_LINE_COLINEAR;
}
else {
ans.lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
double mu = ((v1[1] - v3[1]) * (v2[0] - v1[0]) - (v1[0] - v3[0]) * (v2[1] - v1[1])) / div;
if (ans.lambda >= 0.0 && ans.lambda <= 1.0 && mu >= 0.0 && mu <= 1.0) {
if (ans.lambda == 0.0 || ans.lambda == 1.0 || mu == 0.0 || mu == 1.0) {
- ans.kind = double2::isect_result::LINE_LINE_EXACT;
+ ans.kind = isect_result<double2>::LINE_LINE_EXACT;
}
else {
- ans.kind = double2::isect_result::LINE_LINE_CROSS;
+ ans.kind = isect_result<double2>::LINE_LINE_CROSS;
}
}
else {
- ans.kind = double2::isect_result::LINE_LINE_NONE;
+ ans.kind = isect_result<double2>::LINE_LINE_NONE;
}
}
return ans;
}
#ifdef WITH_GMP
-mpq2::isect_result mpq2::isect_seg_seg(const mpq2 &v1,
- const mpq2 &v2,
- const mpq2 &v3,
- const mpq2 &v4)
+template<>
+isect_result<mpq2> isect_seg_seg(const mpq2 &v1, const mpq2 &v2, const mpq2 &v3, const mpq2 &v4)
{
- mpq2::isect_result ans;
+ isect_result<mpq2> ans;
mpq_class div = (v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]);
if (div == 0.0) {
ans.lambda = 0.0;
- ans.kind = mpq2::isect_result::LINE_LINE_COLINEAR;
+ ans.kind = isect_result<mpq2>::LINE_LINE_COLINEAR;
}
else {
ans.lambda = ((v1[1] - v3[1]) * (v4[0] - v3[0]) - (v1[0] - v3[0]) * (v4[1] - v3[1])) / div;
@@ -109,66 +103,21 @@ mpq2::isect_result mpq2::isect_seg_seg(const mpq2 &v1,
if (ans.lambda >= 0 && ans.lambda <= 1 &&
((div > 0 && mudiv >= 0 && mudiv <= div) || (div < 0 && mudiv <= 0 && mudiv >= div))) {
if (ans.lambda == 0 || ans.lambda == 1 || mudiv == 0 || mudiv == div) {
- ans.kind = mpq2::isect_result::LINE_LINE_EXACT;
+ ans.kind = isect_result<mpq2>::LINE_LINE_EXACT;
}
else {
- ans.kind = mpq2::isect_result::LINE_LINE_CROSS;
+ ans.kind = isect_result<mpq2>::LINE_LINE_CROSS;
}
}
else {
- ans.kind = mpq2::isect_result::LINE_LINE_NONE;
+ ans.kind = isect_result<mpq2>::LINE_LINE_NONE;
}
}
return ans;
}
#endif
-double3 double3::cross_poly(Span<double3> poly)
-{
- /* Newell's Method. */
- int nv = static_cast<int>(poly.size());
- if (nv < 3) {
- return double3(0, 0, 0);
- }
- const double3 *v_prev = &poly[nv - 1];
- const double3 *v_curr = &poly[0];
- double3 n(0, 0, 0);
- for (int i = 0; i < nv;) {
- n[0] = n[0] + ((*v_prev)[1] - (*v_curr)[1]) * ((*v_prev)[2] + (*v_curr)[2]);
- n[1] = n[1] + ((*v_prev)[2] - (*v_curr)[2]) * ((*v_prev)[0] + (*v_curr)[0]);
- n[2] = n[2] + ((*v_prev)[0] - (*v_curr)[0]) * ((*v_prev)[1] + (*v_curr)[1]);
- v_prev = v_curr;
- ++i;
- if (i < nv) {
- v_curr = &poly[i];
- }
- }
- return n;
-}
-
#ifdef WITH_GMP
-mpq3 mpq3::cross_poly(Span<mpq3> poly)
-{
- /* Newell's Method. */
- int nv = static_cast<int>(poly.size());
- if (nv < 3) {
- return mpq3(0);
- }
- const mpq3 *v_prev = &poly[nv - 1];
- const mpq3 *v_curr = &poly[0];
- mpq3 n(0);
- for (int i = 0; i < nv;) {
- n[0] = n[0] + ((*v_prev)[1] - (*v_curr)[1]) * ((*v_prev)[2] + (*v_curr)[2]);
- n[1] = n[1] + ((*v_prev)[2] - (*v_curr)[2]) * ((*v_prev)[0] + (*v_curr)[0]);
- n[2] = n[2] + ((*v_prev)[0] - (*v_curr)[0]) * ((*v_prev)[1] + (*v_curr)[1]);
- v_prev = v_curr;
- ++i;
- if (i < nv) {
- v_curr = &poly[i];
- }
- }
- return n;
-}
uint64_t hash_mpq_class(const mpq_class &value)
{
@@ -176,20 +125,6 @@ uint64_t hash_mpq_class(const mpq_class &value)
return get_default_hash(static_cast<float>(value.get_d()));
}
-uint64_t mpq2::hash() const
-{
- uint64_t hashx = hash_mpq_class(this->x);
- uint64_t hashy = hash_mpq_class(this->y);
- return hashx ^ (hashy * 33);
-}
-
-uint64_t mpq3::hash() const
-{
- uint64_t hashx = hash_mpq_class(this->x);
- uint64_t hashy = hash_mpq_class(this->y);
- uint64_t hashz = hash_mpq_class(this->z);
- return hashx ^ (hashy * 33) ^ (hashz * 33 * 37);
-}
#endif
-} // namespace blender
+} // namespace blender::math
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 648f876acaa..3022dbbe4ff 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -438,13 +438,6 @@ MINLINE void add_v3fl_v3fl_v3i(float r[3], const float a[3], const int b[3])
r[2] = a[2] + (float)b[2];
}
-MINLINE void add_v3fl_v3fl_v3s(float r[3], const float a[3], const short b[3])
-{
- r[0] = a[0] + (float)b[0];
- r[1] = a[1] + (float)b[1];
- r[2] = a[2] + (float)b[2];
-}
-
MINLINE void add_v4_v4(float r[4], const float a[4])
{
r[0] += a[0];
diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc
index ce4db0c6b9d..a3eae1896d3 100644
--- a/source/blender/blenlib/intern/mesh_boolean.cc
+++ b/source/blender/blenlib/intern/mesh_boolean.cc
@@ -28,8 +28,6 @@
# include "BLI_array.hh"
# include "BLI_assert.h"
# include "BLI_delaunay_2d.h"
-# include "BLI_double3.hh"
-# include "BLI_float3.hh"
# include "BLI_hash.hh"
# include "BLI_kdopbvh.h"
# include "BLI_map.hh"
@@ -37,8 +35,9 @@
# include "BLI_math_boolean.hh"
# include "BLI_math_geom.h"
# include "BLI_math_mpq.hh"
+# include "BLI_math_vec_mpq_types.hh"
+# include "BLI_math_vec_types.hh"
# include "BLI_mesh_intersect.hh"
-# include "BLI_mpq3.hh"
# include "BLI_set.hh"
# include "BLI_span.hh"
# include "BLI_stack.hh"
@@ -1633,13 +1632,13 @@ static Edge find_good_sorting_edge(const Vert *testp,
ordinate[axis_next] = -abscissa[axis];
ordinate[axis_next_next] = 0;
/* By construction, dot(abscissa, ordinate) == 0, so they are perpendicular. */
- mpq3 normal = mpq3::cross(abscissa, ordinate);
+ mpq3 normal = math::cross(abscissa, ordinate);
if (dbg_level > 0) {
std::cout << "abscissa = " << abscissa << "\n";
std::cout << "ordinate = " << ordinate << "\n";
std::cout << "normal = " << normal << "\n";
}
- mpq_class nlen2 = normal.length_squared();
+ mpq_class nlen2 = math::length_squared(normal);
mpq_class max_abs_slope = -1;
Edge esort;
const Vector<Edge> &edges = tmtopo.vert_edges(closestp);
@@ -1648,12 +1647,12 @@ static Edge find_good_sorting_edge(const Vert *testp,
const mpq3 &co_other = v_other->co_exact;
mpq3 evec = co_other - co_closest;
/* Get projection of evec onto plane of abscissa and ordinate. */
- mpq3 proj_evec = evec - (mpq3::dot(evec, normal) / nlen2) * normal;
+ mpq3 proj_evec = evec - (math::dot(evec, normal) / nlen2) * normal;
/* The projection calculations along the abscissa and ordinate should
* be scaled by 1/abscissa and 1/ordinate respectively,
* but we can skip: it won't affect which `evec` has the maximum slope. */
- mpq_class evec_a = mpq3::dot(proj_evec, abscissa);
- mpq_class evec_o = mpq3::dot(proj_evec, ordinate);
+ mpq_class evec_a = math::dot(proj_evec, abscissa);
+ mpq_class evec_o = math::dot(proj_evec, ordinate);
if (dbg_level > 0) {
std::cout << "e = " << e << "\n";
std::cout << "v_other = " << v_other << "\n";
@@ -1791,8 +1790,8 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
ap = p;
ap -= a;
- mpq_class d1 = mpq3::dot_with_buffer(ab, ap, m);
- mpq_class d2 = mpq3::dot_with_buffer(ac, ap, m);
+ mpq_class d1 = math::dot_with_buffer(ab, ap, m);
+ mpq_class d2 = math::dot_with_buffer(ac, ap, m);
if (d1 <= 0 && d2 <= 0) {
/* Barycentric coordinates (1,0,0). */
*r_edge = -1;
@@ -1800,13 +1799,13 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = a\n";
}
- return mpq3::distance_squared_with_buffer(p, a, m);
+ return math::distance_squared_with_buffer(p, a, m);
}
/* Check if p in vertex region outside b. */
bp = p;
bp -= b;
- mpq_class d3 = mpq3::dot_with_buffer(ab, bp, m);
- mpq_class d4 = mpq3::dot_with_buffer(ac, bp, m);
+ mpq_class d3 = math::dot_with_buffer(ab, bp, m);
+ mpq_class d4 = math::dot_with_buffer(ac, bp, m);
if (d3 >= 0 && d4 <= d3) {
/* Barycentric coordinates (0,1,0). */
*r_edge = -1;
@@ -1814,7 +1813,7 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = b\n";
}
- return mpq3::distance_squared_with_buffer(p, b, m);
+ return math::distance_squared_with_buffer(p, b, m);
}
/* Check if p in region of ab. */
mpq_class vc = d1 * d4 - d3 * d2;
@@ -1829,13 +1828,13 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = on ab at " << r << "\n";
}
- return mpq3::distance_squared_with_buffer(p, r, m);
+ return math::distance_squared_with_buffer(p, r, m);
}
/* Check if p in vertex region outside c. */
cp = p;
cp -= c;
- mpq_class d5 = mpq3::dot_with_buffer(ab, cp, m);
- mpq_class d6 = mpq3::dot_with_buffer(ac, cp, m);
+ mpq_class d5 = math::dot_with_buffer(ab, cp, m);
+ mpq_class d6 = math::dot_with_buffer(ac, cp, m);
if (d6 >= 0 && d5 <= d6) {
/* Barycentric coordinates (0,0,1). */
*r_edge = -1;
@@ -1843,7 +1842,7 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = c\n";
}
- return mpq3::distance_squared_with_buffer(p, c, m);
+ return math::distance_squared_with_buffer(p, c, m);
}
/* Check if p in edge region of ac. */
mpq_class vb = d5 * d2 - d1 * d6;
@@ -1858,7 +1857,7 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = on ac at " << r << "\n";
}
- return mpq3::distance_squared_with_buffer(p, r, m);
+ return math::distance_squared_with_buffer(p, r, m);
}
/* Check if p in edge region of bc. */
mpq_class va = d3 * d6 - d5 * d4;
@@ -1874,7 +1873,7 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = on bc at " << r << "\n";
}
- return mpq3::distance_squared_with_buffer(p, r, m);
+ return math::distance_squared_with_buffer(p, r, m);
}
/* p inside face region. Compute barycentric coordinates (u,v,w). */
mpq_class denom = 1 / (va + vb + vc);
@@ -1890,7 +1889,7 @@ static mpq_class closest_on_tri_to_point(const mpq3 &p,
if (dbg_level > 0) {
std::cout << " answer = inside at " << r << "\n";
}
- return mpq3::distance_squared_with_buffer(p, r, m);
+ return math::distance_squared_with_buffer(p, r, m);
}
static float closest_on_tri_to_point_float_dist_squared(const float3 &p,
@@ -2610,7 +2609,7 @@ static void test_tri_inside_shapes(const IMesh &tm,
double3 test_point = calc_point_inside_tri_db(tri_test);
/* Offset the test point a tiny bit in the tri_test normal direction. */
tri_test.populate_plane(false);
- double3 norm = tri_test.plane->norm.normalized();
+ double3 norm = math::normalize(tri_test.plane->norm);
const double offset_amount = 1e-5;
double3 offset_test_point = test_point + offset_amount * norm;
if (dbg_level > 0) {
@@ -3002,7 +3001,7 @@ static void init_face_merge_state(FaceMergeState *fms,
std::cout << "process tri = " << &tri << "\n";
}
BLI_assert(tri.plane_populated());
- if (double3::dot(norm, tri.plane->norm) <= 0.0) {
+ if (math::dot(norm, tri.plane->norm) <= 0.0) {
if (dbg_level > 0) {
std::cout << "triangle has wrong orientation, skipping\n";
}
@@ -3027,7 +3026,7 @@ static void init_face_merge_state(FaceMergeState *fms,
}
if (me_index == -1) {
double3 vec = new_me.v2->co - new_me.v1->co;
- new_me.len_squared = vec.length_squared();
+ new_me.len_squared = math::length_squared(vec);
new_me.orig = tri.edge_orig[i];
new_me.is_intersect = tri.is_intersect[i];
new_me.dissolvable = (new_me.orig == NO_INDEX && !new_me.is_intersect);
@@ -3267,7 +3266,7 @@ static Vector<Face *> merge_tris_for_face(Vector<int> tris,
bool done = false;
double3 first_tri_normal = tm.face(tris[0])->plane->norm;
double3 second_tri_normal = tm.face(tris[1])->plane->norm;
- if (tris.size() == 2 && double3::dot(first_tri_normal, second_tri_normal) > 0.0) {
+ if (tris.size() == 2 && math::dot(first_tri_normal, second_tri_normal) > 0.0) {
/* Is this a case where quad with one diagonal remained unchanged?
* Worth special handling because this case will be very common. */
Face &tri1 = *tm.face(tris[0]);
@@ -3332,7 +3331,7 @@ static bool approx_in_line(const double3 &a, const double3 &b, const double3 &c)
{
double3 vec1 = b - a;
double3 vec2 = c - b;
- double cos_ang = double3::dot(vec1.normalized(), vec2.normalized());
+ double cos_ang = math::dot(math::normalize(vec1), math::normalize(vec2));
return fabs(cos_ang - 1.0) < 1e-4;
}
diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc
index ab1db3f1fda..982759ffcff 100644
--- a/source/blender/blenlib/intern/mesh_intersect.cc
+++ b/source/blender/blenlib/intern/mesh_intersect.cc
@@ -30,15 +30,13 @@
# include "BLI_array.hh"
# include "BLI_assert.h"
# include "BLI_delaunay_2d.h"
-# include "BLI_double3.hh"
-# include "BLI_float3.hh"
# include "BLI_hash.hh"
# include "BLI_kdopbvh.h"
# include "BLI_map.hh"
# include "BLI_math_boolean.hh"
# include "BLI_math_mpq.hh"
-# include "BLI_mpq2.hh"
-# include "BLI_mpq3.hh"
+# include "BLI_math_vec_mpq_types.hh"
+# include "BLI_math_vec_types.hh"
# include "BLI_polyfill_2d.h"
# include "BLI_set.hh"
# include "BLI_span.hh"
@@ -61,11 +59,11 @@
namespace blender::meshintersect {
# ifdef PERFDEBUG
-static void perfdata_init(void);
+static void perfdata_init();
static void incperfcount(int countnum);
static void bumpperfcount(int countnum, int amt);
static void doperfmax(int maxnum, int val);
-static void dump_perfdata(void);
+static void dump_perfdata();
# endif
/** For debugging, can disable threading in intersect code with this static constant. */
@@ -198,14 +196,14 @@ void Face::populate_plane(bool need_exact)
for (int i : index_range()) {
co[i] = vert[i]->co_exact;
}
- normal_exact = mpq3::cross_poly(co);
+ normal_exact = math::cross_poly(co.as_span());
}
else {
mpq3 tr02 = vert[0]->co_exact - vert[2]->co_exact;
mpq3 tr12 = vert[1]->co_exact - vert[2]->co_exact;
- normal_exact = mpq3::cross(tr02, tr12);
+ normal_exact = math::cross(tr02, tr12);
}
- mpq_class d_exact = -mpq3::dot(normal_exact, vert[0]->co_exact);
+ mpq_class d_exact = -math::dot(normal_exact, vert[0]->co_exact);
plane = new Plane(normal_exact, d_exact);
}
else {
@@ -215,14 +213,14 @@ void Face::populate_plane(bool need_exact)
for (int i : index_range()) {
co[i] = vert[i]->co;
}
- normal = double3::cross_poly(co);
+ normal = math::cross_poly(co.as_span());
}
else {
double3 tr02 = vert[0]->co - vert[2]->co;
double3 tr12 = vert[1]->co - vert[2]->co;
- normal = double3::cross_high_precision(tr02, tr12);
+ normal = math::cross(tr02, tr12);
}
- double d = -double3::dot(normal, vert[0]->co);
+ double d = -math::dot(normal, vert[0]->co);
plane = new Plane(normal, d);
}
}
@@ -1098,15 +1096,15 @@ static mpq2 project_3d_to_2d(const mpq3 &p3d, int proj_axis)
*/
static double supremum_dot_cross(const double3 &a, const double3 &b)
{
- double3 abs_a = double3::abs(a);
- double3 abs_b = double3::abs(b);
+ double3 abs_a = math::abs(a);
+ double3 abs_b = math::abs(b);
double3 c;
/* This is dot(cross(a, b), cross(a,b)) but using absolute values for a and b
* and always using + when operation is + or -. */
c[0] = abs_a[1] * abs_b[2] + abs_a[2] * abs_b[1];
c[1] = abs_a[2] * abs_b[0] + abs_a[0] * abs_b[2];
c[2] = abs_a[0] * abs_b[1] + abs_a[1] * abs_b[0];
- return double3::dot(c, c);
+ return math::dot(c, c);
}
/* The index of dot when inputs are plane_coords with index 1 is much higher.
@@ -1143,11 +1141,11 @@ static int filter_plane_side(const double3 &p,
const double3 &abs_plane_p,
const double3 &abs_plane_no)
{
- double d = double3::dot(p - plane_p, plane_no);
+ double d = math::dot(p - plane_p, plane_no);
if (d == 0.0) {
return 0;
}
- double supremum = double3::dot(abs_p + abs_plane_p, abs_plane_no);
+ double supremum = math::dot(abs_p + abs_plane_p, abs_plane_no);
double err_bound = supremum * index_plane_side * DBL_EPSILON;
if (fabs(d) > err_bound) {
return d > 0 ? 1 : -1;
@@ -1178,9 +1176,9 @@ static inline mpq3 tti_interp(
ab -= b;
ac = a;
ac -= c;
- mpq_class den = mpq3::dot_with_buffer(ab, n, dotbuf);
+ mpq_class den = math::dot_with_buffer(ab, n, dotbuf);
BLI_assert(den != 0);
- mpq_class alpha = mpq3::dot_with_buffer(ac, n, dotbuf) / den;
+ mpq_class alpha = math::dot_with_buffer(ac, n, dotbuf) / den;
return a - alpha * ab;
}
@@ -1209,7 +1207,7 @@ static inline int tti_above(const mpq3 &a,
n.y = ba.z * ca.x - ba.x * ca.z;
n.z = ba.x * ca.y - ba.y * ca.x;
- return sgn(mpq3::dot_with_buffer(ad, n, dotbuf));
+ return sgn(math::dot_with_buffer(ad, n, dotbuf));
}
/**
@@ -1428,11 +1426,11 @@ static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
const double3 &d_r2 = vr2->co;
const double3 &d_n2 = tri2.plane->norm;
- const double3 &abs_d_p1 = double3::abs(d_p1);
- const double3 &abs_d_q1 = double3::abs(d_q1);
- const double3 &abs_d_r1 = double3::abs(d_r1);
- const double3 &abs_d_r2 = double3::abs(d_r2);
- const double3 &abs_d_n2 = double3::abs(d_n2);
+ const double3 &abs_d_p1 = math::abs(d_p1);
+ const double3 &abs_d_q1 = math::abs(d_q1);
+ const double3 &abs_d_r1 = math::abs(d_r1);
+ const double3 &abs_d_r2 = math::abs(d_r2);
+ const double3 &abs_d_n2 = math::abs(d_n2);
int sp1 = filter_plane_side(d_p1, d_r2, d_n2, abs_d_p1, abs_d_r2, abs_d_n2);
int sq1 = filter_plane_side(d_q1, d_r2, d_n2, abs_d_q1, abs_d_r2, abs_d_n2);
@@ -1448,9 +1446,9 @@ static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
}
const double3 &d_n1 = tri1.plane->norm;
- const double3 &abs_d_p2 = double3::abs(d_p2);
- const double3 &abs_d_q2 = double3::abs(d_q2);
- const double3 &abs_d_n1 = double3::abs(d_n1);
+ const double3 &abs_d_p2 = math::abs(d_p2);
+ const double3 &abs_d_q2 = math::abs(d_q2);
+ const double3 &abs_d_n1 = math::abs(d_n1);
int sp2 = filter_plane_side(d_p2, d_r1, d_n1, abs_d_p2, abs_d_r1, abs_d_n1);
int sq2 = filter_plane_side(d_q2, d_r1, d_n1, abs_d_q2, abs_d_r1, abs_d_n1);
@@ -1477,17 +1475,17 @@ static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
if (sp1 == 0) {
buf[0] = p1;
buf[0] -= r2;
- sp1 = sgn(mpq3::dot_with_buffer(buf[0], n2, buf[1]));
+ sp1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
}
if (sq1 == 0) {
buf[0] = q1;
buf[0] -= r2;
- sq1 = sgn(mpq3::dot_with_buffer(buf[0], n2, buf[1]));
+ sq1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
}
if (sr1 == 0) {
buf[0] = r1;
buf[0] -= r2;
- sr1 = sgn(mpq3::dot_with_buffer(buf[0], n2, buf[1]));
+ sr1 = sgn(math::dot_with_buffer(buf[0], n2, buf[1]));
}
if (dbg_level > 1) {
@@ -1509,17 +1507,17 @@ static ITT_value intersect_tri_tri(const IMesh &tm, int t1, int t2)
if (sp2 == 0) {
buf[0] = p2;
buf[0] -= r1;
- sp2 = sgn(mpq3::dot_with_buffer(buf[0], n1, buf[1]));
+ sp2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
}
if (sq2 == 0) {
buf[0] = q2;
buf[0] -= r1;
- sq2 = sgn(mpq3::dot_with_buffer(buf[0], n1, buf[1]));
+ sq2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
}
if (sr2 == 0) {
buf[0] = r2;
buf[0] -= r1;
- sr2 = sgn(mpq3::dot_with_buffer(buf[0], n1, buf[1]));
+ sr2 = sgn(math::dot_with_buffer(buf[0], n1, buf[1]));
}
if (dbg_level > 1) {
@@ -1721,7 +1719,7 @@ static CDT_data prepare_cdt_input(const IMesh &tm, int t, const Vector<ITT_value
BLI_assert(tm.face(t)->plane_populated());
ans.t_plane = tm.face(t)->plane;
BLI_assert(ans.t_plane->exact_populated());
- ans.proj_axis = mpq3::dominant_axis(ans.t_plane->norm_exact);
+ ans.proj_axis = math::dominant_axis(ans.t_plane->norm_exact);
prepare_need_tri(ans, tm, t);
for (const ITT_value &itt : itts) {
switch (itt.kind) {
@@ -1757,7 +1755,7 @@ static CDT_data prepare_cdt_input_for_cluster(const IMesh &tm,
BLI_assert(tm.face(t0)->plane_populated());
ans.t_plane = tm.face(t0)->plane;
BLI_assert(ans.t_plane->exact_populated());
- ans.proj_axis = mpq3::dominant_axis(ans.t_plane->norm_exact);
+ ans.proj_axis = math::dominant_axis(ans.t_plane->norm_exact);
for (const int t : cl) {
prepare_need_tri(ans, tm, t);
}
@@ -2004,9 +2002,9 @@ static bool is_quad_flip_first_third(const double3 &v1,
const double3 &normal)
{
double3 dir_v3v1 = v3 - v1;
- double3 tangent = double3::cross_high_precision(dir_v3v1, normal);
- double dot = double3::dot(v1, tangent);
- return (double3::dot(v4, tangent) >= dot) || (double3::dot(v2, tangent) <= dot);
+ double3 tangent = math::cross(dir_v3v1, normal);
+ double dot = math::dot(v1, tangent);
+ return (math::dot(v4, tangent) >= dot) || (math::dot(v2, tangent) <= dot);
}
/**
@@ -2124,7 +2122,7 @@ static Array<Face *> exact_triangulate_poly(Face *f, IMeshArena *arena)
f->populate_plane(false);
}
const double3 &poly_normal = f->plane->norm;
- int axis = double3::dominant_axis(poly_normal);
+ int axis = math::dominant_axis(poly_normal);
/* If project down y axis as opposed to x or z, the orientation
* of the polygon will be reversed.
* Yet another reversal happens if the poly normal in the dominant
@@ -2203,15 +2201,15 @@ static bool face_is_degenerate(const Face *f)
}
double3 da = v2->co - v0->co;
double3 db = v2->co - v1->co;
- double3 dab = double3::cross_high_precision(da, db);
- double dab_length_squared = dab.length_squared();
+ double3 dab = math::cross(da, db);
+ double dab_length_squared = math::length_squared(dab);
double err_bound = supremum_dot_cross(dab, dab) * index_dot_cross * DBL_EPSILON;
if (dab_length_squared > err_bound) {
return false;
}
mpq3 a = v2->co_exact - v0->co_exact;
mpq3 b = v2->co_exact - v1->co_exact;
- mpq3 ab = mpq3::cross(a, b);
+ mpq3 ab = math::cross(a, b);
if (ab.x == 0 && ab.y == 0 && ab.z == 0) {
return true;
}
@@ -2231,8 +2229,8 @@ static bool any_degenerate_tris_fast(const Array<Face *> triangulation)
}
double3 da = v2->co - v0->co;
double3 db = v2->co - v1->co;
- double da_length_squared = da.length_squared();
- double db_length_squared = db.length_squared();
+ double da_length_squared = math::length_squared(da);
+ double db_length_squared = math::length_squared(db);
if (da_length_squared == 0.0 || db_length_squared == 0.0) {
return true;
}
@@ -2240,8 +2238,8 @@ static bool any_degenerate_tris_fast(const Array<Face *> triangulation)
* The triangle is almost degenerate if sin t is almost 0.
* sin^2 t = |da x db|^2 / (|da|^2 |db|^2)
*/
- double3 dab = double3::cross_high_precision(da, db);
- double dab_length_squared = dab.length_squared();
+ double3 dab = math::cross(da, db);
+ double dab_length_squared = math::length_squared(dab);
double sin_squared_t = dab_length_squared / (da_length_squared * db_length_squared);
if (sin_squared_t < 1e-8) {
return true;
diff --git a/source/blender/blenlib/intern/noise.cc b/source/blender/blenlib/intern/noise.cc
index a6ad18801fd..21816fcd595 100644
--- a/source/blender/blenlib/intern/noise.cc
+++ b/source/blender/blenlib/intern/noise.cc
@@ -50,10 +50,8 @@
#include <cmath>
#include <cstdint>
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
-#include "BLI_float4.hh"
#include "BLI_math_base_safe.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_noise.hh"
#include "BLI_utildefines.h"
@@ -1469,7 +1467,7 @@ void voronoi_smooth_f1(const float w,
correctionFactor /= 1.0f + 3.0f * smoothness;
if (r_color != nullptr) {
const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
- smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ smoothColor = math::interpolate(smoothColor, cellColor, h) - correctionFactor;
}
if (r_w != nullptr) {
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
@@ -1592,7 +1590,7 @@ static float voronoi_distance(const float2 a,
{
switch (metric) {
case NOISE_SHD_VORONOI_EUCLIDEAN:
- return float2::distance(a, b);
+ return math::distance(a, b);
case NOISE_SHD_VORONOI_MANHATTAN:
return fabsf(a.x - b.x) + fabsf(a.y - b.y);
case NOISE_SHD_VORONOI_CHEBYCHEV:
@@ -1615,7 +1613,7 @@ void voronoi_f1(const float2 coord,
float3 *r_color,
float2 *r_position)
{
- const float2 cellPosition = float2::floor(coord);
+ const float2 cellPosition = math::floor(coord);
const float2 localPosition = coord - cellPosition;
float minDistance = 8.0f;
@@ -1654,7 +1652,7 @@ void voronoi_smooth_f1(const float2 coord,
float3 *r_color,
float2 *r_position)
{
- const float2 cellPosition = float2::floor(coord);
+ const float2 cellPosition = math::floor(coord);
const float2 localPosition = coord - cellPosition;
const float smoothness_clamped = max_ff(smoothness, FLT_MIN);
@@ -1676,11 +1674,10 @@ void voronoi_smooth_f1(const float2 coord,
correctionFactor /= 1.0f + 3.0f * smoothness;
if (r_color != nullptr) {
const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
- smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ smoothColor = math::interpolate(smoothColor, cellColor, h) - correctionFactor;
}
if (r_position != nullptr) {
- smoothPosition = float2::interpolate(smoothPosition, pointPosition, h) -
- correctionFactor;
+ smoothPosition = math::interpolate(smoothPosition, pointPosition, h) - correctionFactor;
}
}
}
@@ -1704,7 +1701,7 @@ void voronoi_f2(const float2 coord,
float3 *r_color,
float2 *r_position)
{
- const float2 cellPosition = float2::floor(coord);
+ const float2 cellPosition = math::floor(coord);
const float2 localPosition = coord - cellPosition;
float distanceF1 = 8.0f;
@@ -1748,7 +1745,7 @@ void voronoi_f2(const float2 coord,
void voronoi_distance_to_edge(const float2 coord, const float randomness, float *r_distance)
{
- const float2 cellPosition = float2::floor(coord);
+ const float2 cellPosition = math::floor(coord);
const float2 localPosition = coord - cellPosition;
float2 vectorToClosest = float2(0.0f, 0.0f);
@@ -1777,7 +1774,7 @@ void voronoi_distance_to_edge(const float2 coord, const float randomness, float
const float2 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot_v2v2(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
const float distanceToEdge = dot_v2v2((vectorToClosest + vectorToPoint) / 2.0f,
- perpendicularToEdge.normalized());
+ math::normalize(perpendicularToEdge));
minDistance = std::min(minDistance, distanceToEdge);
}
}
@@ -1787,7 +1784,7 @@ void voronoi_distance_to_edge(const float2 coord, const float randomness, float
void voronoi_n_sphere_radius(const float2 coord, const float randomness, float *r_radius)
{
- const float2 cellPosition = float2::floor(coord);
+ const float2 cellPosition = math::floor(coord);
const float2 localPosition = coord - cellPosition;
float2 closestPoint = float2(0.0f, 0.0f);
@@ -1798,7 +1795,7 @@ void voronoi_n_sphere_radius(const float2 coord, const float randomness, float *
const float2 cellOffset = float2(i, j);
const float2 pointPosition = cellOffset +
hash_float_to_float2(cellPosition + cellOffset) * randomness;
- const float distanceToPoint = float2::distance(pointPosition, localPosition);
+ const float distanceToPoint = math::distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
@@ -1817,14 +1814,14 @@ void voronoi_n_sphere_radius(const float2 coord, const float randomness, float *
const float2 cellOffset = float2(i, j) + closestPointOffset;
const float2 pointPosition = cellOffset +
hash_float_to_float2(cellPosition + cellOffset) * randomness;
- const float distanceToPoint = float2::distance(closestPoint, pointPosition);
+ const float distanceToPoint = math::distance(closestPoint, pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
}
- *r_radius = float2::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+ *r_radius = math::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
}
/* **** 3D Voronoi **** */
@@ -1836,7 +1833,7 @@ static float voronoi_distance(const float3 a,
{
switch (metric) {
case NOISE_SHD_VORONOI_EUCLIDEAN:
- return float3::distance(a, b);
+ return math::distance(a, b);
case NOISE_SHD_VORONOI_MANHATTAN:
return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z);
case NOISE_SHD_VORONOI_CHEBYCHEV:
@@ -1860,7 +1857,7 @@ void voronoi_f1(const float3 coord,
float3 *r_color,
float3 *r_position)
{
- const float3 cellPosition = float3::floor(coord);
+ const float3 cellPosition = math::floor(coord);
const float3 localPosition = coord - cellPosition;
float minDistance = 8.0f;
@@ -1902,7 +1899,7 @@ void voronoi_smooth_f1(const float3 coord,
float3 *r_color,
float3 *r_position)
{
- const float3 cellPosition = float3::floor(coord);
+ const float3 cellPosition = math::floor(coord);
const float3 localPosition = coord - cellPosition;
const float smoothness_clamped = max_ff(smoothness, FLT_MIN);
@@ -1925,10 +1922,10 @@ void voronoi_smooth_f1(const float3 coord,
correctionFactor /= 1.0f + 3.0f * smoothness;
if (r_color != nullptr) {
const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
- smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ smoothColor = math::interpolate(smoothColor, cellColor, h) - correctionFactor;
}
if (r_position != nullptr) {
- smoothPosition = float3::interpolate(smoothPosition, pointPosition, h) -
+ smoothPosition = math::interpolate(smoothPosition, pointPosition, h) -
correctionFactor;
}
}
@@ -1954,7 +1951,7 @@ void voronoi_f2(const float3 coord,
float3 *r_color,
float3 *r_position)
{
- const float3 cellPosition = float3::floor(coord);
+ const float3 cellPosition = math::floor(coord);
const float3 localPosition = coord - cellPosition;
float distanceF1 = 8.0f;
@@ -2000,7 +1997,7 @@ void voronoi_f2(const float3 coord,
void voronoi_distance_to_edge(const float3 coord, const float randomness, float *r_distance)
{
- const float3 cellPosition = float3::floor(coord);
+ const float3 cellPosition = math::floor(coord);
const float3 localPosition = coord - cellPosition;
float3 vectorToClosest = float3(0.0f, 0.0f, 0.0f);
@@ -2032,7 +2029,7 @@ void voronoi_distance_to_edge(const float3 coord, const float randomness, float
const float3 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot_v3v3(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
const float distanceToEdge = dot_v3v3((vectorToClosest + vectorToPoint) / 2.0f,
- perpendicularToEdge.normalized());
+ math::normalize(perpendicularToEdge));
minDistance = std::min(minDistance, distanceToEdge);
}
}
@@ -2043,7 +2040,7 @@ void voronoi_distance_to_edge(const float3 coord, const float randomness, float
void voronoi_n_sphere_radius(const float3 coord, const float randomness, float *r_radius)
{
- const float3 cellPosition = float3::floor(coord);
+ const float3 cellPosition = math::floor(coord);
const float3 localPosition = coord - cellPosition;
float3 closestPoint = float3(0.0f, 0.0f, 0.0f);
@@ -2055,7 +2052,7 @@ void voronoi_n_sphere_radius(const float3 coord, const float randomness, float *
const float3 cellOffset = float3(i, j, k);
const float3 pointPosition = cellOffset +
hash_float_to_float3(cellPosition + cellOffset) * randomness;
- const float distanceToPoint = float3::distance(pointPosition, localPosition);
+ const float distanceToPoint = math::distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
@@ -2076,7 +2073,7 @@ void voronoi_n_sphere_radius(const float3 coord, const float randomness, float *
const float3 cellOffset = float3(i, j, k) + closestPointOffset;
const float3 pointPosition = cellOffset +
hash_float_to_float3(cellPosition + cellOffset) * randomness;
- const float distanceToPoint = float3::distance(closestPoint, pointPosition);
+ const float distanceToPoint = math::distance(closestPoint, pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
@@ -2084,7 +2081,7 @@ void voronoi_n_sphere_radius(const float3 coord, const float randomness, float *
}
}
}
- *r_radius = float3::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+ *r_radius = math::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
}
/* **** 4D Voronoi **** */
@@ -2096,7 +2093,7 @@ static float voronoi_distance(const float4 a,
{
switch (metric) {
case NOISE_SHD_VORONOI_EUCLIDEAN:
- return float4::distance(a, b);
+ return math::distance(a, b);
case NOISE_SHD_VORONOI_MANHATTAN:
return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z) + fabsf(a.w - b.w);
case NOISE_SHD_VORONOI_CHEBYCHEV:
@@ -2121,7 +2118,7 @@ void voronoi_f1(const float4 coord,
float3 *r_color,
float4 *r_position)
{
- const float4 cellPosition = float4::floor(coord);
+ const float4 cellPosition = math::floor(coord);
const float4 localPosition = coord - cellPosition;
float minDistance = 8.0f;
@@ -2166,7 +2163,7 @@ void voronoi_smooth_f1(const float4 coord,
float3 *r_color,
float4 *r_position)
{
- const float4 cellPosition = float4::floor(coord);
+ const float4 cellPosition = math::floor(coord);
const float4 localPosition = coord - cellPosition;
const float smoothness_clamped = max_ff(smoothness, FLT_MIN);
@@ -2191,10 +2188,10 @@ void voronoi_smooth_f1(const float4 coord,
correctionFactor /= 1.0f + 3.0f * smoothness;
if (r_color != nullptr) {
const float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
- smoothColor = float3::interpolate(smoothColor, cellColor, h) - correctionFactor;
+ smoothColor = math::interpolate(smoothColor, cellColor, h) - correctionFactor;
}
if (r_position != nullptr) {
- smoothPosition = float4::interpolate(smoothPosition, pointPosition, h) -
+ smoothPosition = math::interpolate(smoothPosition, pointPosition, h) -
correctionFactor;
}
}
@@ -2221,7 +2218,7 @@ void voronoi_f2(const float4 coord,
float3 *r_color,
float4 *r_position)
{
- const float4 cellPosition = float4::floor(coord);
+ const float4 cellPosition = math::floor(coord);
const float4 localPosition = coord - cellPosition;
float distanceF1 = 8.0f;
@@ -2270,7 +2267,7 @@ void voronoi_f2(const float4 coord,
void voronoi_distance_to_edge(const float4 coord, const float randomness, float *r_distance)
{
- const float4 cellPosition = float4::floor(coord);
+ const float4 cellPosition = math::floor(coord);
const float4 localPosition = coord - cellPosition;
float4 vectorToClosest = float4(0.0f, 0.0f, 0.0f, 0.0f);
@@ -2307,7 +2304,7 @@ void voronoi_distance_to_edge(const float4 coord, const float randomness, float
const float4 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot_v4v4(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
const float distanceToEdge = dot_v4v4((vectorToClosest + vectorToPoint) / 2.0f,
- float4::normalize(perpendicularToEdge));
+ math::normalize(perpendicularToEdge));
minDistance = std::min(minDistance, distanceToEdge);
}
}
@@ -2319,7 +2316,7 @@ void voronoi_distance_to_edge(const float4 coord, const float randomness, float
void voronoi_n_sphere_radius(const float4 coord, const float randomness, float *r_radius)
{
- const float4 cellPosition = float4::floor(coord);
+ const float4 cellPosition = math::floor(coord);
const float4 localPosition = coord - cellPosition;
float4 closestPoint = float4(0.0f, 0.0f, 0.0f, 0.0f);
@@ -2333,7 +2330,7 @@ void voronoi_n_sphere_radius(const float4 coord, const float randomness, float *
const float4 pointPosition = cellOffset +
hash_float_to_float4(cellPosition + cellOffset) *
randomness;
- const float distanceToPoint = float4::distance(pointPosition, localPosition);
+ const float distanceToPoint = math::distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
@@ -2357,7 +2354,7 @@ void voronoi_n_sphere_radius(const float4 coord, const float randomness, float *
const float4 pointPosition = cellOffset +
hash_float_to_float4(cellPosition + cellOffset) *
randomness;
- const float distanceToPoint = float4::distance(closestPoint, pointPosition);
+ const float distanceToPoint = math::distance(closestPoint, pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
@@ -2366,7 +2363,7 @@ void voronoi_n_sphere_radius(const float4 coord, const float randomness, float *
}
}
}
- *r_radius = float4::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+ *r_radius = math::distance(closestPointToClosestPoint, closestPoint) / 2.0f;
}
/** \} */
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index c40eed711f5..64bde1193a6 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -144,8 +144,6 @@ void BLI_path_sequence_encode(
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
-/* ******************** string encoding ***************** */
-
void BLI_path_normalize(const char *relabase, char *path)
{
ptrdiff_t a;
@@ -247,12 +245,19 @@ void BLI_path_normalize_dir(const char *relabase, char *dir)
BLI_path_slash_ensure(dir);
}
-bool BLI_filename_make_safe(char *fname)
+bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens)
{
- const char *invalid =
- "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
- "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
- "/\\?*:|\"<>";
+#define INVALID_CHARS \
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
+ "/\\?*:|\""
+#define INVALID_TOKENS "<>"
+
+ const char *invalid = allow_tokens ? INVALID_CHARS : INVALID_CHARS INVALID_TOKENS;
+
+#undef INVALID_CHARS
+#undef INVALID_TOKENS
+
char *fn;
bool changed = false;
@@ -317,6 +322,11 @@ bool BLI_filename_make_safe(char *fname)
return changed;
}
+bool BLI_filename_make_safe(char *fname)
+{
+ return BLI_filename_make_safe_ex(fname, false);
+}
+
bool BLI_path_make_safe(char *path)
{
/* Simply apply BLI_filename_make_safe() over each component of the path.
@@ -947,15 +957,15 @@ bool BLI_path_abs(char *path, const char *basepath)
#endif
- /* push slashes into unix mode - strings entering this part are
+ /* NOTE(@jesterKing): push slashes into unix mode - strings entering this part are
* potentially messed up: having both back- and forward slashes.
* Here we push into one conform direction, and at the end we
* push them into the system specific dir. This ensures uniformity
- * of paths and solving some problems (and prevent potential future
- * ones) -jesterKing.
- * For UNC paths the first characters containing the UNC prefix
+ * of paths and solving some problems (and prevent potential future ones).
+ *
+ * NOTE(@elubie): For UNC paths the first characters containing the UNC prefix
* shouldn't be switched as we need to distinguish them from
- * paths relative to the .blend file -elubie */
+ * paths relative to the `.blend` file. */
BLI_str_replace_char(tmp + BLI_path_unc_prefix_len(tmp), '\\', '/');
/* Paths starting with `//` will get the blend file as their base,
@@ -1002,25 +1012,30 @@ bool BLI_path_abs(char *path, const char *basepath)
return wasrelative;
}
-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))) {
@@ -1031,9 +1046,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
@@ -1721,7 +1737,7 @@ bool BLI_path_contains(const char *container_path, const char *containee_path)
char containee_native[PATH_MAX];
/* Keep space for a trailing slash. If the path is truncated by this, the containee path is
- * longer than PATH_MAX and the result is ill-defined. */
+ * longer than PATH_MAX and the result is ill-defined. */
BLI_strncpy(container_native, container_path, PATH_MAX - 1);
BLI_strncpy(containee_native, containee_path, PATH_MAX);
diff --git a/source/blender/blenlib/intern/polyfill_2d.c b/source/blender/blenlib/intern/polyfill_2d.c
index 2a02abf147a..aec34659884 100644
--- a/source/blender/blenlib/intern/polyfill_2d.c
+++ b/source/blender/blenlib/intern/polyfill_2d.c
@@ -25,7 +25,7 @@
* and that triangles will have non-overlapping indices (even for degenerate geometry).
* - Self-intersections are considered degenerate (resulting triangles will overlap).
* - While multiple polygons aren't supported, holes can still be defined using *key-holes*
- * (where the polygon doubles back on its self with *exactly* matching coordinates).
+ * (where the polygon doubles back on itself with *exactly* matching coordinates).
*
* \note
*
@@ -147,7 +147,7 @@ typedef struct PolyFill {
#endif
} PolyFill;
-/* circular linklist */
+/** Circular double linked-list. */
typedef struct PolyIndex {
struct PolyIndex *next, *prev;
uint index;
diff --git a/source/blender/blenlib/intern/polyfill_2d_beautify.c b/source/blender/blenlib/intern/polyfill_2d_beautify.c
index 684094234cf..aab33cb163b 100644
--- a/source/blender/blenlib/intern/polyfill_2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill_2d_beautify.c
@@ -400,7 +400,7 @@ void BLI_polyfill_beautify(const float (*coords)[2],
BLI_heap_clear(eheap, NULL);
- /* MEM_freeN(eheap_table); */ /* arena */
+ // MEM_freeN(eheap_table); /* arena */
/* get tris from half edge. */
uint tri_index = 0;
diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c
index 26ecc7552dc..9fe82069d2c 100644
--- a/source/blender/blenlib/intern/scanfill.c
+++ b/source/blender/blenlib/intern/scanfill.c
@@ -357,8 +357,10 @@ static ScanFillVertLink *addedgetoscanlist(ScanFillVertLink *scdata,
return NULL;
}
+/**
+ * Return true if `eve` inside the bound-box of `eed`.
+ */
static bool boundinsideEV(ScanFillEdge *eed, ScanFillVert *eve)
-/* is eve inside boundbox eed */
{
float minx, maxx, miny, maxy;
diff --git a/source/blender/blenlib/intern/serialize.cc b/source/blender/blenlib/intern/serialize.cc
index 52aff140e3e..4e7203efe9b 100644
--- a/source/blender/blenlib/intern/serialize.cc
+++ b/source/blender/blenlib/intern/serialize.cc
@@ -44,12 +44,12 @@ const ArrayValue *Value::as_array_value() const
return static_cast<const ArrayValue *>(this);
}
-const ObjectValue *Value::as_object_value() const
+const DictionaryValue *Value::as_dictionary_value() const
{
- if (type_ != eValueType::Object) {
+ if (type_ != eValueType::Dictionary) {
return nullptr;
}
- return static_cast<const ObjectValue *>(this);
+ return static_cast<const DictionaryValue *>(this);
}
static void convert_to_json(nlohmann::ordered_json &j, const Value &value);
@@ -66,13 +66,13 @@ static void convert_to_json(nlohmann::ordered_json &j, const ArrayValue &value)
}
}
-static void convert_to_json(nlohmann::ordered_json &j, const ObjectValue &value)
+static void convert_to_json(nlohmann::ordered_json &j, const DictionaryValue &value)
{
- const ObjectValue::Items &attributes = value.elements();
+ const DictionaryValue::Items &attributes = value.elements();
/* Create a json object to store the attributes. If this isn't done and attributes is empty it
* would return use a null value, in stead of an empty object. */
j = "{}"_json;
- for (const ObjectValue::Item &attribute : attributes) {
+ for (const DictionaryValue::Item &attribute : attributes) {
nlohmann::ordered_json json_item;
convert_to_json(json_item, *attribute.second);
j[attribute.first] = json_item;
@@ -98,8 +98,8 @@ static void convert_to_json(nlohmann::ordered_json &j, const Value &value)
break;
}
- case eValueType::Object: {
- const ObjectValue &object = *value.as_object_value();
+ case eValueType::Dictionary: {
+ const DictionaryValue &object = *value.as_dictionary_value();
convert_to_json(j, object);
break;
}
@@ -133,10 +133,11 @@ static std::unique_ptr<ArrayValue> convert_from_json_to_array(const nlohmann::or
return array;
}
-static std::unique_ptr<ObjectValue> convert_from_json_to_object(const nlohmann::ordered_json &j)
+static std::unique_ptr<DictionaryValue> convert_from_json_to_object(
+ const nlohmann::ordered_json &j)
{
- std::unique_ptr<ObjectValue> object = std::make_unique<ObjectValue>();
- ObjectValue::Items &elements = object->elements();
+ std::unique_ptr<DictionaryValue> object = std::make_unique<DictionaryValue>();
+ DictionaryValue::Items &elements = object->elements();
for (auto element : j.items()) {
std::string key = element.key();
nlohmann::ordered_json element_json = element.value();
diff --git a/source/blender/blenlib/intern/string_cursor_utf8.c b/source/blender/blenlib/intern/string_cursor_utf8.c
index eb49572f06c..5e2a0b85814 100644
--- a/source/blender/blenlib/intern/string_cursor_utf8.c
+++ b/source/blender/blenlib/intern/string_cursor_utf8.c
@@ -199,7 +199,7 @@ void BLI_str_cursor_step_utf8(const char *str,
const int pos_prev = *pos;
if (BLI_str_cursor_step_prev_utf8(str, maxlen, pos)) {
if ((jump != STRCUR_JUMP_ALL) &&
- (delim_type != cursor_delim_type_utf8(str, maxlen, (size_t)*pos))) {
+ (delim_type != cursor_delim_type_utf8(str, maxlen, *pos))) {
/* left only: compensate for index/change in direction */
if ((pos_orig - (*pos)) >= 1) {
*pos = pos_prev;
diff --git a/source/blender/blenlib/intern/task_graph.cc b/source/blender/blenlib/intern/task_graph.cc
index ff7d0ecb4c4..d84857caeea 100644
--- a/source/blender/blenlib/intern/task_graph.cc
+++ b/source/blender/blenlib/intern/task_graph.cc
@@ -109,7 +109,7 @@ struct TaskNode {
#endif
};
-TaskGraph *BLI_task_graph_create(void)
+TaskGraph *BLI_task_graph_create()
{
return new TaskGraph();
}
diff --git a/source/blender/blenlib/intern/task_scheduler.cc b/source/blender/blenlib/intern/task_scheduler.cc
index 69117e9dc7e..5992e092f4d 100644
--- a/source/blender/blenlib/intern/task_scheduler.cc
+++ b/source/blender/blenlib/intern/task_scheduler.cc
@@ -50,8 +50,8 @@ void BLI_task_scheduler_init()
if (num_threads_override > 0) {
/* Override number of threads. This settings is used within the lifetime
* of tbb::global_control, so we allocate it on the heap. */
- task_scheduler_global_control = OBJECT_GUARDED_NEW(
- tbb::global_control, tbb::global_control::max_allowed_parallelism, num_threads_override);
+ task_scheduler_global_control = MEM_new<tbb::global_control>(
+ __func__, tbb::global_control::max_allowed_parallelism, num_threads_override);
task_scheduler_num_threads = num_threads_override;
}
else {
@@ -69,7 +69,7 @@ void BLI_task_scheduler_init()
void BLI_task_scheduler_exit()
{
#ifdef WITH_TBB_GLOBAL_CONTROL
- OBJECT_GUARDED_DELETE(task_scheduler_global_control, tbb::global_control);
+ MEM_delete(task_scheduler_global_control);
#endif
}
diff --git a/source/blender/blenlib/intern/threads.cc b/source/blender/blenlib/intern/threads.cc
index 3589c952409..f131a464650 100644
--- a/source/blender/blenlib/intern/threads.cc
+++ b/source/blender/blenlib/intern/threads.cc
@@ -52,7 +52,6 @@
#endif
#include "atomic_ops.h"
-#include "numaapi.h"
#if defined(__APPLE__) && defined(_OPENMP) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 2) && \
!defined(__clang__)
@@ -125,7 +124,6 @@ static pthread_mutex_t _colormanage_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _fftw_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _view3d_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t mainid;
-static bool is_numa_available = false;
static unsigned int thread_levels = 0; /* threads can be invoked inside threads */
static int num_threads_override = 0;
@@ -143,9 +141,6 @@ struct ThreadSlot {
void BLI_threadapi_init()
{
mainid = pthread_self();
- if (numaAPI_Initialize() == NUMAAPI_SUCCESS) {
- is_numa_available = true;
- }
}
void BLI_threadapi_exit()
@@ -807,110 +802,3 @@ void BLI_thread_queue_wait_finish(ThreadQueue *queue)
pthread_mutex_unlock(&queue->mutex);
}
-
-/* **** Special functions to help performance on crazy NUMA setups. **** */
-
-#if 0 /* UNUSED */
-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. */
- static bool is_initialized = false;
- static bool is_threadripper2 = false;
- if (is_initialized) {
- return is_threadripper2;
- }
- is_initialized = true;
- char *cpu_brand = BLI_cpu_brand_string();
- if (cpu_brand == nullptr) {
- return false;
- }
- if (strstr(cpu_brand, "Threadripper")) {
- /* NOTE: We consider all Thread-rippers having similar topology to
- * the second one. This is because we are trying to utilize NUMA node
- * 0 as much as possible. This node does exist on earlier versions of
- * thread-ripper and setting affinity to it should not have negative
- * effect.
- * This allows us to avoid per-model check, making the code more
- * reliable for the CPUs which are not yet released.
- */
- if (strstr(cpu_brand, "2990WX") || strstr(cpu_brand, "2950X")) {
- is_threadripper2 = true;
- }
- }
- /* NOTE: While all dies of EPYC has memory controller, only two f them
- * has access to a lower-indexed DDR slots. Those dies are same as on
- * Threadripper2 with the memory controller.
- * Now, it is rather likely that reasonable amount of users don't max
- * up their DR slots, making it only two dies connected to a DDR slot
- * with actual memory in it. */
- if (strstr(cpu_brand, "EPYC")) {
- /* NOTE: Similarly to Thread-ripper we do not do model check. */
- is_threadripper2 = true;
- }
- MEM_freeN(cpu_brand);
- return is_threadripper2;
-}
-
-static void threadripper_put_process_on_fast_node(){
- if (!is_numa_available) {
- return;
- }
- /* NOTE: Technically, we can use NUMA nodes 0 and 2 and using both of
- * them in the affinity mask will allow OS to schedule threads more
- * flexible,possibly increasing overall performance when multiple apps
- * are crunching numbers.
- *
- * However, if scene fits into memory adjacent to a single die we don't
- * want OS to re-schedule the process to another die since that will make
- * it further away from memory allocated for .blend file. */
- /* NOTE: Even if NUMA is available in the API but is disabled in BIOS on
- * this workstation we still process here. If NUMA is disabled it will be a
- * single node, so our action is no-visible-changes, but allows to keep
- * things simple and unified. */
- numaAPI_RunProcessOnNode(0);
-}
-
-static void threadripper_put_thread_on_fast_node(){
- if (!is_numa_available) {
- return;
- }
- /* NOTE: This is where things becomes more interesting. On the one hand
- * we can use nodes 0 and 2 and allow operating system to do balancing
- * of processes/threads for the maximum performance when multiple apps
- * are running.
- * On another hand, however, we probably want to use same node as the
- * main thread since that's where the memory of .blend file is likely
- * to be allocated.
- * Since the main thread is currently on node 0, we also put thread on
- * same node. */
- /* See additional note about NUMA disabled in BIOS above. */
- numaAPI_RunThreadOnNode(0);
-}
-#endif /* UNUSED */
-
-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
- * is that all threads created as children from this thread will inherit
- * the NUMA node and so will end up on the same node. This can be fixed
- * case-by-case by assigning the NUMA node for every child thread, however
- * this is difficult for external libraries and OpenMP, and out of our
- * control for plugins like external renderers. */
-#if 0
- if (check_is_threadripper2_alike_topology()) {
- threadripper_put_process_on_fast_node();
- }
-#endif
-}
-
-void BLI_thread_put_thread_on_fast_node()
-{
- /* Disabled for now, see comment above. */
-#if 0
- if (check_is_threadripper2_alike_topology()) {
- threadripper_put_thread_on_fast_node();
- }
-#endif
-}
diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c
index 55131fa639d..14adab8648b 100644
--- a/source/blender/blenlib/intern/timecode.c
+++ b/source/blender/blenlib/intern/timecode.c
@@ -49,7 +49,7 @@ size_t BLI_timecode_string_from_time(char *str,
/* get cframes */
if (time < 0) {
- /* correction for negative cfraues */
+ /* Correction for negative cframes. */
neg[0] = '-';
time = -time;
}
diff --git a/source/blender/blenlib/tests/BLI_any_test.cc b/source/blender/blenlib/tests/BLI_any_test.cc
index 226088cf3c7..dc72affd610 100644
--- a/source/blender/blenlib/tests/BLI_any_test.cc
+++ b/source/blender/blenlib/tests/BLI_any_test.cc
@@ -9,7 +9,7 @@ namespace blender::tests {
TEST(any, DefaultConstructor)
{
- Any a;
+ Any<> a;
EXPECT_FALSE(a.has_value());
}
@@ -24,11 +24,11 @@ TEST(any, AssignInt)
a = 10;
EXPECT_EQ(value, 10);
- Any b = a;
+ Any<> b = a;
EXPECT_TRUE(b.has_value());
EXPECT_EQ(b.get<int>(), 10);
- Any c = std::move(a);
+ Any<> c = std::move(a);
EXPECT_TRUE(c);
EXPECT_EQ(c.get<int>(), 10);
@@ -48,13 +48,15 @@ TEST(any, AssignMap)
map.add(4, 2);
EXPECT_EQ((a.get<Map<int, int>>().lookup(4)), 2);
- Any b = a;
+ Any<> b = a;
EXPECT_TRUE(b);
EXPECT_EQ((b.get<Map<int, int>>().lookup(4)), 2);
- Any c = std::move(a);
- c = c;
- EXPECT_TRUE(b);
+ Any<> c = std::move(a);
+ /* Test valid state after self assignment. Clang emits `-Wself-assign-overloaded` with `c=c;`.
+ * And `pragma` suppression creates warnings on other compilers. */
+ c = static_cast<decltype(a) &>(c);
+ EXPECT_TRUE(c);
EXPECT_EQ((c.get<Map<int, int>>().lookup(4)), 2);
EXPECT_TRUE((a.get<Map<int, int>>().is_empty())); /* NOLINT: bugprone-use-after-move */
@@ -64,9 +66,9 @@ TEST(any, AssignAny)
{
Any<> a = 5;
Any<> b = std::string("hello");
- Any c;
+ Any<> c;
- Any z;
+ Any<> z;
EXPECT_FALSE(z.has_value());
z = a;
diff --git a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
index 70e3a99e57a..eac3faa6d15 100644
--- a/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
+++ b/source/blender/blenlib/tests/BLI_delaunay_2d_test.cc
@@ -21,10 +21,9 @@ extern "C" {
#define DO_RANDOM_TESTS 0
#include "BLI_array.hh"
-#include "BLI_double2.hh"
#include "BLI_math_boolean.hh"
#include "BLI_math_mpq.hh"
-#include "BLI_mpq2.hh"
+#include "BLI_math_vec_mpq_types.hh"
#include "BLI_vector.hh"
#include "BLI_delaunay_2d.h"
diff --git a/source/blender/blenlib/tests/BLI_fileops_test.cc b/source/blender/blenlib/tests/BLI_fileops_test.cc
new file mode 100644
index 00000000000..e2a792647dc
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_fileops_test.cc
@@ -0,0 +1,40 @@
+/* Apache License, Version 2.0 */
+
+#include "BLI_fileops.hh"
+
+#include "testing/testing.h"
+
+namespace blender::tests {
+
+TEST(fileops, fstream_open_string_filename)
+{
+ const std::string test_files_dir = blender::tests::flags_test_asset_dir();
+ if (test_files_dir.empty()) {
+ FAIL();
+ }
+
+ const std::string filepath = test_files_dir + "/asset_library/новый/blender_assets.cats.txt";
+ fstream in(filepath, std::ios_base::in);
+ ASSERT_TRUE(in.is_open()) << "could not open " << filepath;
+ in.close(); /* This should not crash. */
+
+ /* Reading the file not tested here. That's deferred to `std::fstream` anyway. */
+}
+
+TEST(fileops, fstream_open_charptr_filename)
+{
+ const std::string test_files_dir = blender::tests::flags_test_asset_dir();
+ if (test_files_dir.empty()) {
+ FAIL();
+ }
+
+ const std::string filepath_str = test_files_dir + "/asset_library/новый/blender_assets.cats.txt";
+ const char *filepath = filepath_str.c_str();
+ fstream in(filepath, std::ios_base::in);
+ ASSERT_TRUE(in.is_open()) << "could not open " << filepath;
+ in.close(); /* This should not crash. */
+
+ /* Reading the file not tested here. That's deferred to `std::fstream` anyway. */
+}
+
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_listbase_test.cc b/source/blender/blenlib/tests/BLI_listbase_test.cc
index d66eb214902..9e4d7c7dd36 100644
--- a/source/blender/blenlib/tests/BLI_listbase_test.cc
+++ b/source/blender/blenlib/tests/BLI_listbase_test.cc
@@ -154,6 +154,31 @@ TEST(listbase, FindLinkFromStringOrPointer)
BLI_freelistN(&lb);
}
+TEST(listbase, FromLink)
+{
+ ListBase lb = {nullptr, nullptr};
+ Link *link1 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link1"));
+ Link *link2 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link2"));
+ Link *link3 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link3"));
+
+ /* NULL safety. */
+ EXPECT_EQ(lb, BLI_listbase_from_link(nullptr));
+
+ /* One link. */
+ BLI_addtail(&lb, link1);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link1));
+
+ /* Two links. */
+ BLI_addtail(&lb, link2);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link2));
+
+ /* Three links, search from middle. */
+ BLI_addtail(&lb, link3);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link2));
+
+ BLI_freelistN(&lb);
+}
+
/* -------------------------------------------------------------------- */
/* Sort utilities & test */
diff --git a/source/blender/blenlib/tests/BLI_math_vec_types_test.cc b/source/blender/blenlib/tests/BLI_math_vec_types_test.cc
new file mode 100644
index 00000000000..c9be404139e
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_math_vec_types_test.cc
@@ -0,0 +1,149 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_math_vec_types.hh"
+
+namespace blender::tests {
+
+using namespace blender::math;
+
+TEST(math_vec_types, ScalarConstructorUnsigned)
+{
+ float2 u(5u);
+ EXPECT_EQ(u[0], 5.0f);
+ EXPECT_EQ(u[1], 5.0f);
+}
+
+TEST(math_vec_types, ScalarConstructorInt)
+{
+ float2 i(-5);
+ EXPECT_EQ(i[0], -5.0f);
+ EXPECT_EQ(i[1], -5.0f);
+}
+
+TEST(math_vec_types, ScalarConstructorFloat)
+{
+ float2 f(5.2f);
+ EXPECT_FLOAT_EQ(f[0], 5.2f);
+ EXPECT_FLOAT_EQ(f[1], 5.2f);
+}
+
+TEST(math_vec_types, ScalarConstructorDouble)
+{
+ float2 d(5.2);
+ EXPECT_FLOAT_EQ(d[0], 5.2f);
+ EXPECT_FLOAT_EQ(d[1], 5.2f);
+}
+
+TEST(math_vec_types, MultiScalarConstructorVec2)
+{
+ int2 i(5, -1);
+ EXPECT_EQ(i[0], 5);
+ EXPECT_EQ(i[1], -1);
+}
+
+TEST(math_vec_types, MultiScalarConstructorVec3)
+{
+ int3 i(5, -1, 6u);
+ EXPECT_EQ(i[0], 5);
+ EXPECT_EQ(i[1], -1);
+ EXPECT_EQ(i[2], 6);
+}
+
+TEST(math_vec_types, MultiScalarConstructorVec4)
+{
+ int4 i(5, -1, 6u, 0);
+ EXPECT_EQ(i[0], 5);
+ EXPECT_EQ(i[1], -1);
+ EXPECT_EQ(i[2], 6);
+ EXPECT_EQ(i[3], 0);
+}
+
+TEST(math_vec_types, MixedScalarVectorConstructorVec3)
+{
+ float3 fl_v2(float2(5.5f), 1.8f);
+ EXPECT_FLOAT_EQ(fl_v2[0], 5.5f);
+ EXPECT_FLOAT_EQ(fl_v2[1], 5.5f);
+ EXPECT_FLOAT_EQ(fl_v2[2], 1.8f);
+
+ float3 v2_fl(1.8f, float2(5.5f));
+ EXPECT_FLOAT_EQ(v2_fl[0], 1.8f);
+ EXPECT_FLOAT_EQ(v2_fl[1], 5.5f);
+ EXPECT_FLOAT_EQ(v2_fl[2], 5.5f);
+}
+
+TEST(math_vec_types, MixedScalarVectorConstructorVec4)
+{
+ int4 v2_fl_fl(float2(1), 2, 3);
+ EXPECT_EQ(v2_fl_fl[0], 1);
+ EXPECT_EQ(v2_fl_fl[1], 1);
+ EXPECT_EQ(v2_fl_fl[2], 2);
+ EXPECT_EQ(v2_fl_fl[3], 3);
+
+ float4 fl_v2_fl(1, int2(2), 3);
+ EXPECT_EQ(fl_v2_fl[0], 1);
+ EXPECT_EQ(fl_v2_fl[1], 2);
+ EXPECT_EQ(fl_v2_fl[2], 2);
+ EXPECT_EQ(fl_v2_fl[3], 3);
+
+ double4 fl_fl_v2(1, 2, double2(3));
+ EXPECT_EQ(fl_fl_v2[0], 1);
+ EXPECT_EQ(fl_fl_v2[1], 2);
+ EXPECT_EQ(fl_fl_v2[2], 3);
+ EXPECT_EQ(fl_fl_v2[3], 3);
+
+ int4 v2_v2(float2(1), uint2(2));
+ EXPECT_EQ(v2_v2[0], 1);
+ EXPECT_EQ(v2_v2[1], 1);
+ EXPECT_EQ(v2_v2[2], 2);
+ EXPECT_EQ(v2_v2[3], 2);
+
+ float4 v3_fl(uint3(1), 2);
+ EXPECT_EQ(v3_fl[0], 1);
+ EXPECT_EQ(v3_fl[1], 1);
+ EXPECT_EQ(v3_fl[2], 1);
+ EXPECT_EQ(v3_fl[3], 2);
+
+ uint4 fl_v3(1, float3(2));
+ EXPECT_EQ(fl_v3[0], 1);
+ EXPECT_EQ(fl_v3[1], 2);
+ EXPECT_EQ(fl_v3[2], 2);
+ EXPECT_EQ(fl_v3[3], 2);
+}
+
+TEST(math_vec_types, ComponentMasking)
+{
+ int4 i(0, 1, 2, 3);
+ float2 f2 = float2(i);
+ EXPECT_EQ(f2[0], 0.0f);
+ EXPECT_EQ(f2[1], 1.0f);
+}
+
+TEST(math_vec_types, PointerConversion)
+{
+ float array[3] = {1.0f, 2.0f, 3.0f};
+ float3 farray(array);
+ EXPECT_EQ(farray[0], 1.0f);
+ EXPECT_EQ(farray[1], 2.0f);
+ EXPECT_EQ(farray[2], 3.0f);
+}
+
+TEST(math_vec_types, PointerArrayConversion)
+{
+ float array[1][3] = {{1.0f, 2.0f, 3.0f}};
+ float(*ptr)[3] = array;
+ float3 fptr(ptr);
+ EXPECT_EQ(fptr[0], 1.0f);
+ EXPECT_EQ(fptr[1], 2.0f);
+ EXPECT_EQ(fptr[2], 3.0f);
+}
+
+TEST(math_vec_types, VectorTypeConversion)
+{
+ double2 d(int2(float2(5.75f, -1.57f)));
+ EXPECT_EQ(d[0], 5.0);
+ EXPECT_EQ(d[1], -1.0);
+}
+
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_memory_utils_test.cc b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
index 23415e69b04..74e54151a06 100644
--- a/source/blender/blenlib/tests/BLI_memory_utils_test.cc
+++ b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
@@ -1,6 +1,6 @@
/* Apache License, Version 2.0 */
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_memory_utils.hh"
#include "BLI_strict_flags.h"
#include "testing/testing.h"
@@ -169,4 +169,11 @@ static_assert(is_span_convertible_pointer_v<int *, const void *>);
static_assert(!is_span_convertible_pointer_v<TestBaseClass *, TestChildClass *>);
static_assert(!is_span_convertible_pointer_v<TestChildClass *, TestBaseClass *>);
+static_assert(is_same_any_v<int, float, bool, int>);
+static_assert(is_same_any_v<int, int, float>);
+static_assert(is_same_any_v<int, int>);
+static_assert(!is_same_any_v<int, float, bool>);
+static_assert(!is_same_any_v<int, float>);
+static_assert(!is_same_any_v<int>);
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
index d759f0c3be4..2b8fb3dbea4 100644
--- a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
+++ b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
@@ -11,8 +11,8 @@
#include "BLI_array.hh"
#include "BLI_map.hh"
#include "BLI_math_mpq.hh"
+#include "BLI_math_vec_mpq_types.hh"
#include "BLI_mesh_boolean.hh"
-#include "BLI_mpq3.hh"
#include "BLI_vector.hh"
#ifdef WITH_GMP
diff --git a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
index 68111fb8eb1..d2d76593129 100644
--- a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
+++ b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
@@ -10,8 +10,8 @@
#include "BLI_array.hh"
#include "BLI_math_mpq.hh"
+#include "BLI_math_vec_mpq_types.hh"
#include "BLI_mesh_intersect.hh"
-#include "BLI_mpq3.hh"
#include "BLI_task.h"
#include "BLI_vector.hh"
diff --git a/source/blender/blenlib/tests/BLI_serialize_test.cc b/source/blender/blenlib/tests/BLI_serialize_test.cc
index 6c55a85ca1e..120fcdc3e81 100644
--- a/source/blender/blenlib/tests/BLI_serialize_test.cc
+++ b/source/blender/blenlib/tests/BLI_serialize_test.cc
@@ -93,8 +93,8 @@ TEST(serialize, object_to_json)
{
JsonFormatter json;
std::stringstream out;
- ObjectValue value_object;
- ObjectValue::Items &attributes = value_object.elements();
+ DictionaryValue value_object;
+ DictionaryValue::Items &attributes = value_object.elements();
attributes.append_as(std::pair(std::string("best_number"), new IntValue(42)));
json.serialize(out, value_object);
diff --git a/source/blender/blenlib/tests/BLI_task_test.cc b/source/blender/blenlib/tests/BLI_task_test.cc
index dd4441517a9..3bb6f6f753c 100644
--- a/source/blender/blenlib/tests/BLI_task_test.cc
+++ b/source/blender/blenlib/tests/BLI_task_test.cc
@@ -154,7 +154,7 @@ static void task_mempool_iter_tls_func(void *UNUSED(userdata),
EXPECT_TRUE(data != nullptr);
if (task_data->accumulate_items == nullptr) {
- task_data->accumulate_items = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
+ task_data->accumulate_items = MEM_cnew<ListBase>(__func__);
}
/* Flip to prove this has been touched. */
@@ -172,7 +172,7 @@ static void task_mempool_iter_tls_reduce(const void *__restrict UNUSED(userdata)
if (data_chunk->accumulate_items != nullptr) {
if (join_chunk->accumulate_items == nullptr) {
- join_chunk->accumulate_items = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
+ join_chunk->accumulate_items = MEM_cnew<ListBase>(__func__);
}
BLI_movelisttolist(join_chunk->accumulate_items, data_chunk->accumulate_items);
}
diff --git a/source/blender/blenlib/tests/BLI_vector_test.cc b/source/blender/blenlib/tests/BLI_vector_test.cc
index e8636168308..e9393a2b1e5 100644
--- a/source/blender/blenlib/tests/BLI_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_vector_test.cc
@@ -708,6 +708,17 @@ TEST(vector, Prepend)
EXPECT_EQ_ARRAY(vec.data(), Span({7, 8, 1, 2, 3}).data(), 5);
}
+TEST(vector, PrependString)
+{
+ std::string s = "test";
+ Vector<std::string> vec;
+ vec.prepend(s);
+ vec.prepend(std::move(s));
+ EXPECT_EQ(vec.size(), 2);
+ EXPECT_EQ(vec[0], "test");
+ EXPECT_EQ(vec[1], "test");
+}
+
TEST(vector, ReverseIterator)
{
Vector<int> vec = {4, 5, 6, 7};
diff --git a/source/blender/blenlib/tests/performance/CMakeLists.txt b/source/blender/blenlib/tests/performance/CMakeLists.txt
index 5342dbe286c..036955a4b43 100644
--- a/source/blender/blenlib/tests/performance/CMakeLists.txt
+++ b/source/blender/blenlib/tests/performance/CMakeLists.txt
@@ -23,7 +23,6 @@ set(INC
..
)
-setup_libdirs()
include_directories(${INC})
BLENDER_TEST_PERFORMANCE(BLI_ghash_performance "bf_blenlib")
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 567886e4d54..c4c3b42cb63 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -233,7 +233,7 @@ BlendHandle *BLO_blendhandle_from_memory(const void *mem,
struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
int ofblocktype,
- const bool use_assets_only,
+ 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.
@@ -246,8 +246,10 @@ struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh,
* \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);
+struct LinkNode * /*BLODataBlockInfo */ BLO_blendhandle_get_datablock_info(BlendHandle *bh,
+ int ofblocktype,
+ 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).
@@ -367,12 +369,12 @@ typedef struct LibraryLink_Params {
void BLO_library_link_params_init(struct LibraryLink_Params *params,
struct Main *bmain,
- const int flag,
- const int id_tag_extra);
+ int flag,
+ int id_tag_extra);
void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params,
struct Main *bmain,
- const int flag,
- const int id_tag_extra,
+ int flag,
+ int id_tag_extra,
struct Scene *scene,
struct ViewLayer *view_layer,
const struct View3D *v3d);
@@ -400,7 +402,7 @@ struct Main *BLO_library_link_begin(BlendHandle **bh,
*/
struct ID *BLO_library_link_named_part(struct Main *mainl,
BlendHandle **bh,
- const short idcode,
+ short idcode,
const char *name,
const struct LibraryLink_Params *params);
/**
@@ -435,7 +437,7 @@ typedef struct TempLibraryContext {
TempLibraryContext *BLO_library_temp_load_id(struct Main *real_main,
const char *blend_file_path,
- const short idcode,
+ short idcode,
const char *idname,
struct ReportList *reports);
void BLO_library_temp_free(TempLibraryContext *temp_lib_ctx);
diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h
index 9bc3714ff38..072f86b48d6 100644
--- a/source/blender/blenloader/BLO_writefile.h
+++ b/source/blender/blenloader/BLO_writefile.h
@@ -69,7 +69,7 @@ struct BlendFileWriteParams {
*/
extern bool BLO_write_file(struct Main *mainvar,
const char *filepath,
- const int write_flags,
+ int write_flags,
const struct BlendFileWriteParams *params,
struct ReportList *reports);
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 05f74bfa834..245514d4977 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../blentranslation
../depsgraph
../draw
+ ../editors/include
../imbuf
../makesdna
../makesrna
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 56047bb7f4f..38f2d8bb22c 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -254,7 +254,7 @@ typedef struct OldNewMap {
/* Array that stores the actual entries. */
OldNew *entries;
int nentries;
- /* Hashmap that stores indices into the `entries` array. */
+ /* Hash-map that stores indices into the `entries` array. */
int32_t *map;
int capacity_exp;
@@ -2544,7 +2544,6 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
else if (sl->spacetype == SPACE_FILE) {
SpaceFile *sfile = (SpaceFile *)sl;
sfile->op = NULL;
- sfile->previews_timer = NULL;
sfile->tags = FILE_TAG_REBUILD_MAIN_FILES;
}
else if (sl->spacetype == SPACE_ACTION) {
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 3b5be3dd013..21b0354b097 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -200,7 +200,7 @@ struct AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const
*
* \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_dna(struct SDNA *sdna, int versionfile, int subversionfile);
void blo_do_versions_oldnewmap_insert(struct OldNewMap *onm,
const void *oldaddr,
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 54e673b51eb..52737950ea3 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -70,6 +70,7 @@
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
+#include "BKE_node_tree_update.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_screen.h"
@@ -579,7 +580,6 @@ static bNodeSocket *do_versions_node_group_add_socket_2_56_2(bNodeTree *ngroup,
gsock->type = type;
gsock->next = gsock->prev = NULL;
- gsock->new_sock = NULL;
gsock->link = NULL;
/* assign new unique index */
gsock->own_index = ngroup->cur_index++;
@@ -590,7 +590,7 @@ static bNodeSocket *do_versions_node_group_add_socket_2_56_2(bNodeTree *ngroup,
BLI_addtail(in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs, gsock);
- ngroup->update |= (in_out == SOCK_IN ? NTREE_UPDATE_GROUP_IN : NTREE_UPDATE_GROUP_OUT);
+ BKE_ntree_update_tag_interface(ngroup);
return gsock;
}
@@ -856,10 +856,9 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (!ts->uv_selectmode || ts->vgroup_weight == 0.0f) {
ts->selectmode = SCE_SELECT_VERTEX;
- /* autokeying - setting should be taken from the user-prefs
- * but the userprefs version may not have correct flags set
- * (i.e. will result in blank box when enabled)
- */
+ /* The auto-keying setting should be taken from the user-preferences
+ * but the user-preferences version may not have correct flags set
+ * (i.e. will result in blank box when enabled). */
ts->autokey_mode = U.autokey_mode;
if (ts->autokey_mode == 0) {
ts->autokey_mode = 2; /* 'add/replace' but not on */
@@ -1004,7 +1003,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
int a, tot;
/* shape keys are no longer applied to the mesh itself, but rather
- * to the derivedmesh/displist, so here we ensure that the basis
+ * to the evaluated #Mesh / #DispList, so here we ensure that the basis
* shape key is always set in the mesh coordinates. */
for (me = bmain->meshes.first; me; me = me->id.next) {
if ((key = blo_do_versions_newlibadr(fd, lib, me->key)) && key->refkey) {
@@ -2019,7 +2018,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
link->fromsock = gsock;
link->tonode = node;
link->tosock = sock;
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
sock->link = link;
}
@@ -2042,7 +2041,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
link->fromsock = sock;
link->tonode = NULL;
link->tosock = gsock;
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
gsock->link = link;
}
@@ -2282,7 +2281,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
do_versions_socket_default_value_259(sock);
}
- ntree->update |= NTREE_UPDATE;
+ BKE_ntree_update_tag_all(ntree);
}
FOREACH_NODETREE_END;
}
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 8a22fd07c24..c34b8f735e5 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -78,6 +78,7 @@
#include "IMB_imbuf.h" /* for proxy / time-code versioning stuff. */
#include "NOD_common.h"
+#include "NOD_composite.h"
#include "NOD_texture.h"
#include "BLO_readfile.h"
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 4333bdb851c..ceddc451a46 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -88,6 +88,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
@@ -401,6 +402,8 @@ static void do_version_scene_collection_to_collection(Main *bmain, Scene *scene)
do_version_layer_collection_pre(
view_layer, &view_layer->layer_collections, enabled_set, selectable_set);
+ BKE_layer_collection_doversion_2_80(scene, view_layer);
+
BKE_layer_collection_sync(scene, view_layer);
do_version_layer_collection_post(
@@ -896,7 +899,7 @@ static void do_versions_material_convert_legacy_blend_mode(bNodeTree *ntree, cha
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index bc3cd7a09cb..81fc6086951 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -30,6 +30,7 @@
#include "BLI_math_vector.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -44,6 +45,8 @@
#include "DNA_listBase.h"
#include "DNA_material_types.h"
#include "DNA_modifier_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DNA_text_types.h"
#include "DNA_workspace_types.h"
@@ -57,6 +60,7 @@
#include "BKE_fcurve.h"
#include "BKE_fcurve_driver.h"
#include "BKE_idprop.h"
+#include "BKE_image.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_main.h"
@@ -592,7 +596,7 @@ static bNodeTree *add_realize_node_tree(Main *bmain)
nodeSetSelected(node, false);
}
- ntreeUpdateTree(bmain, node_tree);
+ version_socket_update_is_used(node_tree);
return node_tree;
}
@@ -790,6 +794,40 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
*/
{
/* Keep this block, even when empty. */
+
+ { /* Ensure driver variable names are unique within the driver. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == NULL) {
+ continue;
+ }
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
+ ChannelDriver *driver = fcu->driver;
+ /* Ensure the uniqueness front to back. Given a list of identically
+ * named variables, the last one gets to keep its original name. This
+ * matches the evaluation order, and thus shouldn't change the evaluated
+ * value of the driver expression. */
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
+ BLI_uniquename(&driver->variables,
+ dvar,
+ dvar->name,
+ '_',
+ offsetof(DriverVar, name),
+ sizeof(dvar->name));
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ /* Ensure tiled image sources contain a UDIM token. */
+ LISTBASE_FOREACH (Image *, ima, &bmain->images) {
+ if (ima->source == IMA_SRC_TILED) {
+ char *filename = (char *)BLI_path_basename(ima->filepath);
+ BKE_image_ensure_tile_token(filename);
+ }
+ }
}
}
@@ -1136,7 +1174,7 @@ static void legacy_vec_roll_to_mat3_normalized(const float nor[3],
const float z = nor[2];
const float theta = 1.0f + y; /* remapping Y from [-1,+1] to [0,2]. */
- const float theta_alt = x * x + z * z; /* Helper value for matrix calculations.*/
+ const float theta_alt = x * x + z * z; /* Helper value for matrix calculations. */
float rMatrix[3][3], bMatrix[3][3];
BLI_ASSERT_UNIT_V3(nor);
@@ -2035,7 +2073,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
SpaceFile *sfile = (SpaceFile *)sl;
if (sfile->params) {
sfile->params->flag &= ~(FILE_PARAMS_FLAG_UNUSED_1 | FILE_PARAMS_FLAG_UNUSED_2 |
- FILE_PARAMS_FLAG_UNUSED_3 | FILE_PARAMS_FLAG_UNUSED_4);
+ FILE_PARAMS_FLAG_UNUSED_3 | FILE_PATH_TOKENS_ALLOW);
}
/* New default import type: Append with reuse. */
@@ -2414,7 +2452,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
data->data_type = SOCK_FLOAT;
data->operation = node->custom1;
strcpy(node->idname, "FunctionNodeCompare");
- node->update = NODE_UPDATE;
node->storage = data;
}
}
@@ -2432,22 +2469,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- /* Add node storage for map range node. */
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == SH_NODE_MAP_RANGE) {
- if (node->storage == NULL) {
- NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__);
- data->clamp = node->custom1;
- data->data_type = CD_PROP_FLOAT;
- data->interpolation_type = node->custom2;
- node->storage = data;
- }
- }
- }
- }
- FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) {
@@ -2475,5 +2496,65 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Add node storage for map range node. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_MAP_RANGE) {
+ if (node->storage == NULL) {
+ NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__);
+ data->clamp = node->custom1;
+ data->data_type = CD_PROP_FLOAT;
+ data->interpolation_type = node->custom2;
+ node->storage = data;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ /* Update spreadsheet data set region type. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_CHANNELS) {
+ region->regiontype = RGN_TYPE_TOOLS;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Initialize the bone wireframe opacity setting. */
+ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "bone_wire_alpha")) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ v3d->overlay.bone_wire_alpha = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ /* Rename sockets on multiple nodes */
+ LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_output_socket_name(
+ ntree, GEO_NODE_STRING_TO_CURVES, "Curves", "Curve Instances");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_INPUT_MESH_EDGE_ANGLE, "Angle", "Unsigned Angle");
+ version_node_output_socket_name(
+ ntree, GEO_NODE_INPUT_MESH_ISLAND, "Index", "Island Index");
+ version_node_input_socket_name(ntree, GEO_NODE_TRANSFER_ATTRIBUTE, "Target", "Source");
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc
index 3deaaa040d6..575bfd565e6 100644
--- a/source/blender/blenloader/intern/versioning_common.cc
+++ b/source/blender/blenloader/intern/versioning_common.cc
@@ -223,3 +223,19 @@ void version_node_socket_index_animdata(Main *bmain,
FOREACH_NODETREE_END;
}
}
+
+void version_socket_update_is_used(bNodeTree *ntree)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->flag &= ~SOCK_IN_USE;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->flag &= ~SOCK_IN_USE;
+ }
+ }
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ link->fromsock->flag |= SOCK_IN_USE;
+ link->tosock->flag |= SOCK_IN_USE;
+ }
+}
diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h
index 0613484b754..ea850a052ae 100644
--- a/source/blender/blenloader/intern/versioning_common.h
+++ b/source/blender/blenloader/intern/versioning_common.h
@@ -39,21 +39,18 @@ struct ARegion *do_versions_add_region_if_not_found(struct ListBase *regionbase,
*
* \return the ID (if found).
*/
-ID *do_versions_rename_id(Main *bmain,
- const short id_type,
- const char *name_src,
- const char *name_dst);
+ID *do_versions_rename_id(Main *bmain, short id_type, const char *name_src, const char *name_dst);
void version_node_socket_name(struct bNodeTree *ntree,
- const int node_type,
+ int node_type,
const char *old_name,
const char *new_name);
void version_node_input_socket_name(struct bNodeTree *ntree,
- const int node_type,
+ int node_type,
const char *old_name,
const char *new_name);
void version_node_output_socket_name(struct bNodeTree *ntree,
- const int node_type,
+ int node_type,
const char *old_name,
const char *new_name);
@@ -85,7 +82,7 @@ void version_node_socket_index_animdata(
/**
* 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);
+void version_node_id(struct bNodeTree *ntree, int node_type, const char *new_name);
/**
* Convert `SocketName.001` unique name format to `SocketName_001`. Previously both were used.
@@ -100,6 +97,12 @@ struct bNodeSocket *version_node_add_socket_if_not_exist(struct bNodeTree *ntree
const char *identifier,
const char *name);
+/**
+ * The versioning code generally expects `SOCK_IN_USE` to be set correctly. This function updates
+ * the flag on all sockets after changes to the node tree.
+ */
+void version_socket_update_is_used(bNodeTree *ntree);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index afe2e1067ae..1f18405cdf9 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -42,12 +42,15 @@
#include "BKE_main.h"
#include "BKE_node.h"
+#include "NOD_shader.h"
+
#include "MEM_guardedalloc.h"
#include "IMB_colormanagement.h"
#include "BLO_readfile.h"
#include "readfile.h"
+#include "versioning_common.h"
static bool socket_is_used(bNodeSocket *sock)
{
@@ -170,7 +173,7 @@ static void displacement_node_insert(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -243,7 +246,7 @@ static void square_roughness_node_insert(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -318,7 +321,7 @@ static void ambient_occlusion_node_relink(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -466,7 +469,7 @@ static void update_math_node_single_operand_operators(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -528,7 +531,7 @@ static void update_vector_math_node_add_and_subtract_operators(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -566,7 +569,7 @@ static void update_vector_math_node_dot_product_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -631,7 +634,7 @@ static void update_vector_math_node_cross_product_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -683,7 +686,7 @@ static void update_vector_math_node_normalize_operator(bNodeTree *ntree)
}
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -785,7 +788,7 @@ static void update_vector_math_node_average_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -974,7 +977,7 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1149,7 +1152,7 @@ static void update_voronoi_node_crackle(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1191,7 +1194,7 @@ static void update_voronoi_node_coloring(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1234,7 +1237,7 @@ static void update_voronoi_node_square_distance(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1279,7 +1282,7 @@ static void update_noise_and_wave_distortion(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index a5c44ea711b..234951eac9a 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -61,6 +61,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
@@ -583,11 +584,11 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
bNodeSocketValueFloat *roughness_data = roughness_socket->default_value;
roughness_data->value = 0.4f;
node->custom2 = SHD_SUBSURFACE_RANDOM_WALK;
- nodeUpdate(ma->nodetree, node);
+ BKE_ntree_update_tag_node_property(ma->nodetree, node);
}
else if (node->type == SH_NODE_SUBSURFACE_SCATTERING) {
node->custom1 = SHD_SUBSURFACE_RANDOM_WALK;
- nodeUpdate(ma->nodetree, node);
+ BKE_ntree_update_tag_node_property(ma->nodetree, node);
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 2fceb42262e..94720ad0b0a 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -1859,7 +1859,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (bmain->subversionfile < 4) {
for (sce = bmain->scenes.first; sce; sce = sce->id.next) {
sce->r.bake_mode = 1; /* prevent to include render stuff here */
- sce->r.bake_filter = 16;
+ sce->r.bake_margin = 16;
+ sce->r.bake_margin_type = R_BAKE_ADJACENT_FACES;
sce->r.bake_flag = R_BAKE_CLEAR;
}
}
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 3338d2f658c..064d7977c68 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -569,8 +569,8 @@ void blo_do_versions_userdef(UserDef *userdef)
}
if (!USER_VERSION_ATLEAST(257, 0)) {
- /* clear "AUTOKEY_FLAG_ONLYKEYINGSET" flag from userprefs,
- * so that it doesn't linger around from old configs like a ghost */
+ /* Clear #AUTOKEY_FLAG_ONLYKEYINGSET flag from user-preferences,
+ * so that it doesn't linger around from old configurations like a ghost. */
userdef->autokey_flag &= ~AUTOKEY_FLAG_ONLYKEYINGSET;
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 45258a50961..aa3eef4b475 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1318,6 +1318,9 @@ bool BLO_write_file(Main *mainvar,
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;
@@ -1326,6 +1329,7 @@ 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;
@@ -1349,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->filepath, 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->filepath, dir_dst);
- BLI_path_normalize(mainvar->filepath, 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;
@@ -1393,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:
@@ -1401,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:
diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
index a4a5ced070d..7a8afbcb227 100644
--- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc
+++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
@@ -21,14 +21,17 @@
#include "BKE_appdir.h"
#include "BKE_blender.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_mball_tessellate.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_scene.h"
+#include "BKE_vfont.h"
#include "BLI_path_util.h"
#include "BLI_threads.h"
@@ -43,6 +46,8 @@
#include "IMB_imbuf.h"
+#include "ED_datafiles.h"
+
#include "RNA_define.h"
#include "WM_api.h"
@@ -71,6 +76,8 @@ void BlendfileLoadingBaseTest::SetUpTestCase()
DEG_register_node_types();
RNA_init();
BKE_node_system_init();
+ BKE_callback_global_init();
+ BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size);
G.background = true;
G.factory_startup = true;
@@ -109,6 +116,7 @@ void BlendfileLoadingBaseTest::TearDownTestCase()
void BlendfileLoadingBaseTest::TearDown()
{
+ BKE_mball_cubeTable_free();
depsgraph_free();
blendfile_free();
diff --git a/source/blender/blentranslation/msgfmt/CMakeLists.txt b/source/blender/blentranslation/msgfmt/CMakeLists.txt
index 4b8f0878c75..a535d5b8e2d 100644
--- a/source/blender/blentranslation/msgfmt/CMakeLists.txt
+++ b/source/blender/blentranslation/msgfmt/CMakeLists.txt
@@ -30,7 +30,6 @@ set(SRC
msgfmt.c
)
-setup_libdirs()
add_cc_flags_custom_test(msgfmt)
if(WIN32)
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index ec282888ffa..e2ed005cf9e 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -98,8 +98,10 @@ set(SRC
intern/bmesh_marking.h
intern/bmesh_mesh.c
intern/bmesh_mesh.h
- intern/bmesh_mesh_convert.c
+ intern/bmesh_mesh_convert.cc
intern/bmesh_mesh_convert.h
+ intern/bmesh_mesh_debug.c
+ intern/bmesh_mesh_debug.h
intern/bmesh_mesh_duplicate.c
intern/bmesh_mesh_duplicate.h
intern/bmesh_mesh_normals.c
@@ -191,7 +193,7 @@ set(LIB
if(WITH_BULLET)
list(APPEND INC_SYS
${BULLET_INCLUDE_DIRS}
- "../../../intern/rigidbody/"
+ ../../../intern/rigidbody
)
if(NOT WITH_SYSTEM_BULLET)
list(APPEND LIB
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index 40db423ba2f..fc97c55091a 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -214,6 +214,7 @@ extern "C" {
#include "intern/bmesh_marking.h"
#include "intern/bmesh_mesh.h"
#include "intern/bmesh_mesh_convert.h"
+#include "intern/bmesh_mesh_debug.h"
#include "intern/bmesh_mesh_duplicate.h"
#include "intern/bmesh_mesh_normals.h"
#include "intern/bmesh_mesh_partial_update.h"
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index 5a9d1ba7bc4..a127089ad2c 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -510,23 +510,51 @@ static BMFace *bm_mesh_copy_new_face(
return f_new;
}
-void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst,
- const Mesh *me_src,
- const BMAllocTemplate *allocsize)
+void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst,
+ const Mesh *me_src_array[],
+ const int me_src_array_len,
+ const BMAllocTemplate *allocsize)
+
{
if (allocsize == NULL) {
allocsize = &bm_mesh_allocsize_default;
}
- CustomData_copy(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0);
- CustomData_copy(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0);
- CustomData_copy(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0);
- CustomData_copy(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0);
+ char cd_flag = 0;
+
+ for (int i = 0; i < me_src_array_len; i++) {
+ const Mesh *me_src = me_src_array[i];
+ if (i == 0) {
+ CustomData_copy(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0);
+ CustomData_copy(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0);
+ CustomData_copy(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0);
+ CustomData_copy(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0);
+ }
+ else {
+ CustomData_merge(&me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0);
+ CustomData_merge(&me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0);
+ CustomData_merge(&me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0);
+ CustomData_merge(&me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0);
+ }
+
+ cd_flag |= me_src->cd_flag;
+ }
+
+ cd_flag |= BM_mesh_cd_flag_from_bmesh(bm_dst);
CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT);
CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE);
CustomData_bmesh_init_pool(&bm_dst->ldata, allocsize->totloop, BM_LOOP);
CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
+
+ BM_mesh_cd_flag_apply(bm_dst, cd_flag);
+}
+
+void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst,
+ const Mesh *me_src,
+ const BMAllocTemplate *allocsize)
+{
+ BM_mesh_copy_init_customdata_from_mesh_array(bm_dst, &me_src, 1, allocsize);
}
void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTemplate *allocsize)
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index 692f3b403b5..008219165a8 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -30,19 +30,19 @@ struct Mesh;
*
* \returns false if any verts aren't found.
*/
-bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len);
+bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, 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);
+bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, 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);
+void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, int len);
/**
* Makes an NGon from an un-ordered set of verts.
@@ -82,7 +82,7 @@ BMFace *BM_face_create_quad_tri(BMesh *bm,
BMVert *v3,
BMVert *v4,
const BMFace *f_example,
- const eBMCreateFlag create_flag);
+ eBMCreateFlag create_flag);
/**
* \brief copies face loop data from shared adjacent faces.
@@ -114,9 +114,9 @@ BMFace *BM_face_create_ngon(BMesh *bm,
BMVert *v1,
BMVert *v2,
BMEdge **edges,
- const int len,
+ int len,
const BMFace *f_example,
- const eBMCreateFlag create_flag);
+ eBMCreateFlag create_flag);
/**
* Create an ngon from an array of sorted verts
*
@@ -127,11 +127,11 @@ BMFace *BM_face_create_ngon(BMesh *bm,
*/
BMFace *BM_face_create_ngon_verts(BMesh *bm,
BMVert **vert_arr,
- const int len,
+ int len,
const BMFace *f_example,
- const eBMCreateFlag create_flag,
- const bool calc_winding,
- const bool create_edges);
+ eBMCreateFlag create_flag,
+ bool calc_winding,
+ bool create_edges);
/**
* Copies attributes, e.g. customdata, header flags, etc, from one element
@@ -141,11 +141,24 @@ void BM_elem_attrs_copy_ex(BMesh *bm_src,
BMesh *bm_dst,
const void *ele_src_v,
void *ele_dst_v,
- const char hflag_mask,
- const uint64_t cd_mask_exclude);
+ char hflag_mask,
+ uint64_t cd_mask_exclude);
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v);
void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v);
+/**
+ * Initialize the `bm_dst` layers in preparation for populating it's contents with multiple meshes.
+ * Typically done using multiple calls to #BM_mesh_bm_from_me with the same `bm` argument).
+ *
+ * \note While the custom-data layers of all meshes are created, the active layers are set
+ * by the first instance mesh containing that layer type.
+ * This means the first mesh should always be the main mesh (from the user perspective),
+ * as this is the mesh they have control over (active UV layer for rendering for example).
+ */
+void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst,
+ const struct Mesh *me_src_array[],
+ int me_src_array_len,
+ const struct BMAllocTemplate *allocsize);
void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst,
const struct Mesh *me_src,
const struct BMAllocTemplate *allocsize);
@@ -163,14 +176,14 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst,
*/
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst,
BMesh *bm_src,
- const char htype,
+ char htype,
const struct BMAllocTemplate *allocsize);
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);
+char BM_face_flag_from_mflag(char mflag);
+char BM_edge_flag_from_mflag(short mflag);
/* ME -> BM */
-char BM_vert_flag_from_mflag(const char mflag);
+char BM_vert_flag_from_mflag(char mflag);
char BM_face_flag_to_mflag(BMFace *f);
short BM_edge_flag_to_mflag(BMEdge *e);
/* BM -> ME */
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index cd0e1754cd1..a885df51bd3 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -20,8 +20,7 @@
* \ingroup bmesh
*/
-BMFace *BM_face_copy(
- BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges);
+BMFace *BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, bool copy_verts, bool copy_edges);
typedef enum eBMCreateFlag {
BM_CREATE_NOP = 0,
@@ -41,7 +40,7 @@ typedef enum eBMCreateFlag {
BMVert *BM_vert_create(BMesh *bm,
const float co[3],
const BMVert *v_example,
- const eBMCreateFlag create_flag);
+ eBMCreateFlag create_flag);
/**
* \brief Main function for creating a new edge.
*
@@ -50,7 +49,7 @@ BMVert *BM_vert_create(BMesh *bm,
* 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);
+ BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, eBMCreateFlag create_flag);
/**
* Main face creation function
*
@@ -63,18 +62,18 @@ BMEdge *BM_edge_create(
BMFace *BM_face_create(BMesh *bm,
BMVert **verts,
BMEdge **edges,
- const int len,
+ int len,
const BMFace *f_example,
- const eBMCreateFlag create_flag);
+ 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,
+ int len,
const BMFace *f_example,
- const eBMCreateFlag create_flag,
- const bool create_edges);
+ eBMCreateFlag create_flag,
+ bool create_edges);
/**
* Kills all edges associated with \a f, along with any other faces containing those edges.
@@ -147,8 +146,8 @@ bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b);
*/
void bmesh_kernel_loop_reverse(BMesh *bm,
BMFace *f,
- const int cd_loop_mdisp_offset,
- const bool use_loop_mdisp_flip);
+ int cd_loop_mdisp_offset,
+ bool use_loop_mdisp_flip);
/**
* Avoid calling this where possible,
@@ -171,7 +170,7 @@ void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b);
* \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 *BM_faces_join(BMesh *bm, BMFace **faces, int totface, bool do_del);
/**
* High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate
*/
@@ -179,18 +178,14 @@ void BM_vert_separate(BMesh *bm,
BMVert *v,
BMEdge **e_in,
int e_in_len,
- const bool copy_select,
+ 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,
- const bool copy_select,
- BMVert ***r_vout,
- int *r_vout_len);
+void BM_vert_separate_hflag(
+ BMesh *bm, BMVert *v, char hflag, bool copy_select, BMVert ***r_vout, int *r_vout_len);
void BM_vert_separate_tested_edges(
BMesh *bm, BMVert *v_dst, BMVert *v_src, bool (*testfn)(BMEdge *, void *arg), void *arg);
@@ -211,7 +206,7 @@ void BM_vert_separate_tested_edges(
* \return Success
*/
void bmesh_kernel_vert_separate(
- BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select);
+ BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, bool copy_select);
/**
* \brief Separate Edge
*
@@ -223,7 +218,7 @@ void bmesh_kernel_vert_separate(
* \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);
+void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, bool copy_select);
/**
* \brief Split Face Make Edge (SFME)
@@ -272,7 +267,7 @@ BMFace *bmesh_kernel_split_face_make_edge(BMesh *bm,
ListBase *holes,
#endif
BMEdge *example,
- const bool no_double);
+ bool no_double);
/**
* \brief Split Edge Make Vert (SEMV)
@@ -326,10 +321,10 @@ BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEd
BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
- const bool do_del,
- const bool check_edge_exists,
- const bool kill_degenerate_faces,
- const bool kill_duplicate_faces);
+ bool do_del,
+ bool check_edge_exists,
+ bool kill_degenerate_faces,
+ bool kill_duplicate_faces);
/**
* \brief Join Vert Kill Edge (JVKE)
*
@@ -351,9 +346,9 @@ BMEdge *bmesh_kernel_join_edge_kill_vert(BMesh *bm,
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);
+ bool do_del,
+ bool check_edge_exists,
+ bool kill_degenerate_faces);
/**
* \brief Join Face Kill Edge (JFKE)
*
diff --git a/source/blender/bmesh/intern/bmesh_delete.h b/source/blender/bmesh/intern/bmesh_delete.h
index 18e278a99fd..068c35f6dc7 100644
--- a/source/blender/bmesh/intern/bmesh_delete.h
+++ b/source/blender/bmesh/intern/bmesh_delete.h
@@ -20,16 +20,16 @@
* \ingroup bmesh
*/
-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);
+void BMO_mesh_delete_oflag_tagged(BMesh *bm, short oflag, char htype);
+void BM_mesh_delete_hflag_tagged(BMesh *bm, char hflag, 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);
+void BMO_mesh_delete_oflag_context(BMesh *bm, short oflag, 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);
+void BM_mesh_delete_hflag_context(BMesh *bm, char hflag, int type);
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.h b/source/blender/bmesh/intern/bmesh_edgeloop.h
index 58b0d92fb72..9dc1e64dd46 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.h
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.h
@@ -48,16 +48,14 @@ void BM_mesh_edgeloops_calc_normal(BMesh *bm, struct ListBase *eloops);
void BM_mesh_edgeloops_calc_normal_aligned(BMesh *bm,
struct ListBase *eloops,
const float no_align[3]);
-void BM_mesh_edgeloops_calc_order(BMesh *bm, ListBase *eloops, const bool use_normals);
+void BM_mesh_edgeloops_calc_order(BMesh *bm, ListBase *eloops, bool use_normals);
/**
* 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,
- bool is_closed);
+struct BMEdgeLoopStore *BM_edgeloop_from_verts(BMVert **v_arr, int v_arr_tot, bool is_closed);
void BM_edgeloop_free(struct BMEdgeLoopStore *el_store);
bool BM_edgeloop_is_closed(struct BMEdgeLoopStore *el_store);
diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h
index d1a73509a4a..bf5b5bd09f4 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -28,7 +28,7 @@ void BM_loop_interp_multires_ex(BMesh *bm,
const BMFace *f_src,
const float f_dst_center[3],
const float f_src_center[3],
- const int cd_loop_mdisp_offset);
+ int cd_loop_mdisp_offset);
/**
* Project the multi-resolution grid in target onto f_src's set of multi-resolution grids.
*/
@@ -39,7 +39,7 @@ void BM_face_interp_multires_ex(BMesh *bm,
const BMFace *f_src,
const float f_dst_center[3],
const float f_src_center[3],
- const int cd_loop_mdisp_offset);
+ int cd_loop_mdisp_offset);
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);
@@ -52,7 +52,7 @@ void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src);
* \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);
+ BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, float fac);
/**
* \brief Data, Interpolate From Edges
*
@@ -61,19 +61,15 @@ void BM_data_interp_from_verts(
* \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);
+ BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, 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,
- BMVert *v,
- BMEdge *e,
- const float fac);
+void BM_data_interp_face_vert_edge(
+ BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v, BMEdge *e, float fac);
void BM_data_layer_add(BMesh *bm, CustomData *data, int type);
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name);
void BM_data_layer_free(BMesh *bm, CustomData *data, int type);
@@ -81,7 +77,7 @@ void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n);
void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int dst_n);
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);
+void BM_elem_float_data_set(CustomData *cd, void *element, int type, float val);
/**
* \brief Data Interpolate From Face
@@ -93,19 +89,19 @@ void BM_elem_float_data_set(CustomData *cd, void *element, int type, const float
void BM_face_interp_from_face_ex(BMesh *bm,
BMFace *f_dst,
const BMFace *f_src,
- const bool do_vertex,
+ bool do_vertex,
const void **blocks,
const void **blocks_v,
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);
+void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, 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);
+ BMesh *bm, BMLoop *l_dst, const BMFace *f_src, bool do_vertex, bool do_multires);
/**
* Smooths boundaries between multi-res grids,
@@ -114,16 +110,16 @@ void BM_loop_interp_from_face(
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);
+ BMesh *bm, BMVert *v, 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);
+void BM_vert_loop_groups_data_layer_merge(BMesh *bm, struct LinkNode *groups, 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,
+ int layer_n,
const float *loop_weights);
diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h
index 12b3581b0a1..1c9b322ef75 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.h
+++ b/source/blender/bmesh/intern/bmesh_iterators.h
@@ -188,14 +188,14 @@ typedef struct 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;
+void *BM_iter_at_index(BMesh *bm, 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);
+int BM_iter_as_array(BMesh *bm, char itype, void *data, void **array, int len);
/**
* \brief Iterator as Array
*
@@ -207,7 +207,7 @@ int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, cons
* Caller needs to free the array.
*/
void *BM_iter_as_arrayN(BMesh *bm,
- const char itype,
+ char itype,
void *data,
int *r_len,
void **stack_array,
@@ -219,18 +219,18 @@ void *BM_iter_as_arrayN(BMesh *bm,
*/
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char restrictmask,
+ char restrictmask,
void **array,
- const int len);
+ int len);
void *BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char restrictmask,
+ char restrictmask,
int *r_len,
/* optional args to avoid an alloc (normally stack array) */
void **stack_array,
int stack_array_size);
-int BM_iter_mesh_bitmap_from_filter(const char itype,
+int BM_iter_mesh_bitmap_from_filter(char itype,
BMesh *bm,
uint *bitmap,
bool (*test_fn)(BMElem *, void *user_data),
@@ -248,24 +248,23 @@ int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm,
*
* 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);
+int BM_iter_elem_count_flag(char itype, void *data, char hflag, 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);
+int BMO_iter_elem_count_flag(BMesh *bm, char itype, void *data, short oflag, bool value);
/**
* Utility function.
*/
-int BM_iter_mesh_count(const char itype, BMesh *bm);
+int BM_iter_mesh_count(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);
+int BM_iter_mesh_count_flag(char itype, BMesh *bm, char hflag, 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 e667505caca..edcd9159520 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -109,7 +109,7 @@ struct BMLog {
typedef struct {
float co[3];
- short no[3];
+ float no[3];
char hflag;
float mask;
} BMLogVert;
@@ -200,7 +200,7 @@ static void vert_mask_set(BMVert *v, const float new_mask, const int cd_vert_mas
static void bm_log_vert_bmvert_copy(BMLogVert *lv, BMVert *v, const int cd_vert_mask_offset)
{
copy_v3_v3(lv->co, v->co);
- normal_float_to_short_v3(lv->no, v->no);
+ copy_v3_v3(lv->no, v->no);
lv->mask = vert_mask_get(v, cd_vert_mask_offset);
lv->hflag = v->head.hflag;
}
@@ -294,7 +294,7 @@ static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
BMVert *v = BM_vert_create(bm, lv->co, NULL, BM_CREATE_NOP);
vert_mask_set(v, lv->mask, cd_vert_mask_offset);
v->head.hflag = lv->hflag;
- normal_short_to_float_v3(v->no, lv->no);
+ copy_v3_v3(v->no, lv->no);
bm_log_vert_id_set(log, v, POINTER_AS_UINT(key));
}
}
@@ -329,12 +329,9 @@ static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts)
uint id = POINTER_AS_UINT(key);
BMVert *v = bm_log_vert_from_id(log, id);
float mask;
- short normal[3];
swap_v3_v3(v->co, lv->co);
- copy_v3_v3_short(normal, lv->no);
- normal_float_to_short_v3(lv->no, v->no);
- normal_short_to_float_v3(v->no, normal);
+ swap_v3_v3(v->no, lv->no);
SWAP(char, v->head.hflag, lv->hflag);
mask = lv->mask;
lv->mask = vert_mask_get(v, cd_vert_mask_offset);
@@ -937,7 +934,7 @@ const float *BM_log_original_vert_co(BMLog *log, BMVert *v)
return lv->co;
}
-const short *BM_log_original_vert_no(BMLog *log, BMVert *v)
+const float *BM_log_original_vert_no(BMLog *log, BMVert *v)
{
BMLogEntry *entry = log->current_entry;
const BMLogVert *lv;
@@ -967,7 +964,7 @@ float BM_log_original_mask(BMLog *log, BMVert *v)
return lv->mask;
}
-void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const short **r_no)
+void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no)
{
BMLogEntry *entry = log->current_entry;
const BMLogVert *lv;
diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h
index c6df87168ee..935cb5aba28 100644
--- a/source/blender/bmesh/intern/bmesh_log.h
+++ b/source/blender/bmesh/intern/bmesh_log.h
@@ -119,7 +119,7 @@ void BM_log_redo(BMesh *bm, BMLog *log);
* 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);
+void BM_log_vert_before_modified(BMLog *log, struct BMVert *v, int cd_vert_mask_offset);
/* Log a new vertex as added to the BMesh */
/* Log a new vertex as added to the BMesh
@@ -128,7 +128,7 @@ void BM_log_vert_before_modified(BMLog *log, struct BMVert *v, const int cd_vert
* 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);
+void BM_log_vert_added(BMLog *log, struct BMVert *v, int cd_vert_mask_offset);
/* Log a face before it is modified */
/* Log a face before it is modified
@@ -164,7 +164,7 @@ void BM_log_face_added(BMLog *log, struct BMFace *f);
* 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);
+void BM_log_vert_removed(BMLog *log, struct BMVert *v, int cd_vert_mask_offset);
/* Log a face as removed from the BMesh */
/* Log a face as removed from the BMesh
@@ -196,11 +196,10 @@ void BM_log_before_all_removed(BMesh *bm, BMLog *log);
* 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);
+const float *BM_log_original_vert_no(BMLog *log, BMVert *v);
/* Get the logged mask of a vertex */
/* Get the logged mask of a vertex
@@ -209,7 +208,7 @@ const short *BM_log_original_vert_no(BMLog *log, BMVert *v);
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);
+void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no);
/* For internal use only (unit testing) */
/* For internal use only (unit testing) */
diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h
index 72b520cc72c..01c3291b525 100644
--- a/source/blender/bmesh/intern/bmesh_marking.h
+++ b/source/blender/bmesh/intern/bmesh_marking.h
@@ -39,10 +39,10 @@ typedef enum eBMSelectionFlushFLags {
/* 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);
+void _bm_elem_hide_set(BMesh *bm, BMHeader *head, bool hide);
+void BM_vert_hide_set(BMVert *v, bool hide);
+void BM_edge_hide_set(BMEdge *e, bool hide);
+void BM_face_hide_set(BMFace *f, bool hide);
/* Selection code. */
@@ -50,29 +50,15 @@ void BM_face_hide_set(BMFace *f, const bool hide);
* \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,
- const char htype,
- const char hflag,
- const bool respecthide,
- const bool overwrite,
- const char hflag_test);
-void BM_mesh_elem_hflag_disable_test(BMesh *bm,
- const char htype,
- const char hflag,
- const bool respecthide,
- const bool overwrite,
- const char hflag_test);
-
-void BM_mesh_elem_hflag_enable_all(BMesh *bm,
- const char htype,
- const char hflag,
- const bool respecthide);
-void BM_mesh_elem_hflag_disable_all(BMesh *bm,
- const char htype,
- const char hflag,
- const bool respecthide);
+void BM_elem_select_set(BMesh *bm, BMElem *ele, bool select);
+
+void BM_mesh_elem_hflag_enable_test(
+ BMesh *bm, char htype, char hflag, bool respecthide, bool overwrite, char hflag_test);
+void BM_mesh_elem_hflag_disable_test(
+ BMesh *bm, char htype, char hflag, bool respecthide, bool overwrite, char hflag_test);
+
+void BM_mesh_elem_hflag_enable_all(BMesh *bm, char htype, char hflag, bool respecthide);
+void BM_mesh_elem_hflag_disable_all(BMesh *bm, char htype, char hflag, bool respecthide);
/* Individual element select functions, #BM_elem_select_set is a shortcut for these
* that automatically detects which one to use. */
@@ -83,25 +69,25 @@ void BM_mesh_elem_hflag_disable_all(BMesh *bm,
* Changes selection state of a single vertex
* in a mesh
*/
-void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select);
+void BM_vert_select_set(BMesh *bm, BMVert *v, 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);
+void BM_edge_select_set(BMesh *bm, BMEdge *e, 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);
+void BM_face_select_set(BMesh *bm, BMFace *f, bool select);
/* 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);
+void BM_edge_select_set_noflush(BMesh *bm, BMEdge *e, bool select);
+void BM_face_select_set_noflush(BMesh *bm, BMFace *f, bool select);
/**
* \brief Select Mode Clean
@@ -111,7 +97,7 @@ void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select);
*
* \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_ex(BMesh *bm, short selectmode);
void BM_mesh_select_mode_clean(BMesh *bm);
/**
@@ -128,7 +114,7 @@ void BM_mesh_select_mode_set(BMesh *bm, int selectmode);
* (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_ex(BMesh *bm, short selectmode, eBMSelectionFlushFLags flags);
void BM_mesh_select_mode_flush(BMesh *bm);
/**
@@ -140,19 +126,13 @@ void BM_mesh_deselect_flush(BMesh *bm);
*/
void BM_mesh_select_flush(BMesh *bm);
-int BM_mesh_elem_hflag_count_enabled(BMesh *bm,
- const char htype,
- const char hflag,
- const bool respecthide);
-int BM_mesh_elem_hflag_count_disabled(BMesh *bm,
- const char htype,
- const char hflag,
- const bool respecthide);
+int BM_mesh_elem_hflag_count_enabled(BMesh *bm, char htype, char hflag, bool respecthide);
+int BM_mesh_elem_hflag_count_disabled(BMesh *bm, char htype, char hflag, bool respecthide);
/* 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);
+BMFace *BM_mesh_active_face_get(BMesh *bm, bool is_sloppy, 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);
@@ -211,7 +191,7 @@ 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);
+ BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, bool use_chain);
#define BM_SELECT_HISTORY_BACKUP(bm) \
{ \
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index ad52daa4731..b65f6e4c872 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -928,7 +928,7 @@ void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const
/* Edges' pointers, only vert pointers (as we don't mess with loops!),
* and - ack! - edge pointers,
- * as we have to handle disklinks... */
+ * as we have to handle disk-links. */
if (vptr_map || eptr_map) {
BM_ITER_MESH (ed, &iter, bm, BM_EDGES_OF_MESH) {
if (vptr_map) {
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index e00461ba571..94615d558fa 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -74,14 +74,14 @@ void BM_mesh_clear(BMesh *bm);
* 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);
+void bmesh_edit_begin(BMesh *bm, BMOpTypeFlag type_flag);
/**
* \brief BMesh End Edit
*/
-void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
+void bmesh_edit_end(BMesh *bm, 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);
+void BM_mesh_elem_index_ensure_ex(BMesh *bm, char htype, int elem_offset[4]);
+void BM_mesh_elem_index_ensure(BMesh *bm, char htype);
/**
* Array checking/setting macros.
*
@@ -109,10 +109,10 @@ bool BM_mesh_elem_table_check(BMesh *bm);
*/
void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags);
-void BM_mesh_elem_table_ensure(BMesh *bm, const char htype);
+void BM_mesh_elem_table_ensure(BMesh *bm, 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);
+void BM_mesh_elem_table_init(BMesh *bm, char htype);
+void BM_mesh_elem_table_free(BMesh *bm, char htype);
BLI_INLINE BMVert *BM_vert_at_index(BMesh *bm, const int index)
{
@@ -133,26 +133,26 @@ BLI_INLINE BMFace *BM_face_at_index(BMesh *bm, const int index)
return bm->ftable[index];
}
-BMVert *BM_vert_at_index_find(BMesh *bm, const int index);
-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);
+BMVert *BM_vert_at_index_find(BMesh *bm, int index);
+BMEdge *BM_edge_at_index_find(BMesh *bm, int index);
+BMFace *BM_face_at_index_find(BMesh *bm, int index);
+BMLoop *BM_loop_at_index_find(BMesh *bm, 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);
+BMVert *BM_vert_at_index_find_or_table(BMesh *bm, int index);
+BMEdge *BM_edge_at_index_find_or_table(BMesh *bm, int index);
+BMFace *BM_face_at_index_find_or_table(BMesh *bm, 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);
+int BM_mesh_elem_count(BMesh *bm, char htype);
/**
* Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index 544a81f7020..d6c642ff80b 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -40,7 +40,7 @@
*
* - The active key-block is used for BMesh vertex locations on entering edit-mode.
* So obviously the meshes vertex locations remain unchanged and the shape key
- * its self is not being edited directly.
+ * itself is not being edited directly.
* Simply the #BMVert.co is a initialized from active shape key (when its set).
* - All key-blocks are added as CustomData layers (read code for details).
*
@@ -79,8 +79,11 @@
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
+#include "BLI_array.hh"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_span.hh"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
@@ -95,6 +98,10 @@
#include "bmesh.h"
#include "intern/bmesh_private.h" /* For element checking. */
+using blender::Array;
+using blender::IndexRange;
+using blender::Span;
+
void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
{
const char cd_flag_all = BM_mesh_cd_flag_from_bmesh(bm) | cd_flag;
@@ -107,9 +114,9 @@ void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag)
void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
{
/* CustomData_bmesh_init_pool() must run first */
- BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.pool != NULL);
- BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != NULL);
- BLI_assert(bm->pdata.totlayer == 0 || bm->pdata.pool != NULL);
+ BLI_assert(bm->vdata.totlayer == 0 || bm->vdata.pool != nullptr);
+ BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != nullptr);
+ BLI_assert(bm->pdata.totlayer == 0 || bm->pdata.pool != nullptr);
if (cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
if (!CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
@@ -122,6 +129,17 @@ void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
}
}
+ if (cd_flag & ME_CDFLAG_VERT_CREASE) {
+ if (!CustomData_has_layer(&bm->vdata, CD_CREASE)) {
+ BM_data_layer_add(bm, &bm->vdata, CD_CREASE);
+ }
+ }
+ else {
+ if (CustomData_has_layer(&bm->vdata, CD_CREASE)) {
+ BM_data_layer_free(bm, &bm->vdata, CD_CREASE);
+ }
+ }
+
if (cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
if (!CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
BM_data_layer_add(bm, &bm->edata, CD_BWEIGHT);
@@ -151,6 +169,9 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
}
+ if (CustomData_has_layer(&bm->vdata, CD_CREASE)) {
+ cd_flag |= ME_CDFLAG_VERT_CREASE;
+ }
if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
}
@@ -161,35 +182,28 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
}
/* Static function for alloc (duplicate in modifiers_bmesh.c) */
-static BMFace *bm_face_create_from_mpoly(
- MPoly *mp, MLoop *ml, BMesh *bm, BMVert **vtable, BMEdge **etable)
+static BMFace *bm_face_create_from_mpoly(BMesh &bm,
+ Span<MLoop> loops,
+ Span<BMVert *> vtable,
+ Span<BMEdge *> etable)
{
- BMVert **verts = BLI_array_alloca(verts, mp->totloop);
- BMEdge **edges = BLI_array_alloca(edges, mp->totloop);
- int j;
+ Array<BMVert *, BM_DEFAULT_NGON_STACK_SIZE> verts(loops.size());
+ Array<BMEdge *, BM_DEFAULT_NGON_STACK_SIZE> edges(loops.size());
- for (j = 0; j < mp->totloop; j++, ml++) {
- verts[j] = vtable[ml->v];
- edges[j] = etable[ml->e];
+ for (const int i : loops.index_range()) {
+ verts[i] = vtable[loops[i].v];
+ edges[i] = etable[loops[i].e];
}
- return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD);
+ return BM_face_create(&bm, verts.data(), edges.data(), loops.size(), nullptr, BM_CREATE_SKIP_CD);
}
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 ||
bm->pdata.totlayer || bm->ldata.totlayer));
- MVert *mvert;
- MEdge *medge;
- MLoop *mloop;
- MPoly *mp;
- KeyBlock *actkey, *block;
- BMVert *v, **vtable = NULL;
- BMEdge *e, **etable = NULL;
- BMFace *f, **ftable = NULL;
- float(*keyco)[3] = NULL;
- int totloops, i;
+ KeyBlock *actkey;
+ float(*keyco)[3] = nullptr;
CustomData_MeshMasks mask = CD_MASK_BMESH;
CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
@@ -208,6 +222,14 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
return; /* Sanity check. */
}
+ /* Only copy normals to the new BMesh if they are not already dirty. This avoids unnecessary
+ * work, but also accessing normals on an incomplete mesh, for example when restoring undo steps
+ * in edit mode. */
+ const float(*vert_normals)[3] = nullptr;
+ if (!BKE_mesh_vertex_normals_are_dirty(me)) {
+ vert_normals = BKE_mesh_vertex_normals_ensure(me);
+ }
+
if (is_new) {
CustomData_copy(&me->vdata, &bm->vdata, mask.vmask, CD_CALLOC, 0);
CustomData_copy(&me->edata, &bm->edata, mask.emask, CD_CALLOC, 0);
@@ -224,7 +246,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* -------------------------------------------------------------------- */
/* Shape Key */
int tot_shape_keys = 0;
- if (me->key != NULL && DEG_is_original_id(&me->id)) {
+ if (me->key != nullptr && DEG_is_original_id(&me->id)) {
/* Evaluated meshes can be topologically inconsistent with their shape keys.
* Shape keys are also already integrated into the state of the evaluated
* mesh, so considering them here would kind of apply them twice. */
@@ -251,20 +273,20 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
if (is_new == false) {
tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY));
}
- const float(**shape_key_table)[3] = tot_shape_keys ?
- BLI_array_alloca(shape_key_table, tot_shape_keys) :
- NULL;
+ const float(**shape_key_table)[3] = tot_shape_keys ? (const float(**)[3])BLI_array_alloca(
+ shape_key_table, tot_shape_keys) :
+ nullptr;
if ((params->active_shapekey != 0) && tot_shape_keys > 0) {
- actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1);
+ actkey = static_cast<KeyBlock *>(BLI_findlink(&me->key->block, params->active_shapekey - 1));
}
else {
- actkey = NULL;
+ actkey = nullptr;
}
if (is_new) {
if (tot_shape_keys || params->add_key_index) {
- CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, NULL, 0);
+ CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, nullptr, 0);
}
}
@@ -279,26 +301,29 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
__func__);
me->key->uidgen = 1;
- for (block = me->key->block.first; block; block = block->next) {
+ LISTBASE_FOREACH (KeyBlock *, block, &me->key->block) {
block->uid = me->key->uidgen++;
}
}
}
if (actkey && actkey->totelem == me->totvert) {
- keyco = params->use_shapekey ? actkey->data : NULL;
+ keyco = params->use_shapekey ? static_cast<float(*)[3]>(actkey->data) : nullptr;
if (is_new) {
bm->shapenr = params->active_shapekey;
}
}
- for (i = 0, block = me->key->block.first; i < tot_shape_keys; block = block->next, i++) {
+ int i;
+ KeyBlock *block;
+ for (i = 0, block = static_cast<KeyBlock *>(me->key->block.first); i < tot_shape_keys;
+ block = block->next, i++) {
if (is_new) {
- CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, CD_ASSIGN, NULL, 0, block->name);
+ CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, CD_ASSIGN, nullptr, 0, block->name);
int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
bm->vdata.layers[j].uid = block->uid;
}
- shape_key_table[i] = (const float(*)[3])block->data;
+ shape_key_table[i] = static_cast<const float(*)[3]>(block->data);
}
}
@@ -307,40 +332,50 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE);
CustomData_bmesh_init_pool(&bm->ldata, me->totloop, BM_LOOP);
CustomData_bmesh_init_pool(&bm->pdata, me->totpoly, BM_FACE);
-
- BM_mesh_cd_flag_apply(bm, me->cd_flag);
}
-
- const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
- const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+ BM_mesh_cd_flag_apply(bm, me->cd_flag | (is_new ? 0 : BM_mesh_cd_flag_from_bmesh(bm)));
+
+ /* Only copy these values over if the source mesh is flagged to be using them.
+ * Even if `bm` has these layers, they may have been added from another mesh, when `!is_new`. */
+ const int cd_vert_bweight_offset = (me->cd_flag & ME_CDFLAG_VERT_BWEIGHT) ?
+ CustomData_get_offset(&bm->vdata, CD_BWEIGHT) :
+ -1;
+ const int cd_edge_bweight_offset = (me->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) ?
+ CustomData_get_offset(&bm->edata, CD_BWEIGHT) :
+ -1;
+ const int cd_edge_crease_offset = (me->cd_flag & ME_CDFLAG_EDGE_CREASE) ?
+ CustomData_get_offset(&bm->edata, CD_CREASE) :
+ -1;
const int cd_shape_key_offset = tot_shape_keys ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) :
-1;
const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ?
CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX) :
-1;
- vtable = MEM_mallocN(sizeof(BMVert **) * me->totvert, __func__);
-
- for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
- v = vtable[i] = BM_vert_create(bm, keyco ? keyco[i] : mvert->co, NULL, BM_CREATE_SKIP_CD);
+ Span<MVert> mvert{me->mvert, me->totvert};
+ Array<BMVert *> vtable(me->totvert);
+ for (const int i : mvert.index_range()) {
+ BMVert *v = vtable[i] = BM_vert_create(
+ bm, keyco ? keyco[i] : mvert[i].co, nullptr, BM_CREATE_SKIP_CD);
BM_elem_index_set(v, i); /* set_ok */
/* Transfer flag. */
- v->head.hflag = BM_vert_flag_from_mflag(mvert->flag & ~SELECT);
+ v->head.hflag = BM_vert_flag_from_mflag(mvert[i].flag & ~SELECT);
/* This is necessary for selection counts to work properly. */
- if (mvert->flag & SELECT) {
+ if (mvert[i].flag & SELECT) {
BM_vert_select_set(bm, v, true);
}
- normal_short_to_float_v3(v->no, mvert->no);
+ if (vert_normals) {
+ copy_v3_v3(v->no, vert_normals[i]);
+ }
/* Copy Custom Data */
CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true);
if (cd_vert_bweight_offset != -1) {
- BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert->bweight / 255.0f);
+ BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert[i].bweight / 255.0f);
}
/* Set shape key original index. */
@@ -350,7 +385,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* Set shape-key data. */
if (tot_shape_keys) {
- float(*co_dst)[3] = BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
+ float(*co_dst)[3] = (float(*)[3])BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
for (int j = 0; j < tot_shape_keys; j++, co_dst++) {
copy_v3_v3(*co_dst, shape_key_table[j][i]);
}
@@ -360,19 +395,18 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
bm->elem_index_dirty &= ~BM_VERT; /* Added in order, clear dirty flag. */
}
- etable = MEM_mallocN(sizeof(BMEdge **) * me->totedge, __func__);
-
- medge = me->medge;
- for (i = 0; i < me->totedge; i++, medge++) {
- e = etable[i] = BM_edge_create(
- bm, vtable[medge->v1], vtable[medge->v2], NULL, BM_CREATE_SKIP_CD);
+ Span<MEdge> medge{me->medge, me->totedge};
+ Array<BMEdge *> etable(me->totedge);
+ for (const int i : medge.index_range()) {
+ BMEdge *e = etable[i] = BM_edge_create(
+ bm, vtable[medge[i].v1], vtable[medge[i].v2], nullptr, BM_CREATE_SKIP_CD);
BM_elem_index_set(e, i); /* set_ok */
/* Transfer flags. */
- e->head.hflag = BM_edge_flag_from_mflag(medge->flag & ~SELECT);
+ e->head.hflag = BM_edge_flag_from_mflag(medge[i].flag & ~SELECT);
/* This is necessary for selection counts to work properly. */
- if (medge->flag & SELECT) {
+ if (medge[i].flag & SELECT) {
BM_edge_select_set(bm, e, true);
}
@@ -380,33 +414,35 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true);
if (cd_edge_bweight_offset != -1) {
- BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge->bweight / 255.0f);
+ BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge[i].bweight / 255.0f);
}
if (cd_edge_crease_offset != -1) {
- BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge->crease / 255.0f);
+ BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge[i].crease / 255.0f);
}
}
if (is_new) {
bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */
}
+ Span<MPoly> mpoly{me->mpoly, me->totpoly};
+ Span<MLoop> mloop{me->mloop, me->totloop};
+
/* Only needed for selection. */
+
+ Array<BMFace *> ftable;
if (me->mselect && me->totselect != 0) {
- ftable = MEM_mallocN(sizeof(BMFace **) * me->totpoly, __func__);
+ ftable.reinitialize(me->totpoly);
}
- mloop = me->mloop;
- mp = me->mpoly;
- for (i = 0, totloops = 0; i < me->totpoly; i++, mp++) {
- BMLoop *l_iter;
- BMLoop *l_first;
-
- f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart, bm, vtable, etable);
- if (ftable != NULL) {
+ int totloops = 0;
+ for (const int i : mpoly.index_range()) {
+ BMFace *f = bm_face_create_from_mpoly(
+ *bm, mloop.slice(mpoly[i].loopstart, mpoly[i].totloop), vtable, etable);
+ if (!ftable.is_empty()) {
ftable[i] = f;
}
- if (UNLIKELY(f == NULL)) {
+ if (UNLIKELY(f == nullptr)) {
printf(
"%s: Warning! Bad face in mesh"
" \"%s\" at index %d!, skipping\n",
@@ -420,20 +456,21 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
BM_elem_index_set(f, bm->totface - 1); /* set_ok */
/* Transfer flag. */
- f->head.hflag = BM_face_flag_from_mflag(mp->flag & ~ME_FACE_SEL);
+ f->head.hflag = BM_face_flag_from_mflag(mpoly[i].flag & ~ME_FACE_SEL);
/* This is necessary for selection counts to work properly. */
- if (mp->flag & ME_FACE_SEL) {
+ if (mpoly[i].flag & ME_FACE_SEL) {
BM_face_select_set(bm, f, true);
}
- f->mat_nr = mp->mat_nr;
+ f->mat_nr = mpoly[i].mat_nr;
if (i == me->act_face) {
bm->act_face = f;
}
- int j = mp->loopstart;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ int j = mpoly[i].loopstart;
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
do {
/* Don't use 'j' since we may have skipped some faces, hence some loops. */
BM_elem_index_set(l_iter, totloops++); /* set_ok */
@@ -454,44 +491,39 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
}
/* -------------------------------------------------------------------- */
- /* MSelect clears the array elements (avoid adding multiple times).
+ /* MSelect clears the array elements (to avoid adding multiple times).
*
* Take care to keep this last and not use (v/e/ftable) after this.
*/
if (me->mselect && me->totselect != 0) {
- MSelect *msel;
- for (i = 0, msel = me->mselect; i < me->totselect; i++, msel++) {
+ for (const int i : IndexRange(me->totselect)) {
+ const MSelect &msel = me->mselect[i];
+
BMElem **ele_p;
- switch (msel->type) {
+ switch (msel.type) {
case ME_VSEL:
- ele_p = (BMElem **)&vtable[msel->index];
+ ele_p = (BMElem **)&vtable[msel.index];
break;
case ME_ESEL:
- ele_p = (BMElem **)&etable[msel->index];
+ ele_p = (BMElem **)&etable[msel.index];
break;
case ME_FSEL:
- ele_p = (BMElem **)&ftable[msel->index];
+ ele_p = (BMElem **)&ftable[msel.index];
break;
default:
continue;
}
- if (*ele_p != NULL) {
+ if (*ele_p != nullptr) {
BM_select_history_store_notest(bm, *ele_p);
- *ele_p = NULL;
+ *ele_p = nullptr;
}
}
}
else {
BM_select_history_clear(bm);
}
-
- MEM_freeN(vtable);
- MEM_freeN(etable);
- if (ftable) {
- MEM_freeN(ftable);
- }
}
/**
@@ -500,7 +532,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
{
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
- BMVert **vertMap = NULL;
+ BMVert **vertMap = nullptr;
BMVert *eve;
int i = 0;
BMIter iter;
@@ -508,7 +540,7 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
/* Caller needs to ensure this. */
BLI_assert(ototvert > 0);
- vertMap = MEM_callocN(sizeof(*vertMap) * ototvert, "vertMap");
+ vertMap = static_cast<BMVert **>(MEM_callocN(sizeof(*vertMap) * ototvert, "vertMap"));
if (cd_shape_keyindex_offset != -1) {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
@@ -516,7 +548,7 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
/* Not fool-proof, but chances are if we have many verts with the same index,
* we will want to use the first one,
* since the second is more likely to be a duplicate. */
- (vertMap[keyi] == NULL)) {
+ (vertMap[keyi] == nullptr)) {
vertMap[keyi] = eve;
}
}
@@ -559,8 +591,8 @@ BLI_INLINE void bmesh_quick_edgedraw_flag(MEdge *med, BMEdge *e)
{
/* This is a cheap way to set the edge draw, its not precise and will
* pick the first 2 faces an edge uses.
- * The dot comparison is a little arbitrary, but set so that a 5 subd
- * IcoSphere won't vanish but subd 6 will (as with pre-bmesh Blender). */
+ * The dot comparison is a little arbitrary, but set so that a 5 subdivisions
+ * ico-sphere won't vanish but 6 subdivisions will (as with pre-bmesh Blender). */
if (/* (med->flag & ME_EDGEDRAW) && */ /* Assume to be true. */
(e->l && (e->l != e->l->radial_next)) &&
@@ -586,7 +618,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
- MVert *oldverts = NULL;
+ MVert *oldverts = nullptr;
const int ototvert = me->totvert;
if (me->key && (cd_shape_keyindex_offset != -1)) {
@@ -597,9 +629,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
oldverts = MEM_dupallocN(me->mvert);
#else
oldverts = me->mvert;
- me->mvert = NULL;
+ me->mvert = nullptr;
CustomData_update_typemap(&me->vdata);
- CustomData_set_layer(&me->vdata, CD_MVERT, NULL);
+ CustomData_set_layer(&me->vdata, CD_MVERT, nullptr);
#endif
}
@@ -616,7 +648,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
me->totloop = bm->totloop;
me->totpoly = bm->totface;
/* Will be overwritten with a valid value if 'dotess' is set, otherwise we
- * end up with 'me->totface' and me->mface == NULL which can crash T28625. */
+ * end up with 'me->totface' and me->mface == nullptr which can crash T28625. */
me->totface = 0;
me->act_face = -1;
@@ -629,25 +661,32 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_CALLOC, me->totpoly);
}
- MVert *mvert = bm->totvert ? MEM_callocN(sizeof(MVert) * bm->totvert, "bm_to_me.vert") : NULL;
- MEdge *medge = bm->totedge ? MEM_callocN(sizeof(MEdge) * bm->totedge, "bm_to_me.edge") : NULL;
- MLoop *mloop = bm->totloop ? MEM_callocN(sizeof(MLoop) * bm->totloop, "bm_to_me.loop") : NULL;
- MPoly *mpoly = bm->totface ? MEM_callocN(sizeof(MPoly) * bm->totface, "bm_to_me.poly") : NULL;
+ MVert *mvert = bm->totvert ? (MVert *)MEM_callocN(sizeof(MVert) * bm->totvert, "bm_to_me.vert") :
+ nullptr;
+ MEdge *medge = bm->totedge ? (MEdge *)MEM_callocN(sizeof(MEdge) * bm->totedge, "bm_to_me.edge") :
+ nullptr;
+ MLoop *mloop = bm->totloop ? (MLoop *)MEM_callocN(sizeof(MLoop) * bm->totloop, "bm_to_me.loop") :
+ nullptr;
+ MPoly *mpoly = bm->totface ? (MPoly *)MEM_callocN(sizeof(MPoly) * bm->totface, "bm_to_me.poly") :
+ nullptr;
CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop);
CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly);
+ /* There is no way to tell if BMesh normals are dirty or not. Instead of calculating the normals
+ * on the BMesh possibly unnecessarily, just tag them dirty on the resulting mesh. */
+ BKE_mesh_normals_tag_dirty(me);
+
me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
/* This is called again, 'dotess' arg is used there. */
- BKE_mesh_update_customdata_pointers(me, 0);
+ BKE_mesh_update_customdata_pointers(me, false);
i = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
copy_v3_v3(mvert->co, v->co);
- normal_float_to_short_v3(mvert->no, v->no);
mvert->flag = BM_vert_flag_to_mflag(v);
@@ -733,15 +772,13 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
/* Patch hook indices and vertex parents. */
if (params->calc_object_remap && (ototvert > 0)) {
- BLI_assert(bmain != NULL);
- Object *ob;
- ModifierData *md;
- BMVert **vertMap = NULL;
+ BLI_assert(bmain != nullptr);
+ BMVert **vertMap = nullptr;
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) {
- if (vertMap == NULL) {
+ if (vertMap == nullptr) {
vertMap = bm_to_mesh_vertex_map(bm, ototvert);
}
@@ -765,11 +802,11 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
if (ob->data == me) {
- for (md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Hook) {
HookModifierData *hmd = (HookModifierData *)md;
- if (vertMap == NULL) {
+ if (vertMap == nullptr) {
vertMap = bm_to_mesh_vertex_map(bm, ototvert);
}
@@ -800,15 +837,15 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BKE_mesh_update_customdata_pointers(me, false);
{
- BMEditSelection *selected;
me->totselect = BLI_listbase_count(&(bm->selected));
MEM_SAFE_FREE(me->mselect);
if (me->totselect != 0) {
- me->mselect = MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history");
+ me->mselect = static_cast<MSelect *>(
+ MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history"));
}
- for (i = 0, selected = bm->selected.first; selected; i++, selected = selected->next) {
+ LISTBASE_FOREACH_INDEX (BMEditSelection *, selected, &bm->selected, i) {
if (selected->htype == BM_VERT) {
me->mselect[i].type = ME_VSEL;
}
@@ -827,9 +864,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
if (me->key) {
KeyBlock *currkey;
- KeyBlock *actkey = BLI_findlink(&me->key->block, bm->shapenr - 1);
+ KeyBlock *actkey = static_cast<KeyBlock *>(BLI_findlink(&me->key->block, bm->shapenr - 1));
- float(*ofs)[3] = NULL;
+ float(*ofs)[3] = nullptr;
/* Go through and find any shape-key custom-data layers
* that might not have corresponding KeyBlocks, and add them if necessary. */
@@ -838,7 +875,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
continue;
}
- for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ for (currkey = (KeyBlock *)me->key->block.first; currkey; currkey = currkey->next) {
if (currkey->uid == bm->vdata.layers[i].uid) {
break;
}
@@ -856,10 +893,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
/* Unlikely, but the active key may not be valid if the
* BMesh and the mesh are out of sync. */
- (actkey != NULL) &&
+ (actkey != nullptr) &&
/* Not used here, but 'oldverts' is used later for applying 'ofs'. */
- (oldverts != NULL) &&
+ (oldverts != nullptr) &&
/* Needed for referencing oldverts. */
(cd_shape_keyindex_offset != -1)) {
@@ -868,9 +905,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
/* Active key is a base. */
if (act_is_basis) {
- const float(*fp)[3] = actkey->data;
+ const float(*fp)[3] = static_cast<const float(*)[3]>(actkey->data);
- ofs = MEM_callocN(sizeof(float[3]) * bm->totvert, "currkey->data");
+ ofs = static_cast<float(*)[3]>(
+ MEM_callocN(sizeof(float[3]) * bm->totvert, "currkey->data"));
mvert = me->mvert;
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
@@ -884,7 +922,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
* because it will only work for the existing vertices and not the new
* ones, creating a mess when doing e.g. subdivide + translate. */
MEM_freeN(ofs);
- ofs = NULL;
+ ofs = nullptr;
break;
}
@@ -893,7 +931,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
- for (currkey = me->key->block.first; currkey; currkey = currkey->next) {
+ LISTBASE_FOREACH (KeyBlock *, currkey, &me->key->block) {
int keyi;
const float(*ofs_pt)[3] = ofs;
float *newkey, (*oldkey)[3], *fp;
@@ -903,11 +941,12 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
CustomData_get_n_offset(&bm->vdata,
CD_SHAPEKEY,
currkey_uuid);
- const bool apply_offset = (cd_shape_offset != -1) && (ofs != NULL) && (currkey != actkey) &&
- (bm->shapenr - 1 == currkey->relative);
+ const bool apply_offset = (cd_shape_offset != -1) && (ofs != nullptr) &&
+ (currkey != actkey) && (bm->shapenr - 1 == currkey->relative);
- fp = newkey = MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data");
- oldkey = currkey->data;
+ fp = newkey = static_cast<float *>(
+ MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data"));
+ oldkey = static_cast<float(*)[3]>(currkey->data);
mvert = me->mvert;
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
@@ -928,9 +967,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
else if (cd_shape_offset != -1) {
/* In most cases this runs. */
- copy_v3_v3(fp, BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset));
+ copy_v3_v3(fp, (const float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset));
}
- else if ((oldkey != NULL) && (cd_shape_keyindex_offset != -1) &&
+ else if ((oldkey != nullptr) && (cd_shape_keyindex_offset != -1) &&
((keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset)) != ORIGINDEX_NONE) &&
(keyi < currkey->totelem)) {
/* Old method of reconstructing keys via vertices original key indices,
@@ -950,7 +989,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
* Otherwise, in case we call again #BM_mesh_bm_to_me on same BMesh,
* we'll apply diff from previous call to #BM_mesh_bm_to_me,
* to shape-key values from *original creation of the BMesh*. See T50524. */
- copy_v3_v3(BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp);
+ copy_v3_v3((float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp);
}
fp += 3;
@@ -980,7 +1019,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
}
}
- if (oldverts != NULL) {
+ if (oldverts != nullptr) {
MEM_freeN(oldverts);
}
@@ -995,7 +1034,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
{
/* Must be an empty mesh. */
BLI_assert(me->totvert == 0);
- BLI_assert(cd_mask_extra == NULL || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0);
+ BLI_assert(cd_mask_extra == nullptr || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0);
me->totvert = bm->totvert;
me->totedge = bm->totedge;
@@ -1003,19 +1042,19 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
me->totloop = bm->totloop;
me->totpoly = bm->totface;
- CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totvert);
- CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totedge);
- CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, bm->totface);
+ CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totvert);
+ CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totedge);
+ CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, nullptr, bm->totface);
- CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, bm->totvert);
- CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, bm->totedge);
- CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, bm->totloop);
- CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, bm->totface);
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, bm->totvert);
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, nullptr, bm->totedge);
+ CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, nullptr, bm->totloop);
+ CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, nullptr, bm->totface);
/* Don't process shape-keys, we only feed them through the modifier stack as needed,
* e.g. for applying modifiers or the like. */
CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH;
- if (cd_mask_extra != NULL) {
+ if (cd_mask_extra != nullptr) {
CustomData_MeshMasks_update(&mask, cd_mask_extra);
}
mask.vmask &= ~CD_MASK_SHAPEKEY;
@@ -1041,12 +1080,14 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+ BKE_mesh_normals_tag_dirty(me);
+
me->runtime.deformed_only = true;
/* Don't add origindex layer if one already exists. */
add_orig = !CustomData_has_layer(&bm->pdata, CD_ORIGINDEX);
- index = CustomData_get_layer(&me->vdata, CD_ORIGINDEX);
+ index = (int *)CustomData_get_layer(&me->vdata, CD_ORIGINDEX);
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
MVert *mv = &mvert[i];
@@ -1055,8 +1096,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
BM_elem_index_set(eve, i); /* set_inline */
- normal_float_to_short_v3(mv->no, eve->no);
-
mv->flag = BM_vert_flag_to_mflag(eve);
if (cd_vert_bweight_offset != -1) {
@@ -1071,7 +1110,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
}
bm->elem_index_dirty &= ~BM_VERT;
- index = CustomData_get_layer(&me->edata, CD_ORIGINDEX);
+ index = (int *)CustomData_get_layer(&me->edata, CD_ORIGINDEX);
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
MEdge *med = &medge[i];
@@ -1104,7 +1143,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
}
bm->elem_index_dirty &= ~BM_EDGE;
- index = CustomData_get_layer(&me->pdata, CD_ORIGINDEX);
+ index = (int *)CustomData_get_layer(&me->pdata, CD_ORIGINDEX);
j = 0;
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
BMLoop *l_iter;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h
index ea114487285..07ffc8b43df 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h
@@ -29,8 +29,8 @@ struct CustomData_MeshMasks;
struct Main;
struct Mesh;
-void BM_mesh_cd_flag_ensure(BMesh *bm, struct Mesh *mesh, const char cd_flag);
-void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag);
+void BM_mesh_cd_flag_ensure(BMesh *bm, struct Mesh *mesh, char cd_flag);
+void BM_mesh_cd_flag_apply(BMesh *bm, char cd_flag);
char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
struct BMeshFromMeshParams {
diff --git a/source/blender/bmesh/intern/bmesh_mesh_debug.c b/source/blender/bmesh/intern/bmesh_mesh_debug.c
new file mode 100644
index 00000000000..81a11df13f2
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mesh_debug.c
@@ -0,0 +1,86 @@
+/*
+ * 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
+ *
+ * Evaluated mesh info printing function, to help track down differences output.
+ *
+ * Output from these functions can be evaluated as Python literals.
+ * See `mesh_debug.cc` for the equivalent #Mesh functionality.
+ */
+
+#ifndef NDEBUG
+
+# include <stdio.h>
+
+# include "MEM_guardedalloc.h"
+
+# include "BLI_utildefines.h"
+
+# include "BKE_customdata.h"
+
+# include "bmesh.h"
+
+# include "bmesh_mesh_debug.h"
+
+# include "BLI_dynstr.h"
+
+char *BM_mesh_debug_info(BMesh *bm)
+{
+ DynStr *dynstr = BLI_dynstr_new();
+ char *ret;
+
+ const char *indent8 = " ";
+
+ BLI_dynstr_append(dynstr, "{\n");
+ BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)bm);
+ BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", bm->totvert);
+ BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", bm->totedge);
+ BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", bm->totface);
+
+ BLI_dynstr_append(dynstr, " 'vert_layers': (\n");
+ CustomData_debug_info_from_layers(&bm->vdata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'edge_layers': (\n");
+ CustomData_debug_info_from_layers(&bm->edata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'loop_layers': (\n");
+ CustomData_debug_info_from_layers(&bm->ldata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, " 'poly_layers': (\n");
+ CustomData_debug_info_from_layers(&bm->pdata, indent8, dynstr);
+ BLI_dynstr_append(dynstr, " ),\n");
+
+ BLI_dynstr_append(dynstr, "}\n");
+
+ ret = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+ return ret;
+}
+
+void BM_mesh_debug_print(BMesh *bm)
+{
+ char *str = BM_mesh_debug_info(bm);
+ puts(str);
+ fflush(stdout);
+ MEM_freeN(str);
+}
+
+#endif /* NDEBUG */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_debug.h b/source/blender/bmesh/intern/bmesh_mesh_debug.h
new file mode 100644
index 00000000000..e903b627419
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mesh_debug.h
@@ -0,0 +1,30 @@
+/*
+ * 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 bmesh
+ */
+
+#include "BLI_compiler_attrs.h"
+
+#include "bmesh.h"
+
+#ifndef NDEBUG
+char *BM_mesh_debug_info(BMesh *bm) ATTR_NONNULL(1) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+void BM_mesh_debug_print(BMesh *bm) ATTR_NONNULL(1);
+#endif /* NDEBUG */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.h b/source/blender/bmesh/intern/bmesh_mesh_normals.h
index a2e64b1dc9b..d9b9a88b10d 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.h
@@ -67,13 +67,13 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
const float (*vcos)[3],
const float (*vnos)[3],
const float (*fnos)[3],
- const bool use_split_normals,
- const float split_angle,
+ bool use_split_normals,
+ float split_angle,
float (*r_lnos)[3],
struct MLoopNorSpaceArray *r_lnors_spacearr,
short (*clnors_data)[2],
- const int cd_loop_clnors_offset,
- const bool do_rebuild);
+ int cd_loop_clnors_offset,
+ bool do_rebuild);
/**
* Check whether given loop is part of an unknown-so-far cyclic smooth fan, or not.
@@ -82,21 +82,21 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
*/
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_invalidate(BMesh *bm, 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);
+void BM_normals_loops_edges_tag(BMesh *bm, bool do_edges);
#ifndef NDEBUG
void BM_lnorspace_err(BMesh *bm);
#endif
/* Loop Generics */
struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm,
- const bool do_all_loops_of_vert);
+ bool do_all_loops_of_vert);
void BM_loop_normal_editdata_array_free(struct BMLoopNorEditDataArray *lnors_ed_arr);
/**
@@ -112,4 +112,4 @@ void BM_custom_loop_normals_from_vector_layer(struct BMesh *bm, bool add_sharp_e
* 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);
+void BM_edges_sharp_from_angle_set(BMesh *bm, float split_angle);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_partial_update.h b/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
index 57f57053606..a280acb4624 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_partial_update.h
@@ -59,7 +59,7 @@ typedef struct BMPartialUpdate {
BMPartialUpdate *BM_mesh_partial_create_from_verts(BMesh *bm,
const BMPartialUpdate_Params *params,
const unsigned int *verts_mask,
- const int verts_mask_count)
+ int verts_mask_count)
ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
/**
@@ -71,7 +71,7 @@ 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;
+ 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.
@@ -93,9 +93,7 @@ BMPartialUpdate *BM_mesh_partial_create_from_verts_group_single(
* \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,
- const int *verts_group,
- const int verts_group_count) ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
+ BMesh *bm, const BMPartialUpdate_Params *params, const int *verts_group, int verts_group_count)
+ ATTR_NONNULL(1, 2, 3) ATTR_WARN_UNUSED_RESULT;
void BM_mesh_partial_destroy(BMPartialUpdate *bmpinfo) ATTR_NONNULL(1);
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index f4a5a0bce33..4e8a8a14a6a 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -65,7 +65,7 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v);
*
* \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);
+BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, bool do_del);
/** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */
@@ -87,13 +87,8 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_de
* 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,
- BMLoop *l_b,
- BMLoop **r_l,
- BMEdge *example,
- const bool no_double);
+BMFace *BM_face_split(
+ BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, BMLoop **r_l, BMEdge *example, bool no_double);
/**
* \brief Face Split with intermediate points
@@ -149,10 +144,10 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
float fac,
- const bool do_del,
- const bool join_faces,
- const bool kill_degenerate_faces,
- const bool kill_duplicate_faces);
+ bool do_del,
+ bool join_faces,
+ bool kill_degenerate_faces,
+ bool kill_duplicate_faces);
/**
* \brief Vert Collapse Faces
*
@@ -163,18 +158,15 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm,
BMEdge *BM_vert_collapse_edge(BMesh *bm,
BMEdge *e_kill,
BMVert *v_kill,
- const bool do_del,
- const bool kill_degenerate_faces,
- const bool kill_duplicate_faces);
+ bool do_del,
+ bool kill_degenerate_faces,
+ 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);
+BMVert *BM_edge_collapse(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill, bool do_del, bool kill_degenerate_faces);
/**
* \brief Edge Split
@@ -227,7 +219,7 @@ bool BM_face_validate(BMFace *face, FILE *err);
*
* \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);
+void BM_edge_calc_rotate(BMEdge *e, bool ccw, BMLoop **r_l1, BMLoop **r_l2);
/**
* \brief Check if Rotate Edge is OK
*
@@ -262,7 +254,7 @@ bool BM_edge_rotate_check_beauty(BMEdge *e, BMLoop *l1, BMLoop *l2);
*
* \see header definition for \a check_flag enum.
*/
-BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag);
+BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, bool ccw, short check_flag);
/** Flags for #BM_edge_rotate */
enum {
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 7865c79323d..85ea27b0f4e 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1186,6 +1186,7 @@ static BMO_FlagSet bmo_enum_triangulate_quad_method[] = {
{MOD_TRIANGULATE_QUAD_FIXED, "FIXED"},
{MOD_TRIANGULATE_QUAD_ALTERNATE, "ALTERNATE"},
{MOD_TRIANGULATE_QUAD_SHORTEDGE, "SHORT_EDGE"},
+ {MOD_TRIANGULATE_QUAD_LONGEDGE, "LONG_EDGE"},
{0, NULL},
};
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index c60e8af68e5..ef3c2cf8f17 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -185,12 +185,12 @@ BLI_INLINE BMFlagLayer *BMO_elem_flag_from_header(BMHeader *ele_head)
_bmo_elem_flag_set(bm, _BMO_CAST_F(e)->oflags, oflag, val)
#define BMO_face_flag_toggle(bm, e, oflag) _bmo_elem_flag_toggle(bm, _BMO_CAST_F(e)->oflags, oflag)
-BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, const BMFlagLayer *oflags, const short oflag);
-BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, const short oflag);
-BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, const short oflag);
-BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, const short oflag);
-BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short oflag, int val);
-BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, const short oflag);
+BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, const BMFlagLayer *oflags, short oflag);
+BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, short oflag);
+BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, short oflag);
+BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, short oflag);
+BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, short oflag, int val);
+BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, short oflag);
/* slot type arrays are terminated by the last member
* having a slot type of 0 */
@@ -353,7 +353,7 @@ typedef struct BMOpDefine {
*
* Initializes an operator structure to a certain type
*/
-void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname);
+void BMO_op_init(BMesh *bm, BMOperator *op, int flag, const char *opname);
/**
* \brief BMESH OPSTACK EXEC OP
@@ -379,13 +379,13 @@ void BMO_op_finish(BMesh *bm, BMOperator *op);
* 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);
+int BMO_mesh_enabled_flag_count(BMesh *bm, char htype, short oflag);
/**
* 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);
+int BMO_mesh_disabled_flag_count(BMesh *bm, char htype, short oflag);
/**
* \brief BMESH OPSTACK PUSH
@@ -462,20 +462,20 @@ void BMO_pop(BMesh *bm);
* \{ */
/** Executes an operator. */
-bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt, ...);
+bool BMO_op_callf(BMesh *bm, int flag, const char *fmt, ...);
/**
* 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.
*/
-bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, ...);
+bool BMO_op_initf(BMesh *bm, BMOperator *op, int flag, const char *fmt, ...);
/**
* 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);
+bool BMO_op_vinitf(BMesh *bm, BMOperator *op, int flag, const char *fmt, va_list vlist);
/** \} */
@@ -549,20 +549,18 @@ typedef enum {
BMO_DELIM_UV = 1 << 4,
} BMO_Delimit;
-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);
+void BMO_op_flag_enable(BMesh *bm, BMOperator *op, int op_flag);
+void BMO_op_flag_disable(BMesh *bm, BMOperator *op, 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);
+void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float f);
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
-void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int i);
+void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int i);
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);
+void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, 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.
@@ -602,13 +600,13 @@ void BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
/** \} */
-void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, const short oflag);
+void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, char htype, short oflag);
void BMO_mesh_selected_remap(BMesh *bm,
BMOpSlot *slot_vert_map,
BMOpSlot *slot_edge_map,
BMOpSlot *slot_face_map,
- const bool check_select);
+ bool check_select);
/**
* Copies the values from another slot to the end of the output slot.
@@ -633,8 +631,8 @@ void BMO_slot_buffer_from_enabled_flag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const short oflag);
+ char htype,
+ short oflag);
/**
* Puts every element of type 'type' (which is a bit-mask) without tool flag 'flag', into a slot.
@@ -643,8 +641,8 @@ void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const short oflag);
+ char htype,
+ short oflag);
/**
* \brief BMO_FLAG_BUFFER
@@ -654,8 +652,8 @@ void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
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);
+ char htype,
+ short oflag);
/**
* \brief BMO_FLAG_BUFFER
*
@@ -664,8 +662,8 @@ void BMO_slot_buffer_flag_enable(BMesh *bm,
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);
+ char htype,
+ short oflag);
/**
* \brief BMO_FLAG_BUFFER
@@ -676,9 +674,9 @@ void BMO_slot_buffer_flag_disable(BMesh *bm,
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);
+ char htype,
+ char hflag,
+ bool do_flush);
/**
* \brief BMO_FLAG_BUFFER
*
@@ -688,9 +686,9 @@ void BMO_slot_buffer_hflag_enable(BMesh *bm,
void BMO_slot_buffer_hflag_disable(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const char hflag,
- const bool do_flush);
+ char htype,
+ char hflag,
+ bool do_flush);
/**
* Puts every element of type 'type' (which is a bit-mask) with header flag 'flag', into a slot.
@@ -700,8 +698,8 @@ 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);
+ char htype,
+ char hflag);
/**
* 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).
@@ -710,8 +708,8 @@ void BMO_slot_buffer_from_disabled_hflag(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const char hflag);
+ char htype,
+ char hflag);
void BMO_slot_buffer_from_array(BMOperator *op,
BMOpSlot *slot,
@@ -739,13 +737,13 @@ void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, const void *element, co
void BMO_slot_map_to_flag(BMesh *bm,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype,
- const short oflag);
+ char htype,
+ short oflag);
void *BMO_slot_buffer_alloc(BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const int len);
+ int len);
/**
* \brief BMO_ALL_TO_SLOT
@@ -756,7 +754,7 @@ void BMO_slot_buffer_from_all(BMesh *bm,
BMOperator *op,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char htype);
+ char htype);
/**
* This part of the API is used to iterate over element buffer or
@@ -800,7 +798,8 @@ typedef struct BMOIter {
int cur; // for arrays
GHashIterator giter;
void **val;
- char restrictmask; /* bitwise '&' with BMHeader.htype */
+ /** Bit-wise '&' with #BMHeader.htype */
+ char restrictmask;
} BMOIter;
void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
@@ -814,7 +813,7 @@ void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char
void *BMO_iter_new(BMOIter *iter,
BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
const char *slot_name,
- const char restrictmask);
+ char restrictmask);
void *BMO_iter_step(BMOIter *iter);
/**
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index 83f2c402c35..e5ede75f737 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -156,19 +156,19 @@ extern const int bmo_opdefines_total;
/*------specific operator helper functions-------*/
void BM_mesh_esubdivide(BMesh *bm,
- const char edge_hflag,
- const float smooth,
- const short smooth_falloff,
- const bool use_smooth_even,
- const float fractal,
- const float along_normal,
- const int numcuts,
- const int seltype,
- const int cornertype,
- const short use_single_edge,
- const short use_grid_fill,
- const short use_only_quads,
- const int seed);
+ char edge_hflag,
+ float smooth,
+ short smooth_falloff,
+ bool use_smooth_even,
+ float fractal,
+ float along_normal,
+ int numcuts,
+ int seltype,
+ int cornertype,
+ short use_single_edge,
+ short use_grid_fill,
+ short use_only_quads,
+ int seed);
/**
* Fills first available UV-map with grid-like UV's for all faces with `oflag` set.
@@ -178,18 +178,15 @@ void BM_mesh_esubdivide(BMesh *bm,
* \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);
+void BM_mesh_calc_uvs_grid(
+ BMesh *bm, uint x_segments, uint y_segments, short oflag, 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);
+void BM_mesh_calc_uvs_sphere(BMesh *bm, short oflag, int cd_loop_uv_offset);
/**
* Fills first available UV-map with 2D projected UVs for all faces with `oflag` set.
*
@@ -198,11 +195,8 @@ void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag, const int cd_loop_uv_
* \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);
+void BM_mesh_calc_uvs_circle(
+ BMesh *bm, float mat[4][4], float radius, short oflag, int cd_loop_uv_offset);
/**
* Fills first available UV-map with cylinder/cone-like UVs for all faces with `oflag` set.
*
@@ -216,12 +210,12 @@ void BM_mesh_calc_uvs_circle(BMesh *bm,
*/
void BM_mesh_calc_uvs_cone(BMesh *bm,
float mat[4][4],
- const float radius_top,
- const float radius_bottom,
- const int segments,
- const bool cap_ends,
- const short oflag,
- const int cd_loop_uv_offset);
+ float radius_top,
+ float radius_bottom,
+ int segments,
+ bool cap_ends,
+ short oflag,
+ int cd_loop_uv_offset);
/**
* Fills first available UV-map with cube-like UVs for all faces with `oflag` set.
*
@@ -231,6 +225,6 @@ void BM_mesh_calc_uvs_cone(BMesh *bm,
* \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);
+void BM_mesh_calc_uvs_cube(BMesh *bm, 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 e9eaf865e3c..e7280303c26 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -1007,6 +1007,7 @@ void BM_face_triangulate(BMesh *bm,
break;
}
case MOD_TRIANGULATE_QUAD_SHORTEDGE:
+ case MOD_TRIANGULATE_QUAD_LONGEDGE:
case MOD_TRIANGULATE_QUAD_BEAUTY:
default: {
BMLoop *l_v3, *l_v4;
@@ -1023,6 +1024,12 @@ void BM_face_triangulate(BMesh *bm,
d2 = len_squared_v3v3(l_v1->v->co, l_v3->v->co);
split_24 = ((d2 - d1) > 0.0f);
}
+ else if (quad_method == MOD_TRIANGULATE_QUAD_LONGEDGE) {
+ float d1, d2;
+ d1 = len_squared_v3v3(l_v4->v->co, l_v2->v->co);
+ d2 = len_squared_v3v3(l_v1->v->co, l_v3->v->co);
+ split_24 = ((d2 - d1) < 0.0f);
+ }
else {
/* first check if the quad is concave on either diagonal */
const int flip_flag = is_quad_flip_v3(
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index e4545e610a0..2123410c738 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -35,7 +35,7 @@ struct Heap;
* \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,
+ bool use_fixed_quad,
BMLoop **r_loops,
uint (*r_index)[3]);
/**
@@ -164,7 +164,7 @@ void BM_face_normal_update(BMFace *f) ATTR_NONNULL();
*/
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_ex(const BMVert *v, 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)
@@ -180,8 +180,8 @@ void BM_vert_normal_update_all(BMVert *v) ATTR_NONNULL();
*/
void BM_face_normal_flip_ex(BMesh *bm,
BMFace *f,
- const int cd_loop_mdisp_offset,
- const bool use_loop_mdisp_flip) ATTR_NONNULL();
+ int cd_loop_mdisp_offset,
+ bool use_loop_mdisp_flip) ATTR_NONNULL();
void BM_face_normal_flip(BMesh *bm, BMFace *f) ATTR_NONNULL();
/**
* BM POINT IN FACE
@@ -226,9 +226,9 @@ void BM_face_triangulate(BMesh *bm,
BMEdge **r_edges_new,
int *r_edges_new_tot,
struct LinkNode **r_faces_double,
- const int quad_method,
- const int ngon_method,
- const bool use_tag,
+ int quad_method,
+ int ngon_method,
+ bool use_tag,
struct MemArena *pf_arena,
struct Heap *pf_heap) ATTR_NONNULL(1, 2);
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
index a25f38a84b3..626df9fb46a 100644
--- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
@@ -31,7 +31,7 @@
bool BM_face_split_edgenet(BMesh *bm,
BMFace *f,
BMEdge **edge_net,
- const int edge_net_len,
+ int edge_net_len,
BMFace ***r_face_arr,
int *r_face_arr_len);
@@ -46,7 +46,7 @@ bool BM_face_split_edgenet(BMesh *bm,
bool BM_face_split_edgenet_connect_islands(BMesh *bm,
BMFace *f,
BMEdge **edge_net_init,
- const uint edge_net_init_len,
+ uint edge_net_init_len,
bool use_partial_connect,
struct MemArena *mem_arena,
BMEdge ***r_edge_net_new,
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index e7e8b7107e5..4b3c4cbff82 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -27,6 +27,10 @@
* parts of the bmesh internals.
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* returns positive nonzero on error */
#ifdef NDEBUG
@@ -40,7 +44,7 @@
* 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);
+int bmesh_elem_check(void *element, char htype);
# define BM_CHECK_ELEMENT(el) \
{ \
if (bmesh_elem_check(el, ((BMHeader *)el)->htype)) { \
@@ -56,7 +60,7 @@ int bmesh_elem_check(void *element, const char htype);
#endif
int bmesh_radial_length(const BMLoop *l);
-int bmesh_disk_count_at_most(const BMVert *v, const int count_max);
+int bmesh_disk_count_at_most(const BMVert *v, int count_max);
int bmesh_disk_count(const BMVert *v);
/**
@@ -98,7 +102,11 @@ enum {
* 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);
+void poly_rotate_plane(const float normal[3], float (*verts)[3], uint nverts);
/* include the rest of our private declarations */
#include "bmesh_structure.h"
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index 48a1d100c72..841549945ca 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -226,7 +226,7 @@ bool BM_vert_pair_share_face_check_cb(BMVert *v_a,
ATTR_NONNULL(1, 2, 3);
BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
BMVert *v_b,
- const bool allow_adjacent,
+ bool allow_adjacent,
bool (*callback)(BMFace *, BMLoop *, BMLoop *, void *userdata),
void *user_data,
BMLoop **r_l_a,
@@ -234,11 +234,8 @@ BMFace *BM_vert_pair_shared_face_cb(BMVert *v_a,
/**
* 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();
+BMFace *BM_vert_pair_share_face_by_len(
+ BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, 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.
@@ -246,22 +243,16 @@ BMFace *BM_vert_pair_share_face_by_len(BMVert *v_a,
* 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) ATTR_NONNULL();
+BMFace *BM_vert_pair_share_face_by_angle(
+ BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, bool allow_adjacent) ATTR_NONNULL();
-BMFace *BM_edge_pair_share_face_by_len(BMEdge *e_a,
- BMEdge *e_b,
- BMLoop **r_l_a,
- BMLoop **r_l_b,
- const bool allow_adjacent) ATTR_NONNULL();
+BMFace *BM_edge_pair_share_face_by_len(
+ BMEdge *e_a, BMEdge *e_b, BMLoop **r_l_a, BMLoop **r_l_b, bool allow_adjacent) ATTR_NONNULL();
int BM_vert_edge_count_nonwire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#define BM_vert_edge_count_is_equal(v, n) (BM_vert_edge_count_at_most(v, (n) + 1) == n)
#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
+int BM_vert_edge_count_at_most(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/**
* Returns the number of edges around this vertex.
@@ -269,7 +260,7 @@ int BM_vert_edge_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_U
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
+int BM_edge_face_count_at_most(const BMEdge *e, int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/**
* Returns the number of faces around this edge
@@ -346,9 +337,8 @@ 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();
+ int cd_loop_type,
+ int cd_loop_offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* The number of loops connected to this loop (not including disconnected regions).
@@ -383,11 +373,11 @@ float BM_loop_point_side_of_edge_test(const BMLoop *l, const float co[3]) ATTR_W
/**
* \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 *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, 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);
+BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, float eps_sq);
/**
* Calculates the angle between the previous and next loops
@@ -421,7 +411,7 @@ float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NON
* \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])
+float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, float epsilon_sq, float r_normal[3])
ATTR_NONNULL();
/**
* A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
@@ -429,7 +419,7 @@ float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq,
float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
const float normal_fallback[3],
float const (*vertexCos)[3],
- const float epsilon_sq,
+ float epsilon_sq,
float r_normal[3]) ATTR_NONNULL();
float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
const float normal_fallback[3],
@@ -464,7 +454,7 @@ void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);
*
* \return angle in radians
*/
-float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT
+float BM_edge_calc_face_angle_ex(const BMEdge *e, float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
float BM_edge_calc_face_angle(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
@@ -475,8 +465,7 @@ float BM_edge_calc_face_angle(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONN
*
* \return angle in radians
*/
-float BM_edge_calc_face_angle_signed_ex(const BMEdge *e,
- const float fallback) ATTR_WARN_UNUSED_RESULT
+float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/**
* \brief BMESH EDGE/FACE ANGLE
@@ -488,8 +477,7 @@ float BM_edge_calc_face_angle_signed_ex(const BMEdge *e,
*/
float BM_edge_calc_face_angle_with_imat3_ex(const BMEdge *e,
const float imat3[3][3],
- const float fallback) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+ float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
float BM_edge_calc_face_angle_with_imat3(const BMEdge *e,
const float imat3[3][3]) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
@@ -516,7 +504,7 @@ float BM_vert_calc_edge_angle(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONN
*
* \returns the angle in radians
*/
-float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback) ATTR_WARN_UNUSED_RESULT
+float BM_vert_calc_edge_angle_ex(const BMVert *v, float fallback) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/**
* \note this isn't optimal to run on an array of verts,
@@ -527,7 +515,7 @@ float BM_vert_calc_shell_factor(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NO
* 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();
+ char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* \note quite an obscure function.
* used in bmesh operators that have a relative scale options,
@@ -573,7 +561,7 @@ BMFace *BM_face_find_double(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
* 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)
+ * pressing F-key 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.
*/
@@ -595,7 +583,7 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT A
* \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;
+BMFace *BM_face_exists_overlap(BMVert **varr, 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
@@ -604,8 +592,7 @@ BMFace *BM_face_exists_overlap(BMVert **varr, const int len) ATTR_WARN_UNUSED_RE
* \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();
+bool BM_face_exists_overlap_subset(BMVert **varr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Returns the number of faces that are adjacent to both f1 and f2,
@@ -704,27 +691,26 @@ void BM_edge_ordered_verts_ex(const BMEdge *edge,
const BMLoop *edge_loop) ATTR_NONNULL();
bool BM_vert_is_all_edge_flag_test(const BMVert *v,
- const char hflag,
- const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ char hflag,
+ bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_all_face_flag_test(const BMVert *v,
- const char hflag,
- const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ char hflag,
+ bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_edge_is_all_face_flag_test(const BMEdge *e,
- const char hflag,
- const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+ char hflag,
+ 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
+bool BM_edge_is_any_vert_flag_test(const BMEdge *e, 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
+bool BM_edge_is_any_face_flag_test(const BMEdge *e, char hflag) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT
+bool BM_face_is_any_vert_flag_test(const BMFace *f, char hflag) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT
+bool BM_face_is_any_edge_flag_test(const BMFace *f, char hflag) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-bool BM_edge_is_any_face_len_test(const BMEdge *e, const int len) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+bool BM_edge_is_any_face_len_test(const BMEdge *e, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Use within assert's to check normals are valid.
@@ -755,8 +741,8 @@ int BM_mesh_calc_face_groups(BMesh *bm,
BMLoopFilterFunc filter_fn,
BMLoopPairFilterFunc filter_pair_fn,
void *user_data,
- const char hflag_test,
- const char htype_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+ char hflag_test,
+ char htype_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
/**
* Calculate isolated groups of edges with optional filtering.
*
@@ -780,7 +766,7 @@ int BM_mesh_calc_edge_groups(BMesh *bm,
int (**r_group_index)[2],
BMVertFilterFunc filter_fn,
void *user_data,
- const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+ char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
/**
* This is an alternative to #BM_mesh_calc_edge_groups.
@@ -797,6 +783,6 @@ int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm,
ATTR_NONNULL(1, 2, 3, 4, 5);
/* Not really any good place to put this. */
-float bmesh_subd_falloff_calc(const int falloff, float val) ATTR_WARN_UNUSED_RESULT;
+float bmesh_subd_falloff_calc(int falloff, float val) ATTR_WARN_UNUSED_RESULT;
#include "bmesh_query_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_query_uv.h b/source/blender/bmesh/intern/bmesh_query_uv.h
index d63b8e5e701..4399f8b4c4d 100644
--- a/source/blender/bmesh/intern/bmesh_query_uv.h
+++ b/source/blender/bmesh/intern/bmesh_query_uv.h
@@ -21,10 +21,9 @@
*/
float BM_loop_uv_calc_edge_length_squared(const BMLoop *l,
- const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+ int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-float BM_loop_uv_calc_edge_length(const BMLoop *l,
- const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+float BM_loop_uv_calc_edge_length(const BMLoop *l, int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/**
@@ -37,24 +36,24 @@ float BM_loop_uv_calc_edge_length(const BMLoop *l,
*/
void BM_face_uv_calc_center_median_weighted(const BMFace *f,
const float aspect[2],
- const int cd_loop_uv_offset,
+ int cd_loop_uv_offset,
float r_cent[2]) ATTR_NONNULL();
-void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2])
+void BM_face_uv_calc_center_median(const BMFace *f, 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
+float BM_face_uv_calc_cross(const BMFace *f, int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-void BM_face_uv_minmax(const BMFace *f, float min[2], float max[2], const int cd_loop_uv_offset);
-void BM_face_uv_transform(BMFace *f, const float matrix[2][2], const int cd_loop_uv_offset);
+void BM_face_uv_minmax(const BMFace *f, float min[2], float max[2], int cd_loop_uv_offset);
+void BM_face_uv_transform(BMFace *f, const float matrix[2][2], int cd_loop_uv_offset);
bool BM_loop_uv_share_edge_check_with_limit(BMLoop *l_a,
BMLoop *l_b,
const float limit[2],
- const int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
+ int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/**
@@ -62,13 +61,12 @@ bool BM_loop_uv_share_edge_check_with_limit(BMLoop *l_a,
*/
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();
+ 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)
+bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, int cd_loop_uv_offset)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
@@ -76,13 +74,11 @@ bool BM_edge_uv_share_vert_check(BMEdge *e, BMLoop *l_a, BMLoop *l_b, const int
*/
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();
+ 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
- ATTR_NONNULL();
+ int cd_loop_uv_offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
index e2e26a69d44..8a9c1f114f9 100644
--- a/source/blender/bmesh/intern/bmesh_structure.h
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -47,7 +47,7 @@ BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_W
ATTR_NONNULL();
BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT
+int bmesh_disk_facevert_count_at_most(const BMVert *v, int count_max) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
/**
* \brief DISK COUNT FACE VERT
@@ -106,8 +106,7 @@ void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL();
int bmesh_radial_facevert_count_at_most(const BMLoop *l,
const BMVert *v,
- const int count_max) ATTR_WARN_UNUSED_RESULT
- ATTR_NONNULL();
+ int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* \brief RADIAL COUNT FACE VERT
*
diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c
index e1f7430bc53..0e13c4c8128 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.c
+++ b/source/blender/bmesh/intern/bmesh_walkers.c
@@ -33,19 +33,19 @@
/**
* NOTE(@joeedh): Details on design.
*
- * original design: walkers directly emulation recursive functions.
- * functions save their state onto a worklist, and also add new states
- * to implement recursive or looping behavior. generally only one
- * state push per call with a specific state is desired.
+ * Original design: walkers directly emulation recursive functions.
+ * functions save their state onto a #BMWalker.worklist, and also add new states
+ * to implement recursive or looping behavior.
+ * Generally only one state push per call with a specific state is desired.
*
* basic design pattern: the walker step function goes through its
* list of possible choices for recursion, and recurses (by pushing a new state)
- * using the first non-visited one. This choice is the flagged as visited using
- * the ghash. each step may push multiple new states onto the worklist at once.
+ * using the first non-visited one. This choice is the flagged as visited using the #GHash.
+ * Each step may push multiple new states onto the #BMWalker.worklist at once.
*
* - Walkers use tool flags, not header flags.
- * - Walkers now use ghash for storing visited elements,
- * rather than stealing flags. ghash can be rewritten
+ * - Walkers now use #GHash for storing visited elements,
+ * rather than stealing flags. #GHash can be rewritten
* to be faster if necessary, in the far future :) .
* - tools should ALWAYS have necessary error handling
* for if walkers fail.
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
index c337724d096..6bb2830c71b 100644
--- a/source/blender/bmesh/operators/bmo_create.c
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -17,7 +17,7 @@
/** \file
* \ingroup bmesh
*
- * Create faces or edges (Fkey by default).
+ * Create faces or edges (F-key by default).
*/
#include "MEM_guardedalloc.h"
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index 740815691cc..f6cdb18f982 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -30,7 +30,7 @@
# include "RBI_hull_api.h"
-/* XXX: using 128 for totelem and pchunk of mempool, no idea what good
+/* XXX: using 128 for totelem and `pchunk` of `mempool`, no idea what good
* values would be though */
# include "bmesh.h"
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index b7cf9c88282..266b1c0cea8 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -49,8 +49,17 @@
/* GSet for edge rotation */
typedef struct EdRotState {
- int v1, v2; /* edge vert, small -> large */
- int f1, f2; /* face vert, small -> large */
+ /**
+ * Edge vert indices (ordered small -> large).
+ */
+ int v_pair[2];
+ /**
+ * Face vert indices (small -> large).
+ *
+ * Each face-vertex points to a connected triangles vertex
+ * that's isn't part of the edge defined by `v_pair`.
+ */
+ int f_pair[2];
} EdRotState;
#if 0
@@ -58,7 +67,7 @@ typedef struct EdRotState {
static uint erot_gsetutil_hash(const void *ptr)
{
const EdRotState *e_state = (const EdRotState *)ptr;
- return BLI_ghashutil_inthash_v4(&e_state->v1);
+ return BLI_ghashutil_inthash_v4(&e_state->v_pair[0]);
}
#endif
#if 0
@@ -66,33 +75,31 @@ static int erot_gsetutil_cmp(const void *a, const void *b)
{
const EdRotState *e_state_a = (const EdRotState *)a;
const EdRotState *e_state_b = (const EdRotState *)b;
- if (e_state_a->v1 < e_state_b->v1) {
+ if (e_state_a->v_pair[0] < e_state_b->v_pair[0]) {
return -1;
}
- else if (e_state_a->v1 > e_state_b->v1) {
+ if (e_state_a->v_pair[0] > e_state_b->v_pair[0]) {
return 1;
}
- else if (e_state_a->v2 < e_state_b->v2) {
+ if (e_state_a->v_pair[1] < e_state_b->v_pair[1]) {
return -1;
}
- else if (e_state_a->v2 > e_state_b->v2) {
+ if (e_state_a->v_pair[1] > e_state_b->v_pair[1]) {
return 1;
}
- else if (e_state_a->f1 < e_state_b->f1) {
+ if (e_state_a->f_pair[0] < e_state_b->f_pair[0]) {
return -1;
}
- else if (e_state_a->f1 > e_state_b->f1) {
+ if (e_state_a->f_pair[0] > e_state_b->f_pair[0]) {
return 1;
}
- else if (e_state_a->f2 < e_state_b->f2) {
+ if (e_state_a->f_pair[1] < e_state_b->f_pair[1]) {
return -1;
}
- else if (e_state_a->f2 > e_state_b->f2) {
+ if (e_state_a->f_pair[1] > e_state_b->f_pair[1]) {
return 1;
}
- else {
- return 0;
- }
+ return 0;
}
#endif
static GSet *erot_gset_new(void)
@@ -127,12 +134,12 @@ static void erot_state_ex(const BMEdge *e, int v_index[2], int f_index[2])
static void erot_state_current(const BMEdge *e, EdRotState *e_state)
{
- erot_state_ex(e, &e_state->v1, &e_state->f1);
+ erot_state_ex(e, e_state->v_pair, e_state->f_pair);
}
static void erot_state_alternate(const BMEdge *e, EdRotState *e_state)
{
- erot_state_ex(e, &e_state->f1, &e_state->v1);
+ erot_state_ex(e, e_state->f_pair, e_state->v_pair);
}
/* -------------------------------------------------------------------- */
diff --git a/source/blender/bmesh/tools/bmesh_beautify.h b/source/blender/bmesh/tools/bmesh_beautify.h
index 2e7950118c1..a61ae55c3b0 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.h
+++ b/source/blender/bmesh/tools/bmesh_beautify.h
@@ -32,11 +32,11 @@ enum {
*/
void BM_mesh_beautify_fill(BMesh *bm,
BMEdge **edge_array,
- const int edge_array_len,
- const short flag,
- const short method,
- const short oflag_edge,
- const short oflag_face);
+ int edge_array_len,
+ short flag,
+ short method,
+ short oflag_edge,
+ short oflag_face);
/**
* Assuming we have 2 triangles sharing an edge (2 - 4),
@@ -48,5 +48,5 @@ float BM_verts_calc_rotate_beauty(const BMVert *v1,
const BMVert *v2,
const BMVert *v3,
const BMVert *v4,
- const short flag,
- const short method);
+ short flag,
+ short method);
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index 03c10ee9f80..56533e83c39 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -36,25 +36,25 @@ struct MDeformVert;
* \warning all tagged edges _must_ be manifold.
*/
void BM_mesh_bevel(BMesh *bm,
- const float offset,
- const int offset_type,
- const int profile_type,
- const int segments,
- const float profile,
- const bool affect_type,
- const bool use_weights,
- const bool limit_offset,
+ float offset,
+ int offset_type,
+ int profile_type,
+ int segments,
+ float profile,
+ bool affect_type,
+ bool use_weights,
+ bool limit_offset,
const struct MDeformVert *dvert,
- const int vertex_group,
- const int mat,
- const bool loop_slide,
- const bool mark_seam,
- const bool mark_sharp,
- const bool harden_normals,
- const int face_strength_mode,
- const int miter_outer,
- const int miter_inner,
- const float spread,
- const float smoothresh,
+ int vertex_group,
+ int mat,
+ bool loop_slide,
+ bool mark_seam,
+ bool mark_sharp,
+ bool harden_normals,
+ int face_strength_mode,
+ int miter_outer,
+ int miter_inner,
+ float spread,
+ float smoothresh,
const struct CurveProfile *custom_profile,
- const int vmesh_method);
+ int vmesh_method);
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.h b/source/blender/bmesh/tools/bmesh_bisect_plane.h
index 120935296b7..d3c1c6f4c62 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.h
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.h
@@ -27,8 +27,8 @@
*/
void BM_mesh_bisect_plane(BMesh *bm,
const float plane[4],
- const bool use_snap_center,
- const bool use_tag,
- const short oflag_center,
- const short oflag_new,
- const float eps);
+ bool use_snap_center,
+ bool use_tag,
+ short oflag_center,
+ short oflag_new,
+ float eps);
diff --git a/source/blender/bmesh/tools/bmesh_boolean.h b/source/blender/bmesh/tools/bmesh_boolean.h
index 4dacc7b1095..f97f49a7470 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.h
+++ b/source/blender/bmesh/tools/bmesh_boolean.h
@@ -26,14 +26,14 @@ extern "C" {
bool BM_mesh_boolean(BMesh *bm,
struct BMLoop *(*looptris)[3],
- const int looptris_tot,
+ int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data),
void *user_data,
- const int nshapes,
- const bool use_self,
- const bool keep_hidden,
- const bool hole_tolerant,
- const int boolean_mode);
+ int nshapes,
+ bool use_self,
+ bool keep_hidden,
+ bool hole_tolerant,
+ int boolean_mode);
/**
* Perform a Knife Intersection operation on the mesh `bm`.
@@ -47,14 +47,14 @@ bool BM_mesh_boolean(BMesh *bm,
*/
bool BM_mesh_boolean_knife(BMesh *bm,
struct BMLoop *(*looptris)[3],
- const int looptris_tot,
+ int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data),
void *user_data,
- const int nshapes,
- const bool use_self,
- const bool use_separate_all,
- const bool hole_tolerant,
- const bool keep_hidden);
+ int nshapes,
+ bool use_self,
+ bool use_separate_all,
+ bool hole_tolerant,
+ bool keep_hidden);
#ifdef __cplusplus
}
diff --git a/source/blender/bmesh/tools/bmesh_decimate.h b/source/blender/bmesh/tools/bmesh_decimate.h
index 1de241a1326..336b653d462 100644
--- a/source/blender/bmesh/tools/bmesh_decimate.h
+++ b/source/blender/bmesh/tools/bmesh_decimate.h
@@ -35,28 +35,28 @@
* - Face normals are not maintained at all.
*/
void BM_mesh_decimate_collapse(BMesh *bm,
- const float factor,
+ float factor,
float *vweights,
float vweight_factor,
- const bool do_triangulate,
- const int symmetry_axis,
- const float symmetry_eps);
+ bool do_triangulate,
+ int symmetry_axis,
+ 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);
+void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, int iterations, bool tag_only);
+void BM_mesh_decimate_unsubdivide(BMesh *bm, int iterations);
void BM_mesh_decimate_dissolve_ex(BMesh *bm,
- const float angle_limit,
- const bool do_dissolve_boundaries,
+ float angle_limit,
+ bool do_dissolve_boundaries,
BMO_Delimit delimit,
BMVert **vinput_arr,
- const int vinput_len,
+ int vinput_len,
BMEdge **einput_arr,
- const int einput_len,
- const short oflag_out);
+ int einput_len,
+ short oflag_out);
void BM_mesh_decimate_dissolve(BMesh *bm,
- const float angle_limit,
- const bool do_dissolve_boundaries,
+ float angle_limit,
+ bool do_dissolve_boundaries,
const BMO_Delimit delimit);
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index e90e50ef8ff..c653b2b8007 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -847,7 +847,7 @@ BLI_INLINE int bm_edge_is_manifold_or_boundary(BMLoop *l)
/* less optimized version of check below */
return (BM_edge_is_manifold(l->e) || BM_edge_is_boundary(l->e);
#else
- /* if the edge is a boundary it points to its self, else this must be a manifold */
+ /* if the edge is a boundary it points to itself, else this must be a manifold */
return LIKELY(l) && LIKELY(l->radial_next->radial_next == l);
#endif
}
@@ -855,7 +855,7 @@ BLI_INLINE int bm_edge_is_manifold_or_boundary(BMLoop *l)
static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
{
/* simply check that there is no overlap between faces and edges of each vert,
- * (excluding the 2 faces attached to 'e' and 'e' its self) */
+ * (excluding the 2 faces attached to 'e' and 'e' itself) */
BMEdge *e_iter;
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.h b/source/blender/bmesh/tools/bmesh_edgenet.h
index 20edb30442c..60e9d9acff1 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.h
+++ b/source/blender/bmesh/tools/bmesh_edgenet.h
@@ -29,4 +29,4 @@
* \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);
+void BM_mesh_edgenet(BMesh *bm, bool use_edge_tag, bool use_new_face_tag);
diff --git a/source/blender/bmesh/tools/bmesh_edgesplit.h b/source/blender/bmesh/tools/bmesh_edgesplit.h
index bcbb3ab7857..dd835ba335c 100644
--- a/source/blender/bmesh/tools/bmesh_edgesplit.h
+++ b/source/blender/bmesh/tools/bmesh_edgesplit.h
@@ -29,10 +29,7 @@ extern "C" {
* \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,
- const bool copy_select);
+void BM_mesh_edgesplit(BMesh *bm, bool use_verts, bool tag_only, bool copy_select);
#ifdef __cplusplus
}
diff --git a/source/blender/bmesh/tools/bmesh_intersect.h b/source/blender/bmesh/tools/bmesh_intersect.h
index a6c91715f31..4fc6460a35f 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.h
+++ b/source/blender/bmesh/tools/bmesh_intersect.h
@@ -34,17 +34,17 @@ extern "C" {
*/
bool BM_mesh_intersect(BMesh *bm,
struct BMLoop *(*looptris)[3],
- const int looptris_tot,
+ int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data),
void *user_data,
- const bool use_self,
- const bool use_separate,
- const bool use_dissolve,
- const bool use_island_connect,
- const bool use_partial_connect,
- const bool use_edge_tag,
- const int boolean_mode,
- const float eps);
+ bool use_self,
+ bool use_separate,
+ bool use_dissolve,
+ bool use_island_connect,
+ bool use_partial_connect,
+ bool use_edge_tag,
+ int boolean_mode,
+ float eps);
enum {
BMESH_ISECT_BOOLEAN_NONE = -1,
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.h b/source/blender/bmesh/tools/bmesh_intersect_edges.h
index 2736b7a52f9..cd7293c4a0b 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.h
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.h
@@ -21,4 +21,4 @@
#pragma once
bool BM_mesh_intersect_edges(
- BMesh *bm, const char hflag, const float dist, const bool split_faces, GHash *r_targetmap);
+ BMesh *bm, char hflag, float dist, bool split_faces, GHash *r_targetmap);
diff --git a/source/blender/bmesh/tools/bmesh_path_region_uv.h b/source/blender/bmesh/tools/bmesh_path_region_uv.h
index 5767c5384e5..2f29ef2a36e 100644
--- a/source/blender/bmesh/tools/bmesh_path_region_uv.h
+++ b/source/blender/bmesh/tools/bmesh_path_region_uv.h
@@ -23,7 +23,7 @@
struct LinkNode *BM_mesh_calc_path_uv_region_vert(BMesh *bm,
BMElem *ele_src,
BMElem *ele_dst,
- const uint cd_loop_uv_offset,
+ uint cd_loop_uv_offset,
bool (*filter_fn)(BMLoop *, void *user_data),
void *user_data) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3);
@@ -31,7 +31,7 @@ struct LinkNode *BM_mesh_calc_path_uv_region_vert(BMesh *bm,
struct LinkNode *BM_mesh_calc_path_uv_region_edge(BMesh *bm,
BMElem *ele_src,
BMElem *ele_dst,
- const uint cd_loop_uv_offset,
+ uint cd_loop_uv_offset,
bool (*filter_fn)(BMLoop *, void *user_data),
void *user_data) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3);
@@ -39,7 +39,7 @@ struct LinkNode *BM_mesh_calc_path_uv_region_edge(BMesh *bm,
struct LinkNode *BM_mesh_calc_path_uv_region_face(BMesh *bm,
BMElem *ele_src,
BMElem *ele_dst,
- const uint cd_loop_uv_offset,
+ uint cd_loop_uv_offset,
bool (*filter_fn)(BMFace *, void *user_data),
void *user_data) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2, 3);
diff --git a/source/blender/bmesh/tools/bmesh_triangulate.h b/source/blender/bmesh/tools/bmesh_triangulate.h
index f45f94f15d8..0d78b6a74b4 100644
--- a/source/blender/bmesh/tools/bmesh_triangulate.h
+++ b/source/blender/bmesh/tools/bmesh_triangulate.h
@@ -23,10 +23,10 @@
#pragma once
void BM_mesh_triangulate(BMesh *bm,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const bool tag_only,
+ int quad_method,
+ int ngon_method,
+ int min_vertices,
+ bool tag_only,
BMOperator *op,
BMOpSlot *slot_facemap_out,
BMOpSlot *slot_facemap_double_out);
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.h b/source/blender/bmesh/tools/bmesh_wireframe.h
index 5b64a16435f..8e523780a67 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.h
+++ b/source/blender/bmesh/tools/bmesh_wireframe.h
@@ -29,17 +29,17 @@
* \note Behavior matches MOD_solidify.c
*/
void BM_mesh_wireframe(BMesh *bm,
- const float offset,
- const float offset_fac,
- const float offset_fac_vg,
- const bool use_replace,
- const bool use_boundary,
- const bool use_even_offset,
- const bool use_relative_offset,
- const bool use_crease,
- const float crease_weight,
- const int defgrp_index,
- const bool defgrp_invert,
- const short mat_offset,
- const short mat_max,
- const bool use_tag);
+ float offset,
+ float offset_fac,
+ float offset_fac_vg,
+ bool use_replace,
+ bool use_boundary,
+ bool use_even_offset,
+ bool use_relative_offset,
+ bool use_crease,
+ float crease_weight,
+ int defgrp_index,
+ bool defgrp_invert,
+ short mat_offset,
+ short mat_max,
+ bool use_tag);
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 10e385e0187..b9b365a3175 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -38,7 +38,11 @@ set(INC
../render/intern
../../../extern/clew/include
../../../intern/atomic
+ ../../../intern/clog
../../../intern/guardedalloc
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern
)
set(INC_SYS
@@ -136,6 +140,8 @@ set(SRC
nodes/COM_OutputFileNode.h
nodes/COM_RenderLayersNode.cc
nodes/COM_RenderLayersNode.h
+ nodes/COM_SceneTimeNode.cc
+ nodes/COM_SceneTimeNode.h
nodes/COM_SwitchNode.cc
nodes/COM_SwitchNode.h
nodes/COM_SwitchViewNode.cc
@@ -242,6 +248,8 @@ set(SRC
nodes/COM_ColorToBWNode.h
nodes/COM_ConvertAlphaNode.cc
nodes/COM_ConvertAlphaNode.h
+ nodes/COM_ConvertColorSpaceNode.cc
+ nodes/COM_ConvertColorSpaceNode.h
nodes/COM_GammaNode.cc
nodes/COM_GammaNode.h
nodes/COM_HueSaturationValueCorrectNode.cc
@@ -565,6 +573,8 @@ set(SRC
operations/COM_IDMaskOperation.cc
operations/COM_IDMaskOperation.h
+ operations/COM_ConvertColorSpaceOperation.cc
+ operations/COM_ConvertColorSpaceOperation.h
operations/COM_DotproductOperation.cc
operations/COM_DotproductOperation.h
@@ -640,6 +650,15 @@ endif()
blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_compositor PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_compositor PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
+
+if(COMMAND target_precompile_headers)
+ target_precompile_headers(bf_compositor PRIVATE COM_precomp.h)
+endif()
+
if(CXX_WARN_NO_SUGGEST_OVERRIDE)
target_compile_options(bf_compositor PRIVATE "-Wsuggest-override")
endif()
@@ -661,3 +680,6 @@ if(WITH_GTESTS)
include(GTestTesting)
blender_add_test_lib(bf_compositor_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
endif()
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_compositor bf_dna)
diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h
index 1c3a28670df..794bf1b23bc 100644
--- a/source/blender/compositor/COM_defines.h
+++ b/source/blender/compositor/COM_defines.h
@@ -18,7 +18,7 @@
#pragma once
-#include "BLI_float2.hh"
+#include "BLI_math_vec_types.hh"
#include "DNA_vec_types.h"
diff --git a/source/blender/compositor/COM_precomp.h b/source/blender/compositor/COM_precomp.h
new file mode 100644
index 00000000000..4d2681ea0cd
--- /dev/null
+++ b/source/blender/compositor/COM_precomp.h
@@ -0,0 +1,33 @@
+/* Pre-compiled headers, see: D13797. */
+
+#include <cfloat>
+#include <climits>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <iostream>
+#include <iterator>
+#include <list>
+#include <map>
+#include <ostream>
+#include <set>
+#include <string>
+
+#include "COM_ConstantOperation.h"
+#include "COM_ConvertOperation.h"
+#include "COM_Debug.h"
+#include "COM_Enums.h"
+#include "COM_ExecutionGroup.h"
+#include "COM_ExecutionSystem.h"
+#include "COM_MultiThreadedOperation.h"
+#include "COM_Node.h"
+#include "COM_NodeOperation.h"
+#include "COM_OpenCLDevice.h"
+#include "COM_SetAlphaMultiplyOperation.h"
+#include "COM_SetColorOperation.h"
+#include "COM_SetSamplerOperation.h"
+#include "COM_SetValueOperation.h"
+#include "COM_SetVectorOperation.h"
+#include "COM_defines.h"
diff --git a/source/blender/compositor/intern/COM_ConstantFolder.cc b/source/blender/compositor/intern/COM_ConstantFolder.cc
index ca5fd9e8274..f10bee38a6e 100644
--- a/source/blender/compositor/intern/COM_ConstantFolder.cc
+++ b/source/blender/compositor/intern/COM_ConstantFolder.cc
@@ -28,8 +28,6 @@
namespace blender::compositor {
-using Link = NodeOperationBuilder::Link;
-
ConstantFolder::ConstantFolder(NodeOperationBuilder &operations_builder)
: operations_builder_(operations_builder)
{
@@ -178,8 +176,8 @@ void ConstantFolder::delete_constant_buffers()
void ConstantFolder::get_operation_output_operations(NodeOperation *operation,
Vector<NodeOperation *> &r_outputs)
{
- const Vector<Link> &links = operations_builder_.get_links();
- for (const Link &link : links) {
+ const Vector<NodeOperationBuilder::Link> &links = operations_builder_.get_links();
+ for (const NodeOperationBuilder::Link &link : links) {
if (&link.from()->get_operation() == operation) {
r_outputs.append(&link.to()->get_operation());
}
diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc
index 0af4ff7d98d..6cf6c698a2f 100644
--- a/source/blender/compositor/intern/COM_Converter.cc
+++ b/source/blender/compositor/intern/COM_Converter.cc
@@ -46,6 +46,7 @@
#include "COM_CombineColorNode.h"
#include "COM_CompositorNode.h"
#include "COM_ConvertAlphaNode.h"
+#include "COM_ConvertColorSpaceNode.h"
#include "COM_ConvertOperation.h"
#include "COM_Converter.h"
#include "COM_CornerPinNode.h"
@@ -93,6 +94,7 @@
#include "COM_RotateNode.h"
#include "COM_ScaleNode.h"
#include "COM_ScaleOperation.h"
+#include "COM_SceneTimeNode.h"
#include "COM_SeparateColorNode.h"
#include "COM_SetAlphaNode.h"
#include "COM_SetValueOperation.h"
@@ -359,6 +361,9 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_TRANSFORM:
node = new TransformNode(b_node);
break;
+ case CMP_NODE_SCENE_TIME:
+ node = new SceneTimeNode(b_node);
+ break;
case CMP_NODE_STABILIZE2D:
node = new Stabilize2dNode(b_node);
break;
@@ -426,6 +431,9 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_POSTERIZE:
node = new PosterizeNode(b_node);
break;
+ case CMP_NODE_CONVERT_COLOR_SPACE:
+ node = new ConvertColorSpaceNode(b_node);
+ break;
}
return node;
}
diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc
index 50a69e55b2b..8525e2fde50 100644
--- a/source/blender/compositor/intern/COM_Debug.cc
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -431,8 +431,9 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name)
if (!COM_EXPORT_GRAPHVIZ) {
return;
}
- char str[1000000];
- if (graphviz_system(system, str, sizeof(str) - 1)) {
+ const int max_textlength = 1000000;
+ char *str = (char *)MEM_mallocN(max_textlength, __func__);
+ if (graphviz_system(system, str, max_textlength - 1)) {
char basename[FILE_MAX];
char filename[FILE_MAX];
@@ -451,6 +452,7 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name)
fputs(str, fp);
fclose(fp);
}
+ MEM_freeN(str);
}
static std::string get_operations_export_dir()
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h
index 430cde89a3b..d37bfe29306 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.h
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.h
@@ -175,9 +175,7 @@ class ExecutionGroup {
/**
* \brief Determine the rect (minx, maxx, miny, maxy) of a chunk at a position.
*/
- void determine_chunk_rect(rcti *r_rect,
- const unsigned int x_chunk,
- const unsigned int y_chunk) const;
+ void determine_chunk_rect(rcti *r_rect, unsigned int x_chunk, unsigned int y_chunk) const;
/**
* \brief determine the number of chunks, based on the chunk_size, width and height.
@@ -197,7 +195,7 @@ class ExecutionGroup {
* true: package(s) are scheduled
* false: scheduling is deferred (depending workpackages are scheduled)
*/
- bool schedule_chunk_when_possible(ExecutionSystem *graph, const int chunk_x, const int chunk_y);
+ bool schedule_chunk_when_possible(ExecutionSystem *graph, int chunk_x, int chunk_y);
/**
* \brief try to schedule a specific area.
@@ -374,7 +372,7 @@ class ExecutionGroup {
/**
* \brief Determine the rect (minx, maxx, miny, maxy) of a chunk.
*/
- void determine_chunk_rect(rcti *r_rect, const unsigned int chunk_number) const;
+ void determine_chunk_rect(rcti *r_rect, unsigned int chunk_number) const;
void set_chunksize(int chunksize)
{
diff --git a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
index ce724a6b934..6d3a5fba53a 100644
--- a/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
+++ b/source/blender/compositor/intern/COM_FullFrameExecutionModel.h
@@ -75,10 +75,8 @@ class FullFrameExecutionModel : public ExecutionModel {
* 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);
- MemoryBuffer *create_operation_buffer(NodeOperation *op, const int output_x, const int output_y);
+ Vector<MemoryBuffer *> get_input_buffers(NodeOperation *op, int output_x, int output_y);
+ MemoryBuffer *create_operation_buffer(NodeOperation *op, int output_x, int output_y);
void render_operation(NodeOperation *op);
void operation_finished(NodeOperation *operation);
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc
index ae925f796ee..dcc279e3b88 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cc
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc
@@ -289,6 +289,23 @@ void MemoryBuffer::copy_from(const uchar *src,
}
}
+void MemoryBuffer::apply_processor(ColormanageProcessor &processor, const rcti area)
+{
+ const int width = BLI_rcti_size_x(&area);
+ const int height = BLI_rcti_size_y(&area);
+ float *out = get_elem(area.xmin, area.ymin);
+ /* If area allows continuous memory do conversion in one step. Otherwise per row. */
+ if (get_width() == width) {
+ IMB_colormanagement_processor_apply(&processor, out, width, height, get_num_channels(), false);
+ }
+ else {
+ for (int y = 0; y < height; y++) {
+ IMB_colormanagement_processor_apply(&processor, out, width, 1, get_num_channels(), false);
+ out += row_stride;
+ }
+ }
+}
+
static void colorspace_to_scene_linear(MemoryBuffer *buf, const rcti &area, ColorSpace *colorspace)
{
const int width = BLI_rcti_size_x(&area);
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index 1af047e9ce1..1765fb93035 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -26,6 +26,8 @@
#include "BLI_math_interp.h"
#include "BLI_rect.h"
+#include "IMB_colormanagement.h"
+
struct ImBuf;
namespace blender::compositor {
@@ -286,8 +288,7 @@ class MemoryBuffer {
}
}
- void read_elem_filtered(
- const float x, const float y, float dx[2], float dy[2], float *out) const;
+ void read_elem_filtered(float x, float y, float dx[2], float dy[2], float *out) const;
/**
* Get channel value at given coordinates.
@@ -579,6 +580,11 @@ class MemoryBuffer {
return state_ == MemoryBufferState::Temporary;
}
+ /**
+ * \brief Apply a color processor on the given area.
+ */
+ void apply_processor(ColormanageProcessor &processor, const rcti area);
+
void copy_from(const MemoryBuffer *src, const rcti &area);
void copy_from(const MemoryBuffer *src, const rcti &area, int to_x, int to_y);
void copy_from(const MemoryBuffer *src,
@@ -722,18 +728,15 @@ class MemoryBuffer {
void copy_single_elem_from(const MemoryBuffer *src,
int channel_offset,
int elem_size,
- const int to_channel_offset);
- void copy_rows_from(const MemoryBuffer *src,
- const rcti &src_area,
- const int to_x,
- const int to_y);
+ int to_channel_offset);
+ void copy_rows_from(const MemoryBuffer *src, const rcti &src_area, int to_x, int to_y);
void copy_elems_from(const MemoryBuffer *src,
const rcti &area,
- const int channel_offset,
- const int elem_size,
- const int to_x,
- const int to_y,
- const int to_channel_offset);
+ int channel_offset,
+ int elem_size,
+ int to_x,
+ int to_y,
+ int to_channel_offset);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:MemoryBuffer")
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_Node.h b/source/blender/compositor/intern/COM_Node.h
index dd126770303..37fa71f9b97 100644
--- a/source/blender/compositor/intern/COM_Node.h
+++ b/source/blender/compositor/intern/COM_Node.h
@@ -129,13 +129,13 @@ class Node {
* Get the reference to a certain output-socket.
* \param index: The index of the needed output-socket.
*/
- NodeOutput *get_output_socket(const unsigned int index = 0) const;
+ NodeOutput *get_output_socket(unsigned int index = 0) const;
/**
* get the reference to a certain input-socket.
* \param index: The index of the needed input-socket.
*/
- NodeInput *get_input_socket(const unsigned int index) const;
+ NodeInput *get_input_socket(unsigned int index) const;
/**
* \brief Is this node in the active group (the group that is being edited)
diff --git a/source/blender/compositor/intern/COM_compositor.cc b/source/blender/compositor/intern/COM_compositor.cc
index be70ae792cb..5c9b34c4772 100644
--- a/source/blender/compositor/intern/COM_compositor.cc
+++ b/source/blender/compositor/intern/COM_compositor.cc
@@ -51,7 +51,7 @@ static void compositor_init_node_previews(const RenderData *render_data, bNodeTr
preview_width = (int)(blender::compositor::COM_PREVIEW_SIZE / aspect);
preview_height = blender::compositor::COM_PREVIEW_SIZE;
}
- BKE_node_preview_init_tree(node_tree, preview_width, preview_height, false);
+ BKE_node_preview_init_tree(node_tree, preview_width, preview_height);
}
static void compositor_reset_node_tree_status(bNodeTree *node_tree)
diff --git a/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.cc b/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.cc
new file mode 100644
index 00000000000..4e7bbefc22d
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.cc
@@ -0,0 +1,100 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_ConvertColorSpaceNode.h"
+
+#include "BKE_node.h"
+
+#include "BLI_utildefines.h"
+
+#include "COM_ConvertColorSpaceOperation.h"
+#include "COM_ConvertOperation.h"
+#include "COM_ExecutionSystem.h"
+#include "COM_ImageOperation.h"
+#include "COM_MultilayerImageOperation.h"
+
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"compositor"};
+
+namespace blender::compositor {
+
+ConvertColorSpaceNode::ConvertColorSpaceNode(bNode *editorNode) : Node(editorNode)
+{
+ /* pass */
+}
+
+void ConvertColorSpaceNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &UNUSED(context)) const
+{
+ bNode *b_node = get_bnode();
+
+ NodeInput *inputSocketImage = this->get_input_socket(0);
+ NodeOutput *outputSocketImage = this->get_output_socket(0);
+
+ NodeConvertColorSpace *settings = static_cast<NodeConvertColorSpace *>(b_node->storage);
+
+ if (!performs_conversion(*settings)) {
+ converter.map_output_socket(get_output_socket(0),
+ converter.add_input_proxy(get_input_socket(0), false));
+ return;
+ }
+
+ ConvertColorSpaceOperation *operation = new ConvertColorSpaceOperation();
+ operation->set_settings((NodeConvertColorSpace *)b_node->storage);
+ converter.add_operation(operation);
+
+ converter.map_input_socket(inputSocketImage, operation->get_input_socket(0));
+ converter.map_output_socket(outputSocketImage, operation->get_output_socket());
+}
+
+bool ConvertColorSpaceNode::performs_conversion(NodeConvertColorSpace &settings) const
+{
+ bNode *b_node = get_bnode();
+
+ if (IMB_colormanagement_space_name_is_data(settings.from_color_space)) {
+ CLOG_INFO(&LOG,
+ 2,
+ "Color space conversion bypassed for node: %s. From color space is data: %s.",
+ b_node->name,
+ settings.from_color_space);
+ return false;
+ }
+
+ if (IMB_colormanagement_space_name_is_data(settings.to_color_space)) {
+ CLOG_INFO(&LOG,
+ 2,
+ "Color space conversion bypassed for node: %s. To color space is data: %s.",
+ b_node->name,
+ settings.to_color_space);
+ return false;
+ }
+
+ if (STREQLEN(
+ settings.from_color_space, settings.to_color_space, sizeof(settings.from_color_space))) {
+ CLOG_INFO(&LOG,
+ 2,
+ "Color space conversion bypassed for node: %s. To and from are the same: %s.",
+ b_node->name,
+ settings.from_color_space);
+ return false;
+ }
+ return true;
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.h b/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.h
new file mode 100644
index 00000000000..b3460abea27
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_ConvertColorSpaceNode.h
@@ -0,0 +1,46 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_Node.h"
+#include "COM_defines.h"
+#include "DNA_image_types.h"
+#include "DNA_node_types.h"
+
+#include "RE_engine.h"
+#include "RE_pipeline.h"
+
+namespace blender::compositor {
+
+/**
+ * \brief ImageNode
+ * \ingroup Node
+ */
+class ConvertColorSpaceNode : public Node {
+ public:
+ ConvertColorSpaceNode(bNode *editorNode);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
+
+ private:
+ /** \brief check if the given settings changes color space. */
+ bool performs_conversion(NodeConvertColorSpace &settings) const;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
index 605dc1dc84d..c360e519cf8 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.cc
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
@@ -16,9 +16,12 @@
* Copyright 2018, Blender Foundation.
*/
-#include "COM_CryptomatteNode.h"
#include "BKE_node.h"
+
+#include "NOD_composite.h"
+
#include "COM_ConvertOperation.h"
+#include "COM_CryptomatteNode.h"
#include "COM_MultilayerImageOperation.h"
#include "COM_RenderLayersProg.h"
#include "COM_SetAlphaMultiplyOperation.h"
diff --git a/source/blender/compositor/nodes/COM_SceneTimeNode.cc b/source/blender/compositor/nodes/COM_SceneTimeNode.cc
new file mode 100644
index 00000000000..533f30918ca
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SceneTimeNode.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.
+ *
+ * Copyright 2022, Blender Foundation.
+ */
+
+#include "COM_SceneTimeNode.h"
+
+#include "COM_SetValueOperation.h"
+
+namespace blender::compositor {
+
+SceneTimeNode::SceneTimeNode(bNode *editor_node) : Node(editor_node)
+{
+ /* pass */
+}
+
+void SceneTimeNode::convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const
+{
+ SetValueOperation *SecondOperation = new SetValueOperation();
+ SetValueOperation *frameOperation = new SetValueOperation();
+
+ const int frameNumber = context.get_framenumber();
+ const Scene *scene = context.get_scene();
+ const double frameRate = (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base);
+
+ SecondOperation->set_value(float(frameNumber / frameRate));
+ converter.add_operation(SecondOperation);
+
+ frameOperation->set_value(frameNumber);
+ converter.add_operation(frameOperation);
+
+ converter.map_output_socket(get_output_socket(0), SecondOperation->get_output_socket());
+ converter.map_output_socket(get_output_socket(1), frameOperation->get_output_socket());
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/nodes/COM_SceneTimeNode.h b/source/blender/compositor/nodes/COM_SceneTimeNode.h
new file mode 100644
index 00000000000..62c502d26d2
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SceneTimeNode.h
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2022, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_Node.h"
+
+namespace blender::compositor {
+
+/**
+ * \brief SceneTimeNode
+ * \ingroup Node
+ */
+class SceneTimeNode : public Node {
+ public:
+ SceneTimeNode(bNode *editor_node);
+ void convert_to_operations(NodeConverter &converter,
+ const CompositorContext &context) const override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.cc b/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.cc
new file mode 100644
index 00000000000..5b1dfb4a02c
--- /dev/null
+++ b/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.cc
@@ -0,0 +1,91 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "COM_ConvertColorSpaceOperation.h"
+
+namespace blender::compositor {
+
+ConvertColorSpaceOperation::ConvertColorSpaceOperation()
+{
+ this->add_input_socket(DataType::Color);
+ this->add_output_socket(DataType::Color);
+ this->input_program_ = nullptr;
+ color_processor_ = nullptr;
+}
+
+void ConvertColorSpaceOperation::set_settings(NodeConvertColorSpace *node_color_space)
+{
+ this->settings_ = node_color_space;
+}
+
+void ConvertColorSpaceOperation::init_execution()
+{
+ if (BLI_strnlen(settings_->from_color_space, sizeof(settings_->from_color_space)) == 0 ||
+ BLI_strnlen(settings_->to_color_space, sizeof(settings_->to_color_space)) == 0) {
+ return;
+ }
+
+ int in_colorspace_index = IMB_colormanagement_colorspace_get_named_index(
+ settings_->from_color_space);
+ int out_colorspace_index = IMB_colormanagement_colorspace_get_named_index(
+ settings_->to_color_space);
+
+ if (in_colorspace_index == 0 || out_colorspace_index == 0) {
+ return;
+ }
+
+ this->input_program_ = this->get_input_socket_reader(0);
+
+ color_processor_ = IMB_colormanagement_colorspace_processor_new(settings_->from_color_space,
+ settings_->to_color_space);
+}
+
+void ConvertColorSpaceOperation::execute_pixel_sampled(float output[4],
+ float x,
+ float y,
+ PixelSampler sampler)
+{
+ this->input_program_->read_sampled(output, x, y, sampler);
+ if (color_processor_ != nullptr) {
+ IMB_colormanagement_processor_apply_pixel(color_processor_, output, 3);
+ }
+}
+
+void ConvertColorSpaceOperation::update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs)
+{
+ for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
+ copy_v4_v4(it.out, it.in(0));
+ }
+
+ if (color_processor_ != nullptr) {
+ output->apply_processor(*color_processor_, area);
+ }
+}
+
+void ConvertColorSpaceOperation::deinit_execution()
+{
+ if (color_processor_ != nullptr) {
+ IMB_colormanagement_processor_free(color_processor_);
+ }
+ this->input_program_ = nullptr;
+ this->color_processor_ = nullptr;
+}
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.h b/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.h
new file mode 100644
index 00000000000..c065224eadc
--- /dev/null
+++ b/source/blender/compositor/operations/COM_ConvertColorSpaceOperation.h
@@ -0,0 +1,57 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#include "COM_ConvertColorSpaceNode.h"
+#include "COM_MultiThreadedOperation.h"
+#include "IMB_colormanagement.h"
+
+namespace blender::compositor {
+
+class ConvertColorSpaceOperation : public MultiThreadedOperation {
+ private:
+ SocketReader *input_program_;
+ NodeConvertColorSpace *settings_;
+ ColormanageProcessor *color_processor_;
+
+ public:
+ ConvertColorSpaceOperation();
+
+ void set_settings(NodeConvertColorSpace *node_color_space);
+ /**
+ * The inner loop of this operation.
+ */
+ void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override;
+
+ /**
+ * Initialize the execution
+ */
+ void init_execution() override;
+
+ /**
+ * Deinitialize the execution
+ */
+ void deinit_execution() override;
+
+ void update_memory_buffer_partial(MemoryBuffer *output,
+ const rcti &area,
+ Span<MemoryBuffer *> inputs) override;
+};
+
+} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_CropOperation.cc b/source/blender/compositor/operations/COM_CropOperation.cc
index 5d78ed9d41a..2385a0b54ba 100644
--- a/source/blender/compositor/operations/COM_CropOperation.cc
+++ b/source/blender/compositor/operations/COM_CropOperation.cc
@@ -42,22 +42,22 @@ void CropBaseOperation::update_area()
local_settings.y1 = height * local_settings.fac_y1;
local_settings.y2 = height * local_settings.fac_y2;
}
- if (width <= local_settings.x1 + 1) {
- local_settings.x1 = width - 1;
+ if (width < local_settings.x1) {
+ local_settings.x1 = width;
}
- if (height <= local_settings.y1 + 1) {
- local_settings.y1 = height - 1;
+ if (height < local_settings.y1) {
+ local_settings.y1 = height;
}
- if (width <= local_settings.x2 + 1) {
- local_settings.x2 = width - 1;
+ if (width < local_settings.x2) {
+ local_settings.x2 = width;
}
- if (height <= local_settings.y2 + 1) {
- local_settings.y2 = height - 1;
+ if (height < local_settings.y2) {
+ local_settings.y2 = height;
}
- xmax_ = MAX2(local_settings.x1, local_settings.x2) + 1;
+ xmax_ = MAX2(local_settings.x1, local_settings.x2);
xmin_ = MIN2(local_settings.x1, local_settings.x2);
- ymax_ = MAX2(local_settings.y1, local_settings.y2) + 1;
+ ymax_ = MAX2(local_settings.y1, local_settings.y2);
ymin_ = MIN2(local_settings.y1, local_settings.y2);
}
else {
@@ -98,10 +98,8 @@ void CropOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- rcti crop_area;
- BLI_rcti_init(&crop_area, xmin_, xmax_, ymin_, ymax_);
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
- if (BLI_rcti_isect_pt(&crop_area, it.x, it.y)) {
+ if ((it.x < xmax_ && it.x >= xmin_) && (it.y < ymax_ && it.y >= ymin_)) {
copy_v4_v4(it.out, it.in(0));
}
else {
@@ -166,11 +164,11 @@ void CropImageOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- rcti op_area;
- BLI_rcti_init(&op_area, 0, get_width(), 0, get_height());
const MemoryBuffer *input = inputs[0];
+ const int width = get_width();
+ const int height = get_height();
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
- if (BLI_rcti_isect_pt(&op_area, it.x, it.y)) {
+ if (it.x >= 0 && it.x < width && it.y >= 0 && it.y < height) {
input->read_elem_checked(it.x + xmin_, it.y + ymin_, it.out);
}
else {
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc
index 1a8c000cdd8..cfd83102aaf 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc
+++ b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc
@@ -85,11 +85,6 @@ void GaussianAlphaBlurBaseOperation::get_area_of_interest(const int input_idx,
}
}
-BLI_INLINE float finv_test(const float f, const bool test)
-{
- return (LIKELY(test == false)) ? f : 1.0f - f;
-}
-
void GaussianAlphaBlurBaseOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h
index 0f83a67cef7..2bab6912d34 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.h
@@ -39,9 +39,7 @@ class GaussianAlphaBlurBaseOperation : public BlurBaseOperation {
virtual void init_execution() override;
virtual void deinit_execution() override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) final;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) final;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) final;
@@ -57,6 +55,11 @@ class GaussianAlphaBlurBaseOperation : public BlurBaseOperation {
{
falloff_ = falloff;
}
+
+ BLI_INLINE float finv_test(const float f, const bool test)
+ {
+ return (LIKELY(test == false)) ? f : 1.0f - f;
+ }
};
} // namespace blender::compositor
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc
index de0010fcb58..3836cf45371 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc
@@ -71,11 +71,6 @@ void GaussianAlphaXBlurOperation::update_gauss()
}
}
-BLI_INLINE float finv_test(const float f, const bool test)
-{
- return (LIKELY(test == false)) ? f : 1.0f - f;
-}
-
void GaussianAlphaXBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
const bool do_invert = do_subtract_;
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc
index 90a80e6779a..d71d90e7fa4 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc
@@ -73,11 +73,6 @@ void GaussianAlphaYBlurOperation::update_gauss()
}
}
-BLI_INLINE float finv_test(const float f, const bool test)
-{
- return (LIKELY(test == false)) ? f : 1.0f - f;
-}
-
void GaussianAlphaYBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
{
const bool do_invert = do_subtract_;
diff --git a/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h b/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h
index 31b045241f8..55099c2d9be 100644
--- a/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianBlurBaseOperation.h
@@ -39,9 +39,7 @@ class GaussianBlurBaseOperation : public BlurBaseOperation {
virtual void init_execution() override;
virtual void deinit_execution() override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
virtual void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h
index 923daf7a447..06d7d85894c 100644
--- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.h
@@ -51,9 +51,7 @@ class GaussianBokehBlurOperation : public BlurBaseOperation {
ReadBufferOperation *read_operation,
rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
@@ -88,9 +86,7 @@ class GaussianBlurReferenceOperation : public BlurBaseOperation {
ReadBufferOperation *read_operation,
rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.h b/source/blender/compositor/operations/COM_GlareBaseOperation.h
index 09db5efcec9..c29587839b1 100644
--- a/source/blender/compositor/operations/COM_GlareBaseOperation.h
+++ b/source/blender/compositor/operations/COM_GlareBaseOperation.h
@@ -70,9 +70,7 @@ class GlareBaseOperation : public SingleThreadedOperation {
ReadBufferOperation *read_operation,
rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) final;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) final;
void update_memory_buffer(MemoryBuffer *output,
const rcti &area,
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.h b/source/blender/compositor/operations/COM_InpaintOperation.h
index 989d154dab5..0e52aa82b92 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.h
+++ b/source/blender/compositor/operations/COM_InpaintOperation.h
@@ -67,9 +67,7 @@ class InpaintSimpleOperation : public NodeOperation {
ReadBufferOperation *read_operation,
rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.h b/source/blender/compositor/operations/COM_KeyingBlurOperation.h
index 11fde5f5436..cc4a98767d8 100644
--- a/source/blender/compositor/operations/COM_KeyingBlurOperation.h
+++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.h
@@ -55,9 +55,7 @@ class KeyingBlurOperation : public MultiThreadedOperation {
ReadBufferOperation *read_operation,
rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.h b/source/blender/compositor/operations/COM_KeyingClipOperation.h
index 3bdc7281683..b945d4264af 100644
--- a/source/blender/compositor/operations/COM_KeyingClipOperation.h
+++ b/source/blender/compositor/operations/COM_KeyingClipOperation.h
@@ -69,9 +69,7 @@ class KeyingClipOperation : public MultiThreadedOperation {
ReadBufferOperation *read_operation,
rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
index c34eaad87ef..5d12f29b83f 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
@@ -18,6 +18,8 @@
#include "COM_KeyingScreenOperation.h"
+#include "DNA_defaults.h"
+
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
@@ -75,7 +77,7 @@ void KeyingScreenOperation::deinit_execution()
KeyingScreenOperation::TriangulationData *KeyingScreenOperation::build_voronoi_triangulation()
{
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
TriangulationData *triangulation;
MovieTracking *tracking = &movie_clip_->tracking;
MovieTrackingTrack *track;
@@ -132,8 +134,7 @@ KeyingScreenOperation::TriangulationData *KeyingScreenOperation::build_voronoi_t
return nullptr;
}
- triangulation = (TriangulationData *)MEM_callocN(sizeof(TriangulationData),
- "keying screen triangulation data");
+ triangulation = MEM_cnew<TriangulationData>("keying screen triangulation data");
sites = (VoronoiSite *)MEM_callocN(sizeof(VoronoiSite) * sites_total,
"keyingscreen voronoi sites");
@@ -243,7 +244,7 @@ KeyingScreenOperation::TileData *KeyingScreenOperation::triangulate(const rcti *
return nullptr;
}
- tile_data = (TileData *)MEM_callocN(sizeof(TileData), "keying screen tile data");
+ tile_data = MEM_cnew<TileData>("keying screen tile data");
for (i = 0; i < triangulation->triangles_total; i++) {
if (BLI_rcti_isect(rect, &triangulation->triangles_AABB[i], nullptr)) {
@@ -302,7 +303,7 @@ void KeyingScreenOperation::determine_canvas(const rcti &preferred_area, rcti &r
r_area = COM_AREA_NONE;
if (movie_clip_) {
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
int width, height;
int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(movie_clip_, framenumber_);
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
index d04a970bc03..b25073394a2 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc
@@ -18,6 +18,8 @@
#include "COM_MovieDistortionOperation.h"
+#include "DNA_defaults.h"
+
#include "BKE_movieclip.h"
namespace blender::compositor {
@@ -36,7 +38,7 @@ void MovieDistortionOperation::init_data()
{
if (movie_clip_) {
MovieTracking *tracking = &movie_clip_->tracking;
- MovieClipUser clip_user = {0};
+ MovieClipUser clip_user = *DNA_struct_default_get(MovieClipUser);
int calibration_width, calibration_height;
BKE_movieclip_user_set_frame(&clip_user, framenumber_);
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
index 9f8bf2ed127..864eb68ac24 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
@@ -41,7 +41,7 @@ class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOpera
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
const char *view_name,
- const bool save_as_render);
+ bool save_as_render);
void *get_handle(const char *filename);
void deinit_execution() override;
@@ -78,7 +78,7 @@ class OutputStereoOperation : public OutputSingleLayerOperation {
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
const char *view_name,
- const bool save_as_render);
+ bool save_as_render);
void *get_handle(const char *filename);
void deinit_execution() override;
};
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h
index 2a18b056c12..e601ebac4e1 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.h
@@ -57,7 +57,7 @@ class OutputSingleLayerOperation : public MultiThreadedOperation {
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
const char *view_name,
- const bool save_as_render);
+ bool save_as_render);
void execute_region(rcti *rect, unsigned int tile_number) override;
bool is_output_operation(bool /*rendering*/) const override
@@ -136,7 +136,7 @@ void add_exr_channels(void *exrhandle,
const char *layer_name,
const DataType datatype,
const char *view_name,
- const size_t width,
+ size_t width,
bool use_half_float,
float *buf);
void free_exr_channels(void *exrhandle,
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
index 28da200c615..cb73fa9af7b 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc
@@ -18,6 +18,8 @@
#include "COM_PlaneTrackOperation.h"
+#include "DNA_defaults.h"
+
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
@@ -80,7 +82,7 @@ void PlaneTrackCommon::determine_canvas(const rcti &preferred_area, rcti &r_area
r_area = COM_AREA_NONE;
if (movie_clip_) {
int width, height;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
BKE_movieclip_user_set_frame(&user, framenumber_);
BKE_movieclip_get_size(movie_clip_, &user, &width, &height);
r_area = preferred_area;
diff --git a/source/blender/compositor/operations/COM_RotateOperation.h b/source/blender/compositor/operations/COM_RotateOperation.h
index 3970d3a2776..f53fb3a4932 100644
--- a/source/blender/compositor/operations/COM_RotateOperation.h
+++ b/source/blender/compositor/operations/COM_RotateOperation.h
@@ -56,27 +56,19 @@ class RotateOperation : public MultiThreadedOperation {
const rcti &rotate_canvas,
float &r_offset_x,
float &r_offset_y);
- static void get_area_rotation_bounds(const rcti &area,
- const float center_x,
- const float center_y,
- const float sine,
- const float cosine,
- rcti &r_bounds);
- static void get_area_rotation_bounds_inverted(const rcti &area,
- const float center_x,
- const float center_y,
- const float sine,
- const float cosine,
- rcti &r_bounds);
+ static void get_area_rotation_bounds(
+ const rcti &area, float center_x, float center_y, float sine, float cosine, rcti &r_bounds);
+ static void get_area_rotation_bounds_inverted(
+ const rcti &area, float center_x, float center_y, float sine, float cosine, rcti &r_bounds);
static void get_rotation_area_of_interest(const rcti &input_canvas,
const rcti &rotate_canvas,
- const float sine,
- const float cosine,
+ float sine,
+ float cosine,
const rcti &output_area,
rcti &r_input_area);
static void get_rotation_canvas(const rcti &input_canvas,
- const float sine,
- const float cosine,
+ float sine,
+ float cosine,
rcti &r_canvas);
bool determine_depending_area_of_interest(rcti *input,
diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h
index cac865b41aa..132e9c8fed0 100644
--- a/source/blender/compositor/operations/COM_ScaleOperation.h
+++ b/source/blender/compositor/operations/COM_ScaleOperation.h
@@ -90,8 +90,8 @@ class ScaleOperation : public BaseScaleOperation {
static void scale_area(rcti &area, float relative_scale_x, float relative_scale_y);
static void get_scale_area_of_interest(const rcti &input_canvas,
const rcti &scale_canvas,
- const float relative_scale_x,
- const float relative_scale_y,
+ float relative_scale_x,
+ float relative_scale_y,
const rcti &output_area,
rcti &r_input_area);
static void clamp_area_size_max(rcti &area, Size2f max_size);
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc
index f5d47478a8d..a4990993d73 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cc
+++ b/source/blender/compositor/operations/COM_TextureOperation.cc
@@ -22,6 +22,8 @@
#include "BKE_image.h"
#include "BKE_node.h"
+#include "NOD_texture.h"
+
namespace blender::compositor {
TextureBaseOperation::TextureBaseOperation()
diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cc b/source/blender/compositor/operations/COM_TrackPositionOperation.cc
index fc6be97a29c..61ce750a2f4 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.cc
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cc
@@ -18,6 +18,8 @@
#include "COM_TrackPositionOperation.h"
+#include "DNA_defaults.h"
+
#include "BKE_movieclip.h"
#include "BKE_node.h"
#include "BKE_tracking.h"
@@ -50,7 +52,7 @@ void TrackPositionOperation::calc_track_position()
{
is_track_position_calculated_ = true;
MovieTracking *tracking = nullptr;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
MovieTrackingObject *object;
track_position_ = 0;
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cc b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
index e34b629f457..1d097b37ca5 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cc
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cc
@@ -180,8 +180,13 @@ void VectorBlurOperation::generate_vector_blur(float *data,
inputZ->get_buffer());
}
-/* ****************** Spans ******************************* */
-/* span fill in method, is also used to localize data for zbuffering */
+/* -------------------------------------------------------------------- */
+/** \name Spans
+ *
+ * Duplicated logic from `zbuf.c`.
+ * \{ */
+
+/** Span fill in method, is also used to localize data for Z-buffering. */
struct ZSpan {
/* range for clipping */
int rectx, recty;
@@ -327,11 +332,13 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
}
for (y = my2; y >= my0; y--, xs0 += dx0) {
- /* xs0 is the xcoord! */
+ /* xs0 is the X-coordinate! */
span[y] = xs0;
}
}
+/** \} */
+
/* ******************** VECBLUR ACCUM BUF ************************* */
struct DrawBufPixel {
@@ -339,6 +346,9 @@ struct DrawBufPixel {
float alpha;
};
+/**
+ * \note Near duplicate of `zspan_scanconvert` in `zbuf.c` with some minor adjustments.
+ */
static void zbuf_fill_in_rgba(
ZSpan *zspan, DrawBufPixel *col, float *v1, float *v2, float *v3, float *v4)
{
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.h b/source/blender/compositor/operations/COM_VectorBlurOperation.h
index efcb5001fd4..75df9d9e024 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.h
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.h
@@ -72,9 +72,7 @@ class VectorBlurOperation : public NodeOperation, public QualityStepHelper {
ReadBufferOperation *read_operation,
rcti *output) override;
- void get_area_of_interest(const int input_idx,
- const rcti &output_area,
- rcti &r_input_area) override;
+ void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override;
void update_memory_buffer(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
diff --git a/source/blender/datatoc/CMakeLists.txt b/source/blender/datatoc/CMakeLists.txt
index 8411a1a468e..756ab15b163 100644
--- a/source/blender/datatoc/CMakeLists.txt
+++ b/source/blender/datatoc/CMakeLists.txt
@@ -52,10 +52,6 @@ if(NOT WITH_HEADLESS)
endif()
include_directories(${PNG_INCLUDE_DIRS})
- if(NOT APPLE)
- # APPLE platform uses full paths for linking libraries.
- link_directories(${PNG_LIBPATH} ${ZLIB_LIBPATH})
- endif()
add_executable(datatoc_icon ${SRC})
setup_platform_linker_flags(datatoc_icon)
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index 0b3e028cd06..b8ff49640b7 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -129,10 +129,10 @@ void DEG_free_node_types(void);
* \{ */
/** Tag dependency graph for updates when visible scenes/layers changes. */
-void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, const bool do_time);
+void DEG_graph_tag_on_visible_update(Depsgraph *depsgraph, bool do_time);
/** Tag all dependency graphs for update when visible scenes/layers changes. */
-void DEG_tag_on_visible_update(struct Main *bmain, const bool do_time);
+void DEG_tag_on_visible_update(struct Main *bmain, bool do_time);
/**
* \note Will return NULL if the flag is not known, allowing to gracefully handle situations
@@ -173,7 +173,7 @@ void DEG_enable_editors_update(struct Depsgraph *depsgraph);
void DEG_editors_update(struct Depsgraph *depsgraph, bool time);
/** Clear recalc flags after editors or renderers have handled updates. */
-void DEG_ids_clear_recalc(Depsgraph *depsgraph, const bool backup);
+void DEG_ids_clear_recalc(Depsgraph *depsgraph, bool backup);
/**
* Restore recalc flags, backed up by a previous call to #DEG_ids_clear_recalc.
@@ -220,8 +220,7 @@ typedef struct DEGEditorUpdateContext {
} DEGEditorUpdateContext;
typedef void (*DEG_EditorUpdateIDCb)(const DEGEditorUpdateContext *update_ctx, struct ID *id);
-typedef void (*DEG_EditorUpdateSceneCb)(const DEGEditorUpdateContext *update_ctx,
- const bool updated);
+typedef void (*DEG_EditorUpdateSceneCb)(const DEGEditorUpdateContext *update_ctx, bool updated);
/** Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func);
@@ -266,7 +265,7 @@ void DEG_debug_print_eval_subdata_index(struct Depsgraph *depsgraph,
const char *subdata_comment,
const char *subdata_name,
const void *subdata_address,
- const int subdata_index);
+ int subdata_index);
void DEG_debug_print_eval_parent_typed(struct Depsgraph *depsgraph,
const char *function_name,
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index 94cba833096..0461d8b63fd 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -72,7 +72,7 @@ void DEG_graph_build_for_render_pipeline(struct Depsgraph *graph);
*/
void DEG_graph_build_for_compositor_preview(struct Depsgraph *graph, struct bNodeTree *nodetree);
-void DEG_graph_build_from_ids(struct Depsgraph *graph, struct ID **ids, const int num_ids);
+void DEG_graph_build_from_ids(struct Depsgraph *graph, struct ID **ids, int num_ids);
/** Tag relations from the given graph for update. */
void DEG_graph_tag_relations_update(struct Depsgraph *graph);
@@ -120,7 +120,7 @@ typedef enum eDepsObjectComponentType {
DEG_OB_COMP_ANIMATION,
/* Transform Component (Parenting/Constraints) */
DEG_OB_COMP_TRANSFORM,
- /* Geometry Component (Mesh/Displist) */
+ /* Geometry Component (#Mesh / #DispList). */
DEG_OB_COMP_GEOMETRY,
/* Evaluation-Related Outer Types (with Sub-data) */
@@ -153,9 +153,9 @@ void DEG_add_collection_geometry_customdata_mask(struct DepsNodeHandle *node_han
void DEG_add_simulation_relation(struct DepsNodeHandle *node_handle,
struct Simulation *simulation,
const char *description);
-void DEG_add_node_tree_relation(struct DepsNodeHandle *node_handle,
- struct bNodeTree *node_tree,
- const char *description);
+void DEG_add_node_tree_output_relation(struct DepsNodeHandle *node_handle,
+ struct bNodeTree *node_tree,
+ const char *description);
void DEG_add_bone_relation(struct DepsNodeHandle *handle,
struct Object *object,
const char *bone_name,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
index af7717d7595..0afaa72aad0 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
@@ -127,6 +127,7 @@ void AnimatedPropertyStorage::initializeFromID(DepsgraphBuilderCache *builder_ca
void AnimatedPropertyStorage::tagPropertyAsAnimated(const AnimatedPropertyID &property_id)
{
+ animated_objects_set.add(property_id.data);
animated_properties_set.add(property_id);
}
@@ -147,6 +148,11 @@ bool AnimatedPropertyStorage::isPropertyAnimated(const PointerRNA *pointer_rna,
return isPropertyAnimated(AnimatedPropertyID(pointer_rna, property_rna));
}
+bool AnimatedPropertyStorage::isAnyPropertyAnimated(const PointerRNA *pointer_rna)
+{
+ return animated_objects_set.contains(pointer_rna->data);
+}
+
/* Builder cache itself. */
DepsgraphBuilderCache::~DepsgraphBuilderCache()
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.h b/source/blender/depsgraph/intern/builder/deg_builder_cache.h
index c955a22a5cf..690046cb0d3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cache.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.h
@@ -69,10 +69,13 @@ class AnimatedPropertyStorage {
bool isPropertyAnimated(const AnimatedPropertyID &property_id);
bool isPropertyAnimated(const PointerRNA *pointer_rna, const PropertyRNA *property_rna);
+ bool isAnyPropertyAnimated(const PointerRNA *pointer_rna);
+
/* The storage is fully initialized from all F-Curves from corresponding ID. */
bool is_fully_initialized;
/* indexed by PointerRNA.data. */
+ Set<void *> animated_objects_set;
Set<AnimatedPropertyID> animated_properties_set;
MEM_CXX_CLASS_ALLOC_FUNCS("AnimatedPropertyStorage");
@@ -102,6 +105,13 @@ class DepsgraphBuilderCache {
return animated_property_storage->isPropertyAnimated(args...);
}
+ bool isAnyPropertyAnimated(const PointerRNA *ptr)
+ {
+ AnimatedPropertyStorage *animated_property_storage = ensureInitializedAnimatedPropertyStorage(
+ ptr->owner_id);
+ return animated_property_storage->isAnyPropertyAnimated(ptr);
+ }
+
Map<ID *, AnimatedPropertyStorage *> animated_property_storage_map_;
MEM_CXX_CLASS_ALLOC_FUNCS("DepsgraphBuilderCache");
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 51582508b6f..79d674e8415 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -199,9 +199,7 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
nullptr, OperationCode::OPERATION, "", -1);
/* Pin the node so that it and its relations are preserved by the unused nodes/relations
* deletion. This is mainly to make it easier to debug visibility. */
- /* NOTE: Keep un-pinned for the 3.0 release. This way we are more sure that side effects of the
- * change is minimal outside of the dependency graph area. */
- // visibility_operation->flag |= OperationFlag::DEPSOP_FLAG_PINNED;
+ visibility_operation->flag |= OperationFlag::DEPSOP_FLAG_PINNED;
graph_->operations.append(visibility_operation);
}
return id_node;
@@ -273,6 +271,21 @@ OperationNode *DepsgraphNodeBuilder::add_operation_node(ID *id,
OperationNode *DepsgraphNodeBuilder::ensure_operation_node(ID *id,
NodeType comp_type,
+ const char *comp_name,
+ OperationCode opcode,
+ const DepsEvalOperationCb &op,
+ const char *name,
+ int name_tag)
+{
+ OperationNode *operation = find_operation_node(id, comp_type, comp_name, opcode, name, name_tag);
+ if (operation != nullptr) {
+ return operation;
+ }
+ return add_operation_node(id, comp_type, comp_name, opcode, op, name, name_tag);
+}
+
+OperationNode *DepsgraphNodeBuilder::ensure_operation_node(ID *id,
+ NodeType comp_type,
OperationCode opcode,
const DepsEvalOperationCb &op,
const char *name,
@@ -589,11 +602,7 @@ void DepsgraphNodeBuilder::build_id(ID *id)
case ID_HA:
case ID_PT:
case ID_VO:
- /* TODO(sergey): Get visibility from a "parent" somehow.
- *
- * NOTE: Similarly to above, we don't want false-positives on
- * visibility. */
- build_object_data_geometry_datablock(id, false);
+ build_object_data_geometry_datablock(id);
break;
case ID_SPK:
build_speaker((Speaker *)id);
@@ -769,32 +778,28 @@ void DepsgraphNodeBuilder::build_object(int base_index,
if (object->modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
/* Grease Pencil Modifiers. */
if (object->greasepencil_modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_gpencil_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
/* Shader FX. */
if (object->shader_fx.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_shaderfx_foreach_ID_link(object, modifier_walk, &data);
}
/* Constraints. */
if (object->constraints.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_constraints_id_loop(&object->constraints, constraint_walk, &data);
}
/* Object data. */
- build_object_data(object, is_visible);
+ build_object_data(object);
/* Parameters, used by both drivers/animation and also to inform dependency
* from object's data. */
build_parameters(&object->id);
@@ -897,7 +902,7 @@ void DepsgraphNodeBuilder::build_object_instance_collection(Object *object, bool
is_parent_collection_visible_ = is_current_parent_collection_visible;
}
-void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_object_data(Object *object)
{
if (object->data == nullptr) {
return;
@@ -914,14 +919,14 @@ void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visi
case OB_HAIR:
case OB_POINTCLOUD:
case OB_VOLUME:
- build_object_data_geometry(object, is_object_visible);
+ build_object_data_geometry(object);
break;
case OB_ARMATURE:
if (ID_IS_LINKED(object) && object->proxy_from != nullptr) {
- build_proxy_rig(object, is_object_visible);
+ build_proxy_rig(object);
}
else {
- build_rig(object, is_object_visible);
+ build_rig(object);
}
break;
case OB_LAMP:
@@ -1121,7 +1126,14 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips)
void DepsgraphNodeBuilder::build_animation_images(ID *id)
{
- if (BKE_image_user_id_has_animation(id)) {
+ /* GPU materials might use an animated image. However, these materials have no been built yet. We
+ * could scan the entire node tree recursively to check if any texture node has a video. That is
+ * quite expensive. For now just always add this operation node, because it is very fast. */
+ /* TODO: Add a more precise check when it is cheaper to iterate over all image nodes in a node
+ * tree. */
+ const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO);
+
+ if (BKE_image_user_id_has_animation(id) || can_have_gpu_material) {
ID *id_cow = get_cow_id(id);
add_operation_node(
id,
@@ -1201,8 +1213,16 @@ void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path
return;
}
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
- ensure_operation_node(
- id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, nullptr, prop_identifier);
+ /* Custom properties of bones are placed in their components to improve granularity. */
+ if (RNA_struct_is_a(ptr.type, &RNA_PoseBone)) {
+ const bPoseChannel *pchan = static_cast<const bPoseChannel *>(ptr.data);
+ ensure_operation_node(
+ id, NodeType::BONE, pchan->name, OperationCode::ID_PROPERTY, nullptr, prop_identifier);
+ }
+ else {
+ ensure_operation_node(
+ id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, nullptr, prop_identifier);
+ }
}
void DepsgraphNodeBuilder::build_parameters(ID *id)
@@ -1465,7 +1485,7 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
/* ObData Geometry Evaluation */
/* XXX: what happens if the datablock is shared! */
-void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_object_data_geometry(Object *object)
{
OperationNode *op_node;
Scene *scene_cow = get_cow_datablock(scene_);
@@ -1487,7 +1507,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob
/* Point caches. */
build_object_pointcache(object);
/* Geometry. */
- build_object_data_geometry_datablock((ID *)object->data, is_object_visible);
+ build_object_data_geometry_datablock((ID *)object->data);
build_dimensions(object);
/* Batch cache. */
add_operation_node(
@@ -1497,7 +1517,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob
[object_cow](::Depsgraph *depsgraph) { BKE_object_select_update(depsgraph, object_cow); });
}
-void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool is_object_visible)
+void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata)
{
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
@@ -1541,17 +1561,15 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow);
});
op_node->set_as_entry();
- /* Make sure objects used for bevel.taper are in the graph.
- * NOTE: This objects might be not linked to the scene. */
Curve *cu = (Curve *)obdata;
if (cu->bevobj != nullptr) {
- build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, false);
}
if (cu->taperobj != nullptr) {
- build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, false);
}
if (cu->textoncurve != nullptr) {
- build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, false);
}
break;
}
@@ -1710,8 +1728,8 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(ntree->id.properties);
/* Animation, */
build_animdata(&ntree->id);
- /* Shading update. */
- add_operation_node(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ /* Output update. */
+ add_operation_node(&ntree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
@@ -2114,10 +2132,7 @@ void DepsgraphNodeBuilder::modifier_walk(void *user_data,
}
switch (GS(id->name)) {
case ID_OB:
- /* Special case for object, so we take owner visibility into
- * account. */
- data->builder->build_object(
- -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible);
+ data->builder->build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false);
break;
default:
data->builder->build_id(id);
@@ -2137,10 +2152,7 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/,
}
switch (GS(id->name)) {
case ID_OB:
- /* Special case for object, so we take owner visibility into
- * account. */
- data->builder->build_object(
- -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible);
+ data->builder->build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false);
break;
default:
data->builder->build_id(id);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 2d24dc49802..a1db4aaf693 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -135,6 +135,13 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
OperationNode *ensure_operation_node(ID *id,
NodeType comp_type,
+ const char *comp_name,
+ OperationCode opcode,
+ const DepsEvalOperationCb &op = nullptr,
+ const char *name = "",
+ int name_tag = -1);
+ OperationNode *ensure_operation_node(ID *id,
+ NodeType comp_type,
OperationCode opcode,
const DepsEvalOperationCb &op = nullptr,
const char *name = "",
@@ -186,20 +193,17 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_object_flags(int base_index,
Object *object,
eDepsNode_LinkedState_Type linked_state);
- virtual void build_object_data(Object *object, bool is_object_visible);
+ virtual void build_object_data(Object *object);
virtual void build_object_data_camera(Object *object);
- virtual void build_object_data_geometry(Object *object, bool is_object_visible);
- virtual void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible);
+ virtual void build_object_data_geometry(Object *object);
+ virtual void build_object_data_geometry_datablock(ID *obdata);
virtual void build_object_data_light(Object *object);
virtual void build_object_data_lightprobe(Object *object);
virtual void build_object_data_speaker(Object *object);
virtual void build_object_transform(Object *object);
virtual void build_object_constraints(Object *object);
virtual void build_object_pointcache(Object *object);
- virtual void build_pose_constraints(Object *object,
- bPoseChannel *pchan,
- int pchan_index,
- bool is_object_visible);
+ virtual void build_pose_constraints(Object *object, bPoseChannel *pchan, int pchan_index);
virtual void build_rigidbody(Scene *scene);
virtual void build_particle_systems(Object *object, bool is_object_visible);
virtual void build_particle_settings(ParticleSettings *part);
@@ -227,8 +231,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_dimensions(Object *object);
virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
- virtual void build_rig(Object *object, bool is_object_visible);
- virtual void build_proxy_rig(Object *object, bool is_object_visible);
+ virtual void build_rig(Object *object);
+ virtual void build_proxy_rig(Object *object);
virtual void build_armature(bArmature *armature);
virtual void build_armature_bones(ListBase *bones);
virtual void build_shapekeys(Key *key);
@@ -284,8 +288,6 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
struct BuilderWalkUserData {
DepsgraphNodeBuilder *builder;
- /* Denotes whether object the walk is invoked from is visible. */
- bool is_parent_visible;
};
static void modifier_walk(void *user_data,
struct Object *object,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index 00c78b8edce..e8dda7b8de4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -58,13 +58,11 @@ namespace blender::deg {
void DepsgraphNodeBuilder::build_pose_constraints(Object *object,
bPoseChannel *pchan,
- int pchan_index,
- bool is_object_visible)
+ int pchan_index)
{
/* Pull indirect dependencies via constraints. */
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_object_visible;
BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data);
/* Create node for constraint stack. */
@@ -147,7 +145,7 @@ void DepsgraphNodeBuilder::build_splineik_pose(Object *object,
}
/* Pose/Armature Bones Graph */
-void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_rig(Object *object)
{
bArmature *armature = (bArmature *)object->data;
Scene *scene_cow = get_cow_datablock(scene_);
@@ -272,7 +270,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
}
/* Build constraints. */
if (pchan->constraints.first != nullptr) {
- build_pose_constraints(object, pchan, pchan_index, is_object_visible);
+ build_pose_constraints(object, pchan, pchan_index);
}
/**
* IK Solvers.
@@ -301,14 +299,14 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
}
/* Custom shape. */
if (pchan->custom != nullptr) {
- /* TODO(sergey): Use own visibility. */
- build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ /* NOTE: The relation builder will ensure visibility of the custom shape object. */
+ build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, false);
}
pchan_index++;
}
}
-void DepsgraphNodeBuilder::build_proxy_rig(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
{
bArmature *armature = (bArmature *)object->data;
OperationNode *op_node;
@@ -356,7 +354,8 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object, bool is_object_visibl
/* Custom shape. */
if (pchan->custom != nullptr) {
- build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ /* NOTE: The relation builder will ensure visibility of the custom shape object. */
+ build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, false);
}
pchan_index++;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index b195b2d9e11..cb43ef685d4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -1466,12 +1466,26 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id)
void DepsgraphRelationBuilder::build_animation_images(ID *id)
{
+ /* See #DepsgraphNodeBuilder::build_animation_images. */
+ const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO);
+
/* TODO: can we check for existence of node for performance? */
- if (BKE_image_user_id_has_animation(id)) {
+ if (BKE_image_user_id_has_animation(id) || can_have_gpu_material) {
OperationKey image_animation_key(
id, NodeType::IMAGE_ANIMATION, OperationCode::IMAGE_ANIMATION);
TimeSourceKey time_src_key;
add_relation(time_src_key, image_animation_key, "TimeSrc -> Image Animation");
+
+ /* The image users of these ids may change during evaluation. Make sure that the image
+ * animation update happens after evaluation. */
+ if (GS(id->name) == ID_MA) {
+ OperationKey material_update_key(id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ add_relation(material_update_key, image_animation_key, "Material Update -> Image Animation");
+ }
+ else if (GS(id->name) == ID_WO) {
+ OperationKey world_update_key(id, NodeType::SHADING, OperationCode::WORLD_UPDATE);
+ add_relation(world_update_key, image_animation_key, "World Update -> Image Animation");
+ }
}
}
@@ -1726,8 +1740,22 @@ void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_
return;
}
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
- OperationKey id_property_key(
- id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, prop_identifier);
+ /* Custom properties of bones are placed in their components to improve granularity. */
+ OperationKey id_property_key;
+ if (RNA_struct_is_a(ptr.type, &RNA_PoseBone)) {
+ const bPoseChannel *pchan = static_cast<const bPoseChannel *>(ptr.data);
+ id_property_key = OperationKey(
+ id, NodeType::BONE, pchan->name, OperationCode::ID_PROPERTY, prop_identifier);
+ /* Create relation from the parameters component so that tagging armature for parameters update
+ * properly propagates updates to all properties on bones and deeper (if needed). */
+ OperationKey parameters_init_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_ENTRY);
+ add_relation(
+ parameters_init_key, id_property_key, "Init -> ID Property", RELATION_CHECK_BEFORE_ADD);
+ }
+ else {
+ id_property_key = OperationKey(
+ id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, prop_identifier);
+ }
OperationKey parameters_exit_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT);
add_relation(
id_property_key, parameters_exit_key, "ID Property -> Done", RELATION_CHECK_BEFORE_ADD);
@@ -1770,7 +1798,7 @@ void DepsgraphRelationBuilder::build_world(World *world)
if (world->nodetree != nullptr) {
build_nodetree(world->nodetree);
OperationKey ntree_key(
- &world->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ &world->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
add_relation(ntree_key, world_key, "World's NTree");
build_nested_nodetree(&world->id, world->nodetree);
}
@@ -2381,17 +2409,17 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS);
+ /* For allowing drivers on lamp properties. */
+ ComponentKey shading_key(&lamp->id, NodeType::SHADING);
+ add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters");
+
/* light's nodetree */
if (lamp->nodetree != nullptr) {
build_nodetree(lamp->nodetree);
- ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING);
- add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters");
+ ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::NTREE_OUTPUT);
+ add_relation(nodetree_key, shading_key, "NTree->Light Parameters");
build_nested_nodetree(&lamp->id, lamp->nodetree);
}
-
- /* For allowing drivers on lamp properties. */
- ComponentKey shading_key(&lamp->id, NodeType::SHADING);
- add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters");
}
void DepsgraphRelationBuilder::build_nodetree_socket(bNodeSocket *socket)
@@ -2441,7 +2469,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(ntree->id.properties);
build_animdata(&ntree->id);
build_parameters(&ntree->id);
- ComponentKey shading_key(&ntree->id, NodeType::SHADING);
+ OperationKey ntree_output_key(&ntree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
@@ -2460,25 +2488,25 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
if (id_type == ID_MA) {
build_material((Material *)bnode->id);
ComponentKey material_key(id, NodeType::SHADING);
- add_relation(material_key, shading_key, "Material -> Node");
+ add_relation(material_key, ntree_output_key, "Material -> Node");
}
else if (id_type == ID_TE) {
build_texture((Tex *)bnode->id);
ComponentKey texture_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(texture_key, shading_key, "Texture -> Node");
+ add_relation(texture_key, ntree_output_key, "Texture -> Node");
}
else if (id_type == ID_IM) {
build_image((Image *)bnode->id);
ComponentKey image_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(image_key, shading_key, "Image -> Node");
+ add_relation(image_key, ntree_output_key, "Image -> Node");
}
else if (id_type == ID_OB) {
build_object((Object *)id);
ComponentKey object_transform_key(id, NodeType::TRANSFORM);
- add_relation(object_transform_key, shading_key, "Object Transform -> Node");
+ add_relation(object_transform_key, ntree_output_key, "Object Transform -> Node");
if (object_have_geometry_component(reinterpret_cast<Object *>(id))) {
ComponentKey object_geometry_key(id, NodeType::GEOMETRY);
- add_relation(object_geometry_key, shading_key, "Object Geometry -> Node");
+ add_relation(object_geometry_key, ntree_output_key, "Object Geometry -> Node");
}
}
else if (id_type == ID_SCE) {
@@ -2498,23 +2526,26 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
else if (id_type == ID_MSK) {
build_mask((Mask *)id);
OperationKey mask_key(id, NodeType::PARAMETERS, OperationCode::MASK_EVAL);
- add_relation(mask_key, shading_key, "Mask -> Node");
+ add_relation(mask_key, ntree_output_key, "Mask -> Node");
}
else if (id_type == ID_MC) {
build_movieclip((MovieClip *)id);
OperationKey clip_key(id, NodeType::PARAMETERS, OperationCode::MOVIECLIP_EVAL);
- add_relation(clip_key, shading_key, "Clip -> Node");
+ add_relation(clip_key, ntree_output_key, "Clip -> Node");
}
else if (id_type == ID_VF) {
build_vfont((VFont *)id);
ComponentKey vfont_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(vfont_key, shading_key, "VFont -> Node");
+ add_relation(vfont_key, ntree_output_key, "VFont -> Node");
}
else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
bNodeTree *group_ntree = (bNodeTree *)id;
build_nodetree(group_ntree);
- ComponentKey group_shading_key(&group_ntree->id, NodeType::SHADING);
- add_relation(group_shading_key, shading_key, "Group Node");
+ ComponentKey group_output_key(&group_ntree->id, NodeType::NTREE_OUTPUT);
+ /* This relation is not necessary in all cases (e.g. when the group node is not connected to
+ * the output). Currently, we lack the infrastructure to check for these cases efficiently.
+ * That can be added later. */
+ add_relation(group_output_key, ntree_output_key, "Group Node");
}
else {
BLI_assert_msg(0, "Unknown ID type used for node");
@@ -2528,14 +2559,10 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(socket->prop);
}
- OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
-
if (check_id_has_anim_component(&ntree->id)) {
ComponentKey animation_key(&ntree->id, NodeType::ANIMATION);
- add_relation(animation_key, shading_update_key, "NTree Shading Parameters");
+ add_relation(animation_key, ntree_output_key, "NTree Shading Parameters");
}
- ComponentKey parameters_key(&ntree->id, NodeType::PARAMETERS);
- add_relation(parameters_key, shading_update_key, "NTree Shading Parameters");
}
/* Recursively build graph for material */
@@ -2558,7 +2585,7 @@ void DepsgraphRelationBuilder::build_material(Material *material)
if (material->nodetree != nullptr) {
build_nodetree(material->nodetree);
OperationKey ntree_key(
- &material->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ &material->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
add_relation(ntree_key, material_key, "Material's NTree");
build_nested_nodetree(&material->id, material->nodetree);
}
@@ -2587,8 +2614,13 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
build_parameters(&texture->id);
/* texture's nodetree */
- build_nodetree(texture->nodetree);
- build_nested_nodetree(&texture->id, texture->nodetree);
+ if (texture->nodetree) {
+ build_nodetree(texture->nodetree);
+ OperationKey ntree_key(
+ &texture->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
+ add_relation(ntree_key, texture_key, "Texture's NTree");
+ build_nested_nodetree(&texture->id, texture->nodetree);
+ }
/* Special cases for different IDs which texture uses. */
if (texture->type == TEX_IMAGE) {
@@ -2875,12 +2907,16 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations()
*
* This is similar to what happens in ntree_hack_remap_pointers().
*/
-void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id)
+void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id, bool flush_cow_changes)
{
+ int relation_flag = 0;
+ if (!flush_cow_changes) {
+ relation_flag |= RELATION_FLAG_NO_FLUSH;
+ }
OperationKey owner_copy_on_write_key(
owner, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE);
OperationKey id_copy_on_write_key(id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE);
- add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order");
+ add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order", relation_flag);
}
void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree)
@@ -2888,7 +2924,10 @@ void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree
if (ntree == nullptr) {
return;
}
- build_nested_datablock(owner, &ntree->id);
+ /* Don't flush cow changes, because the node tree may change in ways that do not affect the
+ * owner data block (e.g. when a node is deleted that is not connected to any output).
+ * Data blocks owning node trees should add a relation to the `NTREE_OUTPUT` node instead. */
+ build_nested_datablock(owner, &ntree->id, false);
}
void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key)
@@ -2896,7 +2935,7 @@ void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key)
if (key == nullptr) {
return;
}
- build_nested_datablock(owner, &key->id);
+ build_nested_datablock(owner, &key->id, true);
}
void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 09003de3ce4..d699c799e40 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -71,8 +71,8 @@ struct Scene;
struct Simulation;
struct Speaker;
struct Tex;
-struct ViewLayer;
struct VFont;
+struct ViewLayer;
struct World;
struct bAction;
struct bArmature;
@@ -299,7 +299,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
virtual void build_vfont(VFont *vfont);
- virtual void build_nested_datablock(ID *owner, ID *id);
+ virtual void build_nested_datablock(ID *owner, ID *id, bool flush_cow_changes);
virtual void build_nested_nodetree(ID *owner, bNodeTree *ntree);
virtual void build_nested_shapekey(ID *owner, Key *key);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index 3039eebe857..856e37ee473 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -49,6 +49,7 @@
#include "DEG_depsgraph_build.h"
#include "intern/builder/deg_builder.h"
+#include "intern/builder/deg_builder_cache.h"
#include "intern/builder/deg_builder_pchanmap.h"
#include "intern/debug/deg_debug.h"
#include "intern/node/deg_node.h"
@@ -84,14 +85,21 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
OperationKey solver_key(
&object->id, NodeType::EVAL_POSE, rootchan->name, OperationCode::POSE_IK_SOLVER);
OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP);
- add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree");
+ /* If any of the constraint parameters are animated, connect the relation. Since there is only
+ * one Init IK node per armature, this link has quite high risk of spurious dependency cycles.
+ */
+ const bool is_itasc = (object->pose->iksolver == IKSOLVER_ITASC);
+ PointerRNA con_ptr;
+ RNA_pointer_create(&object->id, &RNA_Constraint, con, &con_ptr);
+ if (is_itasc || cache_->isAnyPropertyAnimated(&con_ptr)) {
+ add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree");
+ }
add_relation(init_ik_key, solver_key, "Init IK -> IK Solver");
/* Never cleanup before solver is run. */
add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup", RELATION_FLAG_GODMODE);
/* The ITASC solver currently accesses the target transforms in init tree :(
* TODO: Fix ITASC and remove this.
*/
- bool is_itasc = (object->pose->iksolver == IKSOLVER_ITASC);
OperationKey target_dependent_key = is_itasc ? init_ik_key : solver_key;
/* IK target */
/* TODO(sergey): This should get handled as part of the constraint code. */
@@ -100,6 +108,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
if (data->tar != object) {
ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM);
add_relation(target_key, target_dependent_key, con->name);
+ /* Ensure target CoW is ready by the time IK tree is built just in case. */
+ ComponentKey target_cow_key(&data->tar->id, NodeType::COPY_ON_WRITE);
+ add_relation(
+ target_cow_key, init_ik_key, "IK Target CoW -> Init IK Tree", RELATION_CHECK_BEFORE_ADD);
}
/* Subtarget references: */
if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
@@ -129,6 +141,10 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
if (data->poletar != object) {
ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM);
add_relation(target_key, target_dependent_key, con->name);
+ /* Ensure target CoW is ready by the time IK tree is built just in case. */
+ ComponentKey target_cow_key(&data->poletar->id, NodeType::COPY_ON_WRITE);
+ add_relation(
+ target_cow_key, init_ik_key, "IK Target CoW -> Init IK Tree", RELATION_CHECK_BEFORE_ADD);
}
/* Subtarget references: */
if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 40e59875832..76a115a06c8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -181,7 +181,15 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
node_identifier.operation_name_tag = -1;
/* Handling of commonly known scenarios. */
if (rna_prop_affects_parameters_node(ptr, prop)) {
- node_identifier.type = NodeType::PARAMETERS;
+ /* Custom properties of bones are placed in their components to improve granularity. */
+ if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
+ const bPoseChannel *pchan = static_cast<const bPoseChannel *>(ptr->data);
+ node_identifier.type = NodeType::BONE;
+ node_identifier.component_name = pchan->name;
+ }
+ else {
+ node_identifier.type = NodeType::PARAMETERS;
+ }
node_identifier.operation_code = OperationCode::ID_PROPERTY;
node_identifier.operation_name = RNA_property_identifier(
reinterpret_cast<const PropertyRNA *>(prop));
@@ -351,7 +359,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
- node_identifier.type = NodeType::SHADING;
+ node_identifier.type = NodeType::NTREE_OUTPUT;
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) {
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index 7be661d9668..36120ae76d1 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -425,6 +425,7 @@ static void deg_debug_graphviz_node(DotExportContext &ctx,
case NodeType::ARMATURE:
case NodeType::GENERIC_DATABLOCK:
case NodeType::VISIBILITY:
+ case NodeType::NTREE_OUTPUT:
case NodeType::SIMULATION: {
ComponentNode *comp_node = (ComponentNode *)node;
if (comp_node->operations.is_empty()) {
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index db00c595383..acb8fa8fe88 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -148,15 +148,15 @@ void DEG_add_simulation_relation(DepsNodeHandle *node_handle,
deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description);
}
-void DEG_add_node_tree_relation(DepsNodeHandle *node_handle,
- bNodeTree *node_tree,
- const char *description)
+void DEG_add_node_tree_output_relation(DepsNodeHandle *node_handle,
+ bNodeTree *node_tree,
+ const char *description)
{
- /* Using shading key, because that's the one that exists right now. Should use something else in
- * the future. */
- deg::ComponentKey shading_key(&node_tree->id, deg::NodeType::SHADING);
+ deg::OperationKey ntree_output_key(
+ &node_tree->id, deg::NodeType::NTREE_OUTPUT, deg::OperationCode::NTREE_OUTPUT);
deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
- deg_node_handle->builder->add_node_handle_relation(shading_key, deg_node_handle, description);
+ deg_node_handle->builder->add_node_handle_relation(
+ ntree_output_key, deg_node_handle, description);
}
void DEG_add_object_cache_relation(DepsNodeHandle *node_handle,
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index 7af3d03d478..0b219dcbf5e 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -76,14 +76,8 @@ void deg_invalidate_iterator_work_data(DEGObjectIterData *data)
#endif
}
-void verify_id_properties_freed(DEGObjectIterData *data)
+void ensure_id_properties_freed(const Object *dupli_object, Object *temp_dupli_object)
{
- if (data->dupli_object_current == nullptr) {
- /* We didn't enter duplication yet, so we can't have any dangling pointers. */
- return;
- }
- const Object *dupli_object = data->dupli_object_current->ob;
- Object *temp_dupli_object = &data->temp_dupli_object;
if (temp_dupli_object->id.properties == nullptr) {
/* No ID properties in temp data-block -- no leak is possible. */
return;
@@ -97,6 +91,35 @@ void verify_id_properties_freed(DEGObjectIterData *data)
temp_dupli_object->id.properties = nullptr;
}
+void ensure_boundbox_freed(const Object *dupli_object, Object *temp_dupli_object)
+{
+ if (temp_dupli_object->runtime.bb == nullptr) {
+ /* No Bounding Box in temp data-block -- no leak is possible. */
+ return;
+ }
+ if (temp_dupli_object->runtime.bb == dupli_object->runtime.bb) {
+ /* Temp copy of object did not modify Bounding Box. */
+ return;
+ }
+ /* Free memory which is owned by temporary storage which is about to get overwritten. */
+ MEM_freeN(temp_dupli_object->runtime.bb);
+ temp_dupli_object->runtime.bb = nullptr;
+}
+
+void free_owned_memory(DEGObjectIterData *data)
+{
+ if (data->dupli_object_current == nullptr) {
+ /* We didn't enter duplication yet, so we can't have any dangling pointers. */
+ return;
+ }
+
+ const Object *dupli_object = data->dupli_object_current->ob;
+ Object *temp_dupli_object = &data->temp_dupli_object;
+
+ ensure_id_properties_freed(dupli_object, temp_dupli_object);
+ ensure_boundbox_freed(dupli_object, temp_dupli_object);
+}
+
bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, DupliObject *dob)
{
/* Automatic hiding if this object is being instanced on verts/faces/frames
@@ -153,7 +176,7 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data)
continue;
}
- verify_id_properties_freed(data);
+ free_owned_memory(data);
data->dupli_object_current = dob;
@@ -169,6 +192,8 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data)
copy_v4_v4(temp_dupli_object->color, dupli_parent->color);
temp_dupli_object->runtime.select_id = dupli_parent->runtime.select_id;
if (dob->ob->data != dob->ob_data) {
+ /* Do not modify the original boundbox. */
+ temp_dupli_object->runtime.bb = nullptr;
BKE_object_replace_data_on_shallow_copy(temp_dupli_object, dob->ob_data);
}
@@ -192,7 +217,7 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data)
return true;
}
- verify_id_properties_freed(data);
+ free_owned_memory(data);
free_object_duplilist(data->dupli_list);
data->dupli_parent = nullptr;
data->dupli_list = nullptr;
@@ -334,10 +359,13 @@ static void DEG_iterator_ids_step(BLI_Iterator *iter, deg::IDNode *id_node, bool
return;
}
if (only_updated && !(id_cow->recalc & ID_RECALC_ALL)) {
- bNodeTree *ntree = ntreeFromID(id_cow);
-
/* Node-tree is considered part of the data-block. */
- if (!(ntree && (ntree->id.recalc & ID_RECALC_ALL))) {
+ bNodeTree *ntree = ntreeFromID(id_cow);
+ if (ntree == nullptr) {
+ iter->skip = true;
+ return;
+ }
+ if ((ntree->id.recalc & ID_RECALC_NTREE_OUTPUT) == 0) {
iter->skip = true;
return;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 2b0d0e6e780..4bc9e0d2d14 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -232,6 +232,10 @@ void depsgraph_tag_to_component_opcode(const ID *id,
break;
case ID_RECALC_TAG_FOR_UNDO:
break; /* Must be ignored by depsgraph. */
+ case ID_RECALC_NTREE_OUTPUT:
+ *component_type = NodeType::NTREE_OUTPUT;
+ *operation_code = OperationCode::NTREE_OUTPUT;
+ break;
}
}
@@ -749,6 +753,8 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
return "ALL";
case ID_RECALC_TAG_FOR_UNDO:
return "TAG_FOR_UNDO";
+ case ID_RECALC_NTREE_OUTPUT:
+ return "ID_RECALC_NTREE_OUTPUT";
}
return nullptr;
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 116dba054fa..851d0bcf000 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
@@ -898,6 +898,29 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode
if (!deg_copy_on_write_is_needed(id_orig)) {
return id_cow;
}
+
+ /* When updating object data in edit-mode, don't request COW update since this will duplicate
+ * all object data which is unnecessary when the edit-mode data is used for calculating
+ * modifiers.
+ *
+ * TODO: Investigate modes besides edit-mode. */
+ if (check_datablock_expanded(id_cow)) {
+ const ID_Type id_type = GS(id_orig->name);
+ if (OB_DATA_SUPPORT_EDITMODE(id_type) && BKE_object_data_is_in_editmode(id_orig)) {
+ /* Make sure pointers in the edit mode data are updated in the copy.
+ * This allows depsgraph to pick up changes made in another context after it has been
+ * evaluated. Consider the following scenario:
+ *
+ * - ObjectA in SceneA is using Mesh.
+ * - ObjectB in SceneB is using Mesh (same exact datablock).
+ * - Depsgraph of SceneA is evaluated.
+ * - Depsgraph of SceneB is evaluated.
+ * - User enters edit mode of ObjectA in SceneA. */
+ update_edit_mode_pointers(depsgraph, id_orig, id_cow);
+ return id_cow;
+ }
+ }
+
RuntimeBackup backup(depsgraph);
backup.init_from_id(id_cow);
deg_free_copy_on_write_datablock(id_cow);
@@ -1010,7 +1033,7 @@ void deg_free_copy_on_write_datablock(ID *id_cow)
case ID_OB: {
/* TODO(sergey): This workaround is only to prevent free derived
* caches from modifying object->data. This is currently happening
- * due to mesh/curve datablock boundbox tagging dirty. */
+ * due to mesh/curve data-block bound-box tagging dirty. */
Object *ob_cow = (Object *)id_cow;
ob_cow->data = nullptr;
ob_cow->sculpt = nullptr;
diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc
index 8bc03d8b736..075bfd35ec1 100644
--- a/source/blender/depsgraph/intern/node/deg_node.cc
+++ b/source/blender/depsgraph/intern/node/deg_node.cc
@@ -116,6 +116,8 @@ const char *nodeTypeAsString(NodeType type)
return "VISIBILITY";
case NodeType::SIMULATION:
return "SIMULATION";
+ case NodeType::NTREE_OUTPUT:
+ return "NTREE_OUTPUT";
/* Total number of meaningful node types. */
case NodeType::NUM_TYPES:
@@ -174,6 +176,7 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type)
case NodeType::CACHE:
case NodeType::PROXY:
case NodeType::SIMULATION:
+ case NodeType::NTREE_OUTPUT:
return DEG_SCENE_COMP_PARAMETERS;
case NodeType::VISIBILITY:
@@ -251,6 +254,7 @@ eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
case NodeType::DUPLI:
case NodeType::SYNCHRONIZATION:
case NodeType::SIMULATION:
+ case NodeType::NTREE_OUTPUT:
case NodeType::UNDEFINED:
case NodeType::NUM_TYPES:
return DEG_OB_COMP_PARAMETERS;
diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h
index 7e093ab8765..25bbb9a7237 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -83,7 +83,7 @@ enum class NodeType {
ANIMATION,
/* Transform Component (Parenting/Constraints) */
TRANSFORM,
- /* Geometry Component (Mesh/Displist) */
+ /* Geometry Component (#Mesh / #DispList) */
GEOMETRY,
/* Sequencer Component (Scene Only) */
SEQUENCER,
@@ -112,11 +112,11 @@ enum class NodeType {
* which simplifies common algorithms which are dealing with relations and visibility.
*
* The fact that the visibility operates on the ID level basically means that all components in
- * NodeA will be considered as affecting directly visible when NodeB's visibility is
+ * the NodeA will be considered as affecting directly visible when NodeB's visibility is
* affecting directly visible ID.
*
* This is the way to ensure objects needed for visualization without any actual data dependency
- * are properly evaluated. Example of this is custom shapes for bones. */
+ * properly evaluated. Example of this is custom shapes for bones. */
VISIBILITY,
/* **** Evaluation-Related Outer Types (with Subdata) **** */
@@ -147,6 +147,8 @@ enum class NodeType {
SYNCHRONIZATION,
/* Simulation component. */
SIMULATION,
+ /* Node tree output component. */
+ NTREE_OUTPUT,
/* Total number of meaningful node types. */
NUM_TYPES,
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc
index b716877902c..4c430904e44 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_component.cc
@@ -351,6 +351,7 @@ DEG_COMPONENT_NODE_DEFINE(Armature, ARMATURE, 0);
DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0);
DEG_COMPONENT_NODE_DEFINE(Visibility, VISIBILITY, 0);
DEG_COMPONENT_NODE_DEFINE(Simulation, SIMULATION, 0);
+DEG_COMPONENT_NODE_DEFINE(NTreeOutput, NTREE_OUTPUT, ID_RECALC_NTREE_OUTPUT);
/** \} */
@@ -385,6 +386,7 @@ void deg_register_component_depsnodes()
register_node_typeinfo(&DNTI_GENERIC_DATABLOCK);
register_node_typeinfo(&DNTI_VISIBILITY);
register_node_typeinfo(&DNTI_SIMULATION);
+ register_node_typeinfo(&DNTI_NTREE_OUTPUT);
}
/** \} */
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h
index 9f108af8012..f7acd8c72c3 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -163,23 +163,6 @@ struct ComponentNode : public Node {
DEG_COMPONENT_NODE_DECLARE; \
}
-/* When updating object data in edit-mode, don't request COW update since this will duplicate
- * all object data which is unnecessary when the edit-mode data is used for calculating modifiers.
- *
- * TODO: Investigate modes besides edit-mode. */
-#define DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_OBDATA_IN_EDIT_MODE(name) \
- struct name##ComponentNode : public ComponentNode { \
- DEG_COMPONENT_NODE_DECLARE; \
- virtual bool need_tag_cow_before_update() override \
- { \
- if (OB_DATA_SUPPORT_EDITMODE(owner->id_type) && \
- BKE_object_data_is_in_editmode(owner->id_orig)) { \
- return false; \
- } \
- return true; \
- } \
- }
-
#define DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(name) \
struct name##ComponentNode : public ComponentNode { \
DEG_COMPONENT_NODE_DECLARE; \
@@ -202,7 +185,7 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Animation);
DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(BatchCache);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Cache);
DEG_COMPONENT_NODE_DECLARE_GENERIC(CopyOnWrite);
-DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_OBDATA_IN_EDIT_MODE(Geometry);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Geometry);
DEG_COMPONENT_NODE_DECLARE_GENERIC(ImageAnimation);
DEG_COMPONENT_NODE_DECLARE_GENERIC(LayerCollections);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Particles);
@@ -222,6 +205,7 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature);
DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock);
DEG_COMPONENT_NODE_DECLARE_NO_COW(Visibility);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Simulation);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(NTreeOutput);
/* Bone Component */
struct BoneComponentNode : public ComponentNode {
diff --git a/source/blender/depsgraph/intern/node/deg_node_factory.h b/source/blender/depsgraph/intern/node/deg_node_factory.h
index 125f340a0fa..b3153a7ddfb 100644
--- a/source/blender/depsgraph/intern/node/deg_node_factory.h
+++ b/source/blender/depsgraph/intern/node/deg_node_factory.h
@@ -55,7 +55,7 @@ template<class ModeObjectType> struct DepsNodeFactoryImpl : public DepsNodeFacto
void register_node_typeinfo(DepsNodeFactory *factory);
/* Get typeinfo for specified type */
-DepsNodeFactory *type_get_factory(const NodeType type);
+DepsNodeFactory *type_get_factory(NodeType type);
} // namespace deg
} // namespace blender
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index eaae5d2d5dc..2d0d6854851 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -182,6 +182,9 @@ const char *operationCodeAsString(OperationCode opcode)
return "LIGHT_UPDATE";
case OperationCode::WORLD_UPDATE:
return "WORLD_UPDATE";
+ /* Node Tree. */
+ case OperationCode::NTREE_OUTPUT:
+ return "NTREE_OUTPUT";
/* Movie clip. */
case OperationCode::MOVIECLIP_EVAL:
return "MOVIECLIP_EVAL";
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h
index 31cbb9702ba..4abdc014946 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.h
@@ -177,6 +177,9 @@ enum class OperationCode {
LIGHT_UPDATE,
WORLD_UPDATE,
+ /* Node Tree. ----------------------------------------------------------- */
+ NTREE_OUTPUT,
+
/* Batch caches. -------------------------------------------------------- */
GEOMETRY_SELECT_UPDATE,
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index b895e18aa3d..b40fc88a076 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -44,9 +44,11 @@ set(INC
../../../intern/atomic
../../../intern/glew-mx
../../../intern/guardedalloc
+ ../../../intern/opensubdiv
# dna_type_offsets.h
${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern
+ ${OPENSUBDIV_INCLUDE_DIRS}
)
set(SRC
@@ -85,12 +87,13 @@ set(SRC
intern/draw_cache_impl_curve.cc
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_gpencil.c
- intern/draw_cache_impl_hair.c
+ intern/draw_cache_impl_hair.cc
intern/draw_cache_impl_lattice.c
intern/draw_cache_impl_mesh.c
intern/draw_cache_impl_metaball.c
intern/draw_cache_impl_particles.c
intern/draw_cache_impl_pointcloud.c
+ intern/draw_cache_impl_subdivision.cc
intern/draw_cache_impl_volume.c
intern/draw_color_management.cc
intern/draw_common.c
@@ -151,7 +154,7 @@ set(SRC
engines/workbench/workbench_materials.c
engines/workbench/workbench_opaque.c
engines/workbench/workbench_render.c
- engines/workbench/workbench_shader.c
+ engines/workbench/workbench_shader.cc
engines/workbench/workbench_shadow.c
engines/workbench/workbench_transparent.c
engines/workbench/workbench_volume.c
@@ -194,6 +197,7 @@ set(SRC
DRW_engine.h
DRW_select_buffer.h
+ intern/DRW_gpu_wrapper.hh
intern/DRW_render.h
intern/draw_cache.h
intern/draw_cache_extract.h
@@ -209,6 +213,8 @@ set(SRC
intern/draw_manager_testing.h
intern/draw_manager_text.h
intern/draw_shader.h
+ intern/draw_shader_shared.h
+ intern/draw_subdivision.h
intern/draw_texture_pool.h
intern/draw_view.h
intern/draw_view_data.h
@@ -234,6 +240,7 @@ set(SRC
engines/image/image_wrappers.hh
engines/workbench/workbench_engine.h
engines/workbench/workbench_private.h
+ engines/workbench/workbench_shader_shared.h
engines/select/select_engine.h
engines/select/select_private.h
engines/overlay/overlay_engine.h
@@ -246,256 +253,299 @@ set(LIB
bf_windowmanager
)
-data_to_c_simple(engines/eevee/shaders/ambient_occlusion_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/common_uniforms_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/common_utiltex_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lights_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_geom.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_cube_display_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_cube_display_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_grid_display_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_grid_display_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_grid_fill_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lookdev_world_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/closure_eval_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/closure_eval_diffuse_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/closure_eval_glossy_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/closure_eval_refraction_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/closure_eval_translucent_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/closure_type_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_bloom_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_bokeh_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_dilate_tiles_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_downsample_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_filter_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_flatten_tiles_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_gather_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_reduce_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_resolve_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_scatter_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_scatter_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_dof_setup_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_reflection_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_reflection_resolve_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_reflection_trace_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_downsample_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_downsample_cube_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_gtao_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_velocity_resolve_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_velocity_tile_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_mist_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_subsurface_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_translucency_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/effect_temporal_aa.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/object_motion_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/object_motion_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/prepass_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/prepass_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/shadow_accum_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/shadow_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/shadow_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/bsdf_lut_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/cubemap_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/random_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/renderpass_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/cryptomatte_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/ssr_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/surface_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/surface_geom.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/surface_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/surface_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/update_noise_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/volumetric_accum_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/volumetric_lib.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/volumetric_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/volumetric_geom.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/volumetric_vert.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/volumetric_resolve_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/volumetric_scatter_frag.glsl SRC)
-data_to_c_simple(engines/eevee/shaders/volumetric_integration_frag.glsl SRC)
-
-data_to_c_simple(engines/workbench/shaders/workbench_cavity_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_composite_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_cavity_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_outline_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_image_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_matcap_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_material_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_merge_infront_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_prepass_hair_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shader_interface_lib.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_caps_geom.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_debug_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_transparent_accum_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_transparent_resolve_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC)
-data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC)
-
-data_to_c_simple(intern/shaders/common_colormanagement_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_globals_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_pointcloud_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_hair_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_hair_refine_vert.glsl SRC)
-data_to_c_simple(intern/shaders/common_hair_refine_comp.glsl SRC)
-data_to_c_simple(intern/shaders/common_math_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_math_geom_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_view_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_fxaa_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_smaa_lib.glsl SRC)
-data_to_c_simple(intern/shaders/common_fullscreen_vert.glsl SRC)
-
-data_to_c_simple(engines/gpencil/shaders/gpencil_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_vert.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_antialiasing_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_antialiasing_vert.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_common_lib.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_layer_blend_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_mask_invert_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_depth_merge_frag.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_depth_merge_vert.glsl SRC)
-data_to_c_simple(engines/gpencil/shaders/gpencil_vfx_frag.glsl SRC)
-
-data_to_c_simple(engines/select/shaders/selection_id_3D_vert.glsl SRC)
-data_to_c_simple(engines/select/shaders/selection_id_frag.glsl SRC)
-
-data_to_c_simple(engines/basic/shaders/conservative_depth_geom.glsl SRC)
-data_to_c_simple(engines/basic/shaders/depth_vert.glsl SRC)
-data_to_c_simple(engines/basic/shaders/depth_frag.glsl SRC)
-
-data_to_c_simple(engines/overlay/shaders/common_overlay_lib.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/antialiasing_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/antialiasing_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_dof_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_dof_solid_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_envelope_outline_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_envelope_solid_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_shape_outline_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_shape_outline_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_shape_solid_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_shape_solid_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_shape_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_sphere_outline_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_sphere_solid_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_stick_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_stick_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_wire_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/armature_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/background_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/clipbound_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/depth_only_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_curve_handle_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_curve_handle_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_curve_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_curve_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_gpencil_canvas_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_gpencil_guide_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_gpencil_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_lattice_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_lattice_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_common_lib.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_facefill_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_facefill_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_normal_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_analysis_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_analysis_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_skin_root_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_mesh_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_particle_strand_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_particle_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_edges_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_edges_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_edges_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_verts_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_verts_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_faces_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_face_dots_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_image_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_image_mask_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_stretching_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_groundline_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_lightprobe_grid_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_loose_point_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_loose_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_wire_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/extra_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/facing_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/facing_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/grid_background_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/grid_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/grid_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/image_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/image_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/motion_path_line_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/motion_path_line_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/motion_path_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/outline_detect_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/outline_prepass_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/outline_prepass_geom.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/outline_prepass_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_face_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_point_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_texture_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_texture_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_vertcol_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_vertcol_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_weight_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_weight_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/paint_wire_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/particle_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/particle_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/sculpt_mask_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/sculpt_mask_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/volume_velocity_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/volume_gridlines_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/wireframe_vert.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/wireframe_frag.glsl SRC)
-data_to_c_simple(engines/overlay/shaders/xray_fade_frag.glsl SRC)
-
-data_to_c_simple(engines/image/shaders/engine_image_frag.glsl SRC)
-data_to_c_simple(engines/image/shaders/engine_image_vert.glsl SRC)
+set(GLSL_SRC
+ engines/eevee/shaders/ambient_occlusion_lib.glsl
+ engines/eevee/shaders/background_vert.glsl
+ engines/eevee/shaders/common_uniforms_lib.glsl
+ engines/eevee/shaders/common_utiltex_lib.glsl
+ engines/eevee/shaders/lights_lib.glsl
+ engines/eevee/shaders/lightprobe_lib.glsl
+ engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl
+ engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
+ engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
+ engines/eevee/shaders/lightprobe_geom.glsl
+ engines/eevee/shaders/lightprobe_vert.glsl
+ engines/eevee/shaders/lightprobe_cube_display_frag.glsl
+ engines/eevee/shaders/lightprobe_cube_display_vert.glsl
+ engines/eevee/shaders/lightprobe_grid_display_frag.glsl
+ engines/eevee/shaders/lightprobe_grid_display_vert.glsl
+ engines/eevee/shaders/lightprobe_grid_fill_frag.glsl
+ engines/eevee/shaders/lightprobe_planar_display_frag.glsl
+ engines/eevee/shaders/lightprobe_planar_display_vert.glsl
+ engines/eevee/shaders/lookdev_world_frag.glsl
+ engines/eevee/shaders/closure_eval_lib.glsl
+ engines/eevee/shaders/closure_eval_diffuse_lib.glsl
+ engines/eevee/shaders/closure_eval_glossy_lib.glsl
+ engines/eevee/shaders/closure_eval_refraction_lib.glsl
+ engines/eevee/shaders/closure_eval_translucent_lib.glsl
+ engines/eevee/shaders/closure_type_lib.glsl
+ engines/eevee/shaders/effect_bloom_frag.glsl
+ engines/eevee/shaders/effect_dof_bokeh_frag.glsl
+ engines/eevee/shaders/effect_dof_dilate_tiles_frag.glsl
+ engines/eevee/shaders/effect_dof_downsample_frag.glsl
+ engines/eevee/shaders/effect_dof_filter_frag.glsl
+ engines/eevee/shaders/effect_dof_flatten_tiles_frag.glsl
+ engines/eevee/shaders/effect_dof_gather_frag.glsl
+ engines/eevee/shaders/effect_dof_lib.glsl
+ engines/eevee/shaders/effect_dof_reduce_frag.glsl
+ engines/eevee/shaders/effect_dof_resolve_frag.glsl
+ engines/eevee/shaders/effect_dof_scatter_frag.glsl
+ engines/eevee/shaders/effect_dof_scatter_vert.glsl
+ engines/eevee/shaders/effect_dof_setup_frag.glsl
+ engines/eevee/shaders/effect_reflection_lib.glsl
+ engines/eevee/shaders/effect_reflection_resolve_frag.glsl
+ engines/eevee/shaders/effect_reflection_trace_frag.glsl
+ engines/eevee/shaders/effect_downsample_frag.glsl
+ engines/eevee/shaders/effect_downsample_cube_frag.glsl
+ engines/eevee/shaders/effect_gtao_frag.glsl
+ engines/eevee/shaders/effect_velocity_resolve_frag.glsl
+ engines/eevee/shaders/effect_velocity_tile_frag.glsl
+ engines/eevee/shaders/effect_minmaxz_frag.glsl
+ engines/eevee/shaders/effect_mist_frag.glsl
+ engines/eevee/shaders/effect_motion_blur_frag.glsl
+ engines/eevee/shaders/effect_subsurface_frag.glsl
+ engines/eevee/shaders/effect_translucency_frag.glsl
+ engines/eevee/shaders/effect_temporal_aa.glsl
+ engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
+ engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl
+ engines/eevee/shaders/lightprobe_planar_downsample_vert.glsl
+ engines/eevee/shaders/object_motion_frag.glsl
+ engines/eevee/shaders/object_motion_vert.glsl
+ engines/eevee/shaders/prepass_frag.glsl
+ engines/eevee/shaders/prepass_vert.glsl
+ engines/eevee/shaders/shadow_accum_frag.glsl
+ engines/eevee/shaders/shadow_frag.glsl
+ engines/eevee/shaders/shadow_vert.glsl
+ engines/eevee/shaders/bsdf_lut_frag.glsl
+ engines/eevee/shaders/btdf_lut_frag.glsl
+ engines/eevee/shaders/bsdf_common_lib.glsl
+ engines/eevee/shaders/irradiance_lib.glsl
+ engines/eevee/shaders/octahedron_lib.glsl
+ engines/eevee/shaders/cubemap_lib.glsl
+ engines/eevee/shaders/bsdf_sampling_lib.glsl
+ engines/eevee/shaders/random_lib.glsl
+ engines/eevee/shaders/raytrace_lib.glsl
+ engines/eevee/shaders/renderpass_lib.glsl
+ engines/eevee/shaders/renderpass_postprocess_frag.glsl
+ engines/eevee/shaders/cryptomatte_frag.glsl
+ engines/eevee/shaders/ltc_lib.glsl
+ engines/eevee/shaders/ssr_lib.glsl
+ engines/eevee/shaders/surface_frag.glsl
+ engines/eevee/shaders/surface_geom.glsl
+ engines/eevee/shaders/surface_lib.glsl
+ engines/eevee/shaders/surface_vert.glsl
+ engines/eevee/shaders/update_noise_frag.glsl
+ engines/eevee/shaders/volumetric_accum_frag.glsl
+ engines/eevee/shaders/volumetric_lib.glsl
+ engines/eevee/shaders/volumetric_frag.glsl
+ engines/eevee/shaders/volumetric_geom.glsl
+ engines/eevee/shaders/volumetric_vert.glsl
+ engines/eevee/shaders/volumetric_resolve_frag.glsl
+ engines/eevee/shaders/volumetric_scatter_frag.glsl
+ engines/eevee/shaders/volumetric_integration_frag.glsl
+
+ engines/workbench/shaders/workbench_cavity_lib.glsl
+ engines/workbench/shaders/workbench_common_lib.glsl
+ engines/workbench/shaders/workbench_composite_frag.glsl
+ engines/workbench/shaders/workbench_curvature_lib.glsl
+ engines/workbench/shaders/workbench_effect_cavity_frag.glsl
+ engines/workbench/shaders/workbench_effect_dof_frag.glsl
+ engines/workbench/shaders/workbench_effect_outline_frag.glsl
+ engines/workbench/shaders/workbench_effect_smaa_frag.glsl
+ engines/workbench/shaders/workbench_effect_smaa_vert.glsl
+ engines/workbench/shaders/workbench_effect_taa_frag.glsl
+ engines/workbench/shaders/workbench_image_lib.glsl
+ engines/workbench/shaders/workbench_matcap_lib.glsl
+ engines/workbench/shaders/workbench_material_lib.glsl
+ engines/workbench/shaders/workbench_merge_infront_frag.glsl
+ engines/workbench/shaders/workbench_prepass_frag.glsl
+ engines/workbench/shaders/workbench_prepass_hair_vert.glsl
+ engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl
+ engines/workbench/shaders/workbench_prepass_vert.glsl
+ engines/workbench/shaders/workbench_shadow_caps_geom.glsl
+ engines/workbench/shaders/workbench_shadow_debug_frag.glsl
+ engines/workbench/shaders/workbench_shadow_geom.glsl
+ engines/workbench/shaders/workbench_shadow_vert.glsl
+ engines/workbench/shaders/workbench_transparent_accum_frag.glsl
+ engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
+ engines/workbench/shaders/workbench_volume_frag.glsl
+ engines/workbench/shaders/workbench_volume_vert.glsl
+ engines/workbench/shaders/workbench_world_light_lib.glsl
+
+ engines/workbench/workbench_shader_shared.h
+
+ intern/shaders/common_colormanagement_lib.glsl
+ intern/shaders/common_globals_lib.glsl
+ intern/shaders/common_pointcloud_lib.glsl
+ intern/shaders/common_hair_lib.glsl
+ intern/shaders/common_hair_refine_vert.glsl
+ intern/shaders/common_hair_refine_comp.glsl
+ intern/shaders/common_math_lib.glsl
+ intern/shaders/common_math_geom_lib.glsl
+ intern/shaders/common_view_clipping_lib.glsl
+ intern/shaders/common_view_lib.glsl
+ intern/shaders/common_fxaa_lib.glsl
+ intern/shaders/common_smaa_lib.glsl
+ intern/shaders/common_fullscreen_vert.glsl
+
+ intern/shaders/common_subdiv_custom_data_interp_comp.glsl
+ intern/shaders/common_subdiv_ibo_lines_comp.glsl
+ intern/shaders/common_subdiv_ibo_tris_comp.glsl
+ intern/shaders/common_subdiv_lib.glsl
+ intern/shaders/common_subdiv_normals_accumulate_comp.glsl
+ intern/shaders/common_subdiv_normals_finalize_comp.glsl
+ intern/shaders/common_subdiv_patch_evaluation_comp.glsl
+ intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl
+ intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl
+ intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl
+ intern/shaders/common_subdiv_vbo_lnor_comp.glsl
+ intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
+
+ intern/draw_shader_shared.h
+
+ engines/gpencil/shaders/gpencil_frag.glsl
+ engines/gpencil/shaders/gpencil_vert.glsl
+ engines/gpencil/shaders/gpencil_antialiasing_frag.glsl
+ engines/gpencil/shaders/gpencil_antialiasing_vert.glsl
+ engines/gpencil/shaders/gpencil_common_lib.glsl
+ engines/gpencil/shaders/gpencil_layer_blend_frag.glsl
+ engines/gpencil/shaders/gpencil_mask_invert_frag.glsl
+ engines/gpencil/shaders/gpencil_depth_merge_frag.glsl
+ engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
+ engines/gpencil/shaders/gpencil_vfx_frag.glsl
+
+ engines/select/shaders/selection_id_3D_vert.glsl
+ engines/select/shaders/selection_id_frag.glsl
+
+ engines/basic/shaders/conservative_depth_geom.glsl
+ engines/basic/shaders/depth_vert.glsl
+ engines/basic/shaders/depth_frag.glsl
+
+ engines/overlay/shaders/common_overlay_lib.glsl
+ engines/overlay/shaders/antialiasing_frag.glsl
+ engines/overlay/shaders/antialiasing_vert.glsl
+ engines/overlay/shaders/armature_dof_vert.glsl
+ engines/overlay/shaders/armature_dof_solid_frag.glsl
+ engines/overlay/shaders/armature_envelope_outline_vert.glsl
+ engines/overlay/shaders/armature_envelope_solid_frag.glsl
+ engines/overlay/shaders/armature_envelope_solid_vert.glsl
+ engines/overlay/shaders/armature_shape_outline_geom.glsl
+ engines/overlay/shaders/armature_shape_outline_vert.glsl
+ engines/overlay/shaders/armature_shape_solid_frag.glsl
+ engines/overlay/shaders/armature_shape_solid_vert.glsl
+ engines/overlay/shaders/armature_shape_wire_vert.glsl
+ engines/overlay/shaders/armature_sphere_outline_vert.glsl
+ engines/overlay/shaders/armature_sphere_solid_frag.glsl
+ engines/overlay/shaders/armature_sphere_solid_vert.glsl
+ engines/overlay/shaders/armature_stick_frag.glsl
+ engines/overlay/shaders/armature_stick_vert.glsl
+ engines/overlay/shaders/armature_wire_frag.glsl
+ engines/overlay/shaders/armature_wire_vert.glsl
+ engines/overlay/shaders/background_frag.glsl
+ engines/overlay/shaders/clipbound_vert.glsl
+ engines/overlay/shaders/depth_only_vert.glsl
+ engines/overlay/shaders/edit_curve_handle_geom.glsl
+ engines/overlay/shaders/edit_curve_handle_vert.glsl
+ engines/overlay/shaders/edit_curve_point_vert.glsl
+ engines/overlay/shaders/edit_curve_wire_vert.glsl
+ engines/overlay/shaders/edit_gpencil_canvas_vert.glsl
+ engines/overlay/shaders/edit_gpencil_guide_vert.glsl
+ engines/overlay/shaders/edit_gpencil_vert.glsl
+ engines/overlay/shaders/edit_lattice_point_vert.glsl
+ engines/overlay/shaders/edit_lattice_wire_vert.glsl
+ engines/overlay/shaders/edit_mesh_common_lib.glsl
+ engines/overlay/shaders/edit_mesh_facefill_frag.glsl
+ engines/overlay/shaders/edit_mesh_facefill_vert.glsl
+ engines/overlay/shaders/edit_mesh_frag.glsl
+ engines/overlay/shaders/edit_mesh_geom.glsl
+ engines/overlay/shaders/edit_mesh_normal_vert.glsl
+ engines/overlay/shaders/edit_mesh_analysis_frag.glsl
+ engines/overlay/shaders/edit_mesh_analysis_vert.glsl
+ engines/overlay/shaders/edit_mesh_skin_root_vert.glsl
+ engines/overlay/shaders/edit_mesh_vert.glsl
+ engines/overlay/shaders/edit_particle_strand_vert.glsl
+ engines/overlay/shaders/edit_particle_point_vert.glsl
+ engines/overlay/shaders/edit_uv_edges_vert.glsl
+ engines/overlay/shaders/edit_uv_edges_geom.glsl
+ engines/overlay/shaders/edit_uv_edges_frag.glsl
+ engines/overlay/shaders/edit_uv_verts_vert.glsl
+ engines/overlay/shaders/edit_uv_verts_frag.glsl
+ engines/overlay/shaders/edit_uv_faces_vert.glsl
+ engines/overlay/shaders/edit_uv_face_dots_vert.glsl
+ engines/overlay/shaders/edit_uv_image_vert.glsl
+ engines/overlay/shaders/edit_uv_image_mask_frag.glsl
+ engines/overlay/shaders/edit_uv_stretching_vert.glsl
+ engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl
+ engines/overlay/shaders/extra_frag.glsl
+ engines/overlay/shaders/extra_vert.glsl
+ engines/overlay/shaders/extra_groundline_vert.glsl
+ engines/overlay/shaders/extra_lightprobe_grid_vert.glsl
+ engines/overlay/shaders/extra_loose_point_frag.glsl
+ engines/overlay/shaders/extra_loose_point_vert.glsl
+ engines/overlay/shaders/extra_point_vert.glsl
+ engines/overlay/shaders/extra_wire_frag.glsl
+ engines/overlay/shaders/extra_wire_vert.glsl
+ engines/overlay/shaders/facing_frag.glsl
+ engines/overlay/shaders/facing_vert.glsl
+ engines/overlay/shaders/grid_background_frag.glsl
+ engines/overlay/shaders/grid_frag.glsl
+ engines/overlay/shaders/grid_vert.glsl
+ engines/overlay/shaders/image_vert.glsl
+ engines/overlay/shaders/image_frag.glsl
+ engines/overlay/shaders/motion_path_line_geom.glsl
+ engines/overlay/shaders/motion_path_line_vert.glsl
+ engines/overlay/shaders/motion_path_point_vert.glsl
+ engines/overlay/shaders/outline_detect_frag.glsl
+ engines/overlay/shaders/outline_prepass_frag.glsl
+ engines/overlay/shaders/outline_prepass_geom.glsl
+ engines/overlay/shaders/outline_prepass_vert.glsl
+ engines/overlay/shaders/paint_face_vert.glsl
+ engines/overlay/shaders/paint_point_vert.glsl
+ engines/overlay/shaders/paint_texture_frag.glsl
+ engines/overlay/shaders/paint_texture_vert.glsl
+ engines/overlay/shaders/paint_vertcol_frag.glsl
+ engines/overlay/shaders/paint_vertcol_vert.glsl
+ engines/overlay/shaders/paint_weight_frag.glsl
+ engines/overlay/shaders/paint_weight_vert.glsl
+ engines/overlay/shaders/paint_wire_vert.glsl
+ engines/overlay/shaders/particle_vert.glsl
+ engines/overlay/shaders/particle_frag.glsl
+ engines/overlay/shaders/sculpt_mask_vert.glsl
+ engines/overlay/shaders/sculpt_mask_frag.glsl
+ engines/overlay/shaders/volume_velocity_vert.glsl
+ engines/overlay/shaders/volume_gridlines_vert.glsl
+ engines/overlay/shaders/wireframe_vert.glsl
+ engines/overlay/shaders/wireframe_frag.glsl
+ engines/overlay/shaders/xray_fade_frag.glsl
+
+ engines/image/shaders/engine_image_frag.glsl
+ engines/image/shaders/engine_image_vert.glsl
+)
+
+set(GLSL_C)
+foreach(GLSL_FILE ${GLSL_SRC})
+ data_to_c_simple(${GLSL_FILE} GLSL_C)
+endforeach()
+
+blender_add_lib(bf_draw_shaders "${GLSL_C}" "" "" "")
+
+list(APPEND LIB
+ bf_draw_shaders
+)
+
+set(GLSL_SOURCE_CONTENT "")
+foreach(GLSL_FILE ${GLSL_SRC})
+ get_filename_component(GLSL_FILE_NAME ${GLSL_FILE} NAME)
+ string(REPLACE "." "_" GLSL_FILE_NAME_UNDERSCORES ${GLSL_FILE_NAME})
+ string(APPEND GLSL_SOURCE_CONTENT "SHADER_SOURCE\(datatoc_${GLSL_FILE_NAME_UNDERSCORES}, \"${GLSL_FILE_NAME}\", \"${GLSL_FILE}\"\)\n")
+endforeach()
+
+set(glsl_source_list_file "${CMAKE_CURRENT_BINARY_DIR}/glsl_draw_source_list.h")
+file(GENERATE OUTPUT ${glsl_source_list_file} CONTENT "${GLSL_SOURCE_CONTENT}")
+list(APPEND SRC ${glsl_source_list_file})
+list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR})
+
+target_include_directories(bf_draw_shaders PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
list(APPEND INC
)
@@ -543,8 +593,8 @@ if(WITH_GTESTS)
tests/draw_testing.hh
)
set(TEST_INC
- "../../../intern/ghost/"
- "../gpu/tests/"
+ ../../../intern/ghost
+ ../gpu/tests
)
set(TEST_LIB
)
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 98e166ac3a7..7e411fff72b 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -107,9 +107,9 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
struct ARegion *region,
struct View3D *v3d,
- const bool is_image_render,
- const bool draw_background,
- const bool do_color_management,
+ bool is_image_render,
+ bool draw_background,
+ bool do_color_management,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph,
@@ -125,7 +125,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
bool use_obedit_skip,
bool draw_surface,
bool use_nearest,
- const bool do_material_sub_selection,
+ bool do_material_sub_selection,
const struct rcti *rect,
DRW_SelectPassFn select_pass_fn,
void *select_pass_user_data,
@@ -191,6 +191,10 @@ void DRW_xr_drawing_end(void);
/* For garbage collection */
void DRW_cache_free_old_batches(struct Main *bmain);
+void DRW_cache_free_old_subdiv(void);
+
+/* For the OpenGL evaluators and garbage collected subdivision data. */
+void DRW_subdiv_free(void);
/* Never use this. Only for closing blender. */
void DRW_opengl_context_enable_ex(bool restore);
diff --git a/source/blender/draw/DRW_select_buffer.h b/source/blender/draw/DRW_select_buffer.h
index 18134558af8..0d5c417457c 100644
--- a/source/blender/draw/DRW_select_buffer.h
+++ b/source/blender/draw/DRW_select_buffer.h
@@ -82,10 +82,7 @@ typedef struct SELECTID_Context {
/* draw_select_buffer.c */
-bool DRW_select_buffer_elem_get(const uint sel_id,
- uint *r_elem,
- uint *r_base_index,
- char *r_elem_type);
+bool DRW_select_buffer_elem_get(uint sel_id, uint *r_elem, uint *r_base_index, char *r_elem_type);
uint DRW_select_buffer_context_offset_for_object_elem(struct Depsgraph *depsgraph,
struct Object *object,
char elem_type);
@@ -116,7 +113,7 @@ uint *DRW_select_buffer_bitmap_from_circle(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int center[2],
- const int radius,
+ int radius,
uint *r_bitmap_len);
/**
* \param poly: The polygon coordinates.
@@ -128,7 +125,7 @@ uint *DRW_select_buffer_bitmap_from_poly(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int poly[][2],
- const int poly_len,
+ int poly_len,
const struct rcti *rect,
uint *r_bitmap_len);
/**
@@ -147,9 +144,7 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
const int center[2],
- const uint id_min,
- const uint id_max,
+ uint id_min,
+ uint id_max,
uint *dist);
-void DRW_select_buffer_context_create(struct Base **bases,
- const uint bases_len,
- short select_mode);
+void DRW_select_buffer_context_create(struct Base **bases, uint bases_len, short select_mode);
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h
index ccd53f6c037..240eecf9547 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.h
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.h
@@ -33,6 +33,10 @@ struct Scene;
struct SceneEEVEE;
struct ViewLayer;
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**
* Light Bake.
*/
@@ -66,14 +70,15 @@ void EEVEE_lightbake_update_world_quick(struct EEVEE_ViewLayerData *sldata,
/**
* Light Cache.
*/
-struct LightCache *EEVEE_lightcache_create(const int grid_len,
- const int cube_len,
- const int cube_size,
- const int vis_size,
- const int irr_size[3]);
+struct LightCache *EEVEE_lightcache_create(
+ int grid_len, int cube_len, int cube_size, int vis_size, const int irr_size[3]);
void EEVEE_lightcache_free(struct LightCache *lcache);
bool EEVEE_lightcache_load(struct LightCache *lcache);
void EEVEE_lightcache_info_update(struct SceneEEVEE *eevee);
void EEVEE_lightcache_blend_write(struct BlendWriter *writer, struct LightCache *cache);
void EEVEE_lightcache_blend_read_data(struct BlendDataReader *reader, struct LightCache *cache);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index a0522ad94d2..a027a29c813 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -353,7 +353,7 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
- /* Create Material Ghash */
+ /* Create Material #GHash. */
{
stl->g_data->material_hash = BLI_ghash_ptr_new("Eevee_material ghash");
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index f0d518a58b1..766e721b1b8 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -176,7 +176,7 @@ enum {
VAR_MAT_MESH = (1 << 0),
VAR_MAT_VOLUME = (1 << 1),
VAR_MAT_HAIR = (1 << 2),
- /* VAR_MAT_PROBE = (1 << 3), UNUSED */
+ VAR_MAT_POINTCLOUD = (1 << 3),
VAR_MAT_BLEND = (1 << 4),
VAR_MAT_LOOKDEV = (1 << 5),
VAR_MAT_HOLDOUT = (1 << 6),
@@ -192,8 +192,8 @@ enum {
/* Material shader cache keys */
enum {
/* HACK: This assumes the struct GPUShader will never be smaller than our variations.
- * This allow us to only keep one ghash and avoid bigger keys comparisons/hashing.
- * We combine the GPUShader pointer with the key. */
+ * This allow us to only keep one #GHash and avoid bigger keys comparisons/hashing.
+ * We combine the #GPUShader pointer with the key. */
KEY_CULL = (1 << 0),
KEY_REFRACT = (1 << 1),
KEY_HAIR = (1 << 2),
@@ -1499,7 +1499,7 @@ void EEVEE_temporal_sampling_create_view(EEVEE_Data *vedata);
int EEVEE_temporal_sampling_sample_count_get(const Scene *scene, const EEVEE_StorageList *stl);
int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_temporal_sampling_offset_calc(const double ht_point[2],
- const float filter_size,
+ float filter_size,
float r_offset[2]);
void EEVEE_temporal_sampling_matrices_calc(EEVEE_EffectsInfo *effects, const double ht_point[2]);
/**
@@ -1533,7 +1533,7 @@ void EEVEE_volumes_free(void);
void EEVEE_effects_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
Object *camera,
- const bool minimal);
+ bool minimal);
void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_effects_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
/**
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index 17cc1a46e23..0d6bd1f8024 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -128,7 +128,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
int hitbuf_size[3];
GPU_texture_get_mipmap_size(effects->ssr_hit_output, 0, hitbuf_size);
- /** Screen space raytracing overview
+ /** Screen space ray-tracing overview
*
* Following Frostbite stochastic SSR.
*
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index adede7676d5..c4108969c99 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -887,10 +887,7 @@ struct GPUShader *EEVEE_shaders_volumes_integration_sh_get()
datatoc_volumetric_geom_glsl,
datatoc_volumetric_integration_frag_glsl,
e_data.lib,
- USE_VOLUME_OPTI ? "#extension GL_ARB_shader_image_load_store: enable\n"
- "#extension GL_ARB_shading_language_420pack: enable\n"
- "#define USE_VOLUME_OPTI\n" SHADER_DEFINES :
- SHADER_DEFINES);
+ USE_VOLUME_OPTI ? "#define USE_VOLUME_OPTI\n" SHADER_DEFINES : SHADER_DEFINES);
}
return e_data.volumetric_integration_sh;
}
@@ -1357,6 +1354,9 @@ static char *eevee_get_defines(int options)
if ((options & VAR_MAT_HAIR) != 0) {
BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
}
+ if ((options & VAR_MAT_POINTCLOUD) != 0) {
+ BLI_dynstr_append(ds, "#define POINTCLOUD_SHADER\n");
+ }
if ((options & VAR_WORLD_PROBE) != 0) {
BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n");
}
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
index 0e342938396..cbfa9737a84 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
@@ -26,6 +26,9 @@ void main()
worldNormal = cross(hairTangent, binor);
vec3 world_pos = pos;
+#elif defined(POINTCLOUD_SHADER)
+ pointcloud_get_pos_and_radius(pointPosition, pointRadius);
+ pointID = gl_VertexID;
#else
vec3 world_pos = point_object_to_world(pos);
#endif
diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
index 7d016d57c46..d7fc5e0b52a 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -42,3 +42,13 @@ IN_OUT ShaderHairInterface
flat int hairStrandID;
};
#endif
+
+#ifdef POINTCLOUD_SHADER
+IN_OUT ShaderPointCloudInterface
+{
+ /* world space */
+ float pointRadius;
+ float pointPosition;
+ flat int pointID;
+};
+#endif
diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
index 0ad1393dd70..51e9eda6cc2 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
@@ -31,6 +31,9 @@ void main()
hairThickTime);
worldNormal = cross(hairTangent, binor);
vec3 world_pos = pos;
+#elif defined(POINTCLOUD_SHADER)
+ pointcloud_get_pos_and_radius(pointPosition, pointRadius);
+ pointID = gl_VertexID;
#else
vec3 world_pos = point_object_to_world(pos);
#endif
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 29a9c0211be..bf5dbac9f68 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -108,7 +108,7 @@ BLI_STATIC_ASSERT_ALIGN(gpLight, 16)
/* *********** Draw Data *********** */
typedef struct GPENCIL_MaterialPool {
- /* Linklist. */
+ /* Single linked-list. */
struct GPENCIL_MaterialPool *next;
/* GPU representation of materials. */
gpMaterial mat_data[GP_MATERIAL_BUFFER_LEN];
@@ -148,7 +148,7 @@ typedef struct GPENCIL_ViewLayerData {
/* *********** GPencil *********** */
typedef struct GPENCIL_tVfx {
- /** Linklist */
+ /** Single linked-list. */
struct GPENCIL_tVfx *next;
DRWPass *vfx_ps;
/* Frame-buffer reference since it may not be allocated yet. */
@@ -156,7 +156,7 @@ typedef struct GPENCIL_tVfx {
} GPENCIL_tVfx;
typedef struct GPENCIL_tLayer {
- /** Linklist */
+ /** Single linked-list. */
struct GPENCIL_tLayer *next;
/** Geometry pass (draw all strokes). */
DRWPass *geom_ps;
@@ -172,7 +172,7 @@ typedef struct GPENCIL_tLayer {
} GPENCIL_tLayer;
typedef struct GPENCIL_tObject {
- /** Linklist */
+ /** Single linked-list. */
struct GPENCIL_tObject *next;
struct {
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
index 315133186da..dfff45cbca5 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
@@ -99,6 +99,11 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it
return;
}
+ if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera == NULL) {
+ /* No blur outside camera view (or when DOF is disabled on the camera). */
+ return;
+ }
+
DRWShadingGroup *grp;
const float s = sin(fx->rotation);
const float c = cos(fx->rotation);
@@ -108,7 +113,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it
DRW_view_persmat_get(NULL, persmat, false);
const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
- if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera != NULL) {
+ if ((fx->flag & FX_BLUR_DOF_MODE)) {
/* Compute circle of confusion size. */
float coc = (iter->pd->dof_params[0] / -w) - iter->pd->dof_params[1];
copy_v2_fl(blur_size, fabsf(coc));
diff --git a/source/blender/draw/engines/image/image_private.hh b/source/blender/draw/engines/image/image_private.hh
index 8c63894afd0..05ed2881145 100644
--- a/source/blender/draw/engines/image/image_private.hh
+++ b/source/blender/draw/engines/image/image_private.hh
@@ -73,7 +73,7 @@ class AbstractDrawingMode {
/* image_shader.c */
GPUShader *IMAGE_shader_image_get(bool is_tiled_image);
-void IMAGE_shader_library_ensure(void);
-void IMAGE_shader_free(void);
+void IMAGE_shader_library_ensure();
+void IMAGE_shader_free();
} // namespace blender::draw::image_engine
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index 2345a110134..4029f1237e8 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -139,6 +139,10 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
pd->armature.do_pose_fade_geom = pd->armature.do_pose_xray &&
((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) &&
draw_ctx->object_pose != NULL;
+
+ const float wire_alpha = pd->overlay.bone_wire_alpha;
+ const bool use_wire_alpha = (wire_alpha < 1.0f);
+
DRWState state;
if (pd->armature.do_pose_fade_geom) {
@@ -164,8 +168,8 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[i];
- cb->custom_shapes_ghash = BLI_ghash_ptr_new(__func__);
- cb->custom_shapes_transp_ghash = BLI_ghash_ptr_new(__func__);
+ cb->solid.custom_shapes_ghash = BLI_ghash_ptr_new(__func__);
+ cb->transp.custom_shapes_ghash = BLI_ghash_ptr_new(__func__);
DRWPass **p_armature_ps = &psl->armature_ps[i];
DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
@@ -189,44 +193,85 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
- cb->point_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
+ cb->solid.point_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH);
DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
- DRW_shgroup_uniform_float_copy(grp, "alpha", 0.4f);
- cb->point_transp = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.4f);
+ cb->transp.point_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
sh = OVERLAY_shader_armature_shape(false);
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
- cb->custom_solid = grp;
- cb->box_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
- cb->octa_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
+ cb->solid.custom_fill = grp;
+ cb->solid.box_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
+ cb->solid.octa_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH);
DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
- DRW_shgroup_uniform_float_copy(grp, "alpha", 0.6f);
- cb->custom_transp = grp;
- cb->box_transp = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
- cb->octa_transp = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.6f);
+ cb->transp.custom_fill = grp;
+ cb->transp.box_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
+ cb->transp.octa_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_get());
sh = OVERLAY_shader_armature_sphere(true);
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.point_outline = BUF_INSTANCE(
+ grp, format, DRW_cache_bone_point_wire_outline_get());
+ }
+ else {
+ cb->transp.point_outline = cb->solid.point_outline;
+ }
sh = OVERLAY_shader_armature_shape(true);
- cb->custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
+ cb->solid.custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get());
- cb->octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get());
+ cb->solid.octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get());
+
+ if (use_wire_alpha) {
+ cb->transp.custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get());
+ cb->transp.octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get());
+ }
+ else {
+ cb->transp.custom_outline = cb->solid.custom_outline;
+ cb->transp.box_outline = cb->solid.box_outline;
+ cb->transp.octa_outline = cb->solid.octa_outline;
+ }
sh = OVERLAY_shader_armature_shape_wire();
- cb->custom_wire = grp = DRW_shgroup_create(sh, armature_ps);
+ cb->solid.custom_wire = grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+
+ if (use_wire_alpha) {
+ cb->transp.custom_wire = grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ }
+ else {
+ cb->transp.custom_wire = cb->solid.custom_wire;
+ }
}
{
format = formats->instance_extra;
@@ -234,12 +279,35 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_degrees_of_freedom_wire();
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get());
+ }
+ else {
+ cb->transp.dof_lines = cb->solid.dof_lines;
+ }
sh = OVERLAY_shader_armature_degrees_of_freedom_solid();
grp = DRW_shgroup_create(sh, armature_transp_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_transp_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get());
+ }
+ else {
+ cb->transp.dof_sphere = cb->solid.dof_sphere;
+ }
}
{
format = formats->instance_bone_stick;
@@ -247,7 +315,19 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_stick();
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get());
+ }
+ else {
+ cb->transp.stick = cb->solid.stick;
+ }
}
{
format = formats->instance_bone_envelope;
@@ -258,29 +338,57 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_bool_copy(grp, "isDistance", false);
DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
- cb->envelope_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+ cb->solid.envelope_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_WRITE_DEPTH);
DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA | DRW_STATE_CULL_BACK);
- DRW_shgroup_uniform_float_copy(grp, "alpha", 0.6f);
- cb->envelope_transp = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha * 0.6f);
+ cb->transp.envelope_fill = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
format = formats->instance_bone_envelope_outline;
sh = OVERLAY_shader_armature_envelope(true);
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->envelope_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_outline_get());
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.envelope_outline = BUF_INSTANCE(
+ grp, format, DRW_cache_bone_envelope_outline_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.envelope_outline = BUF_INSTANCE(
+ grp, format, DRW_cache_bone_envelope_outline_get());
+ }
+ else {
+ cb->transp.envelope_outline = cb->solid.envelope_outline;
+ }
format = formats->instance_bone_envelope_distance;
sh = OVERLAY_shader_armature_envelope(false);
grp = DRW_shgroup_create(sh, armature_transp_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
DRW_shgroup_uniform_bool_copy(grp, "isDistance", true);
DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
- cb->envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+ cb->solid.envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_transp_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ DRW_shgroup_uniform_bool_copy(grp, "isDistance", true);
+ DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
+ cb->transp.envelope_distance = BUF_INSTANCE(
+ grp, format, DRW_cache_bone_envelope_solid_get());
+ }
+ else {
+ cb->transp.envelope_distance = cb->solid.envelope_distance;
+ }
}
{
format = formats->pos_color;
@@ -288,7 +396,19 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_wire();
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- cb->wire = BUF_LINE(grp, format);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
+ cb->solid.wire = BUF_LINE(grp, format);
+
+ if (use_wire_alpha) {
+ grp = DRW_shgroup_create(sh, armature_ps);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_float_copy(grp, "alpha", wire_alpha);
+ cb->transp.wire = BUF_LINE(grp, format);
+ }
+ else {
+ cb->transp.wire = cb->solid.wire;
+ }
}
}
}
@@ -540,14 +660,14 @@ static void drw_shgroup_bone_custom_solid(ArmatureDrawContext *ctx,
* 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);
+ Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(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_mesh_batch_cache_validate(mesh);
+ DRW_mesh_batch_cache_validate(custom, mesh);
struct GPUBatch *surf = DRW_mesh_batch_cache_get_surface(mesh);
struct GPUBatch *edges = DRW_mesh_batch_cache_get_edge_detection(mesh, NULL);
@@ -589,13 +709,13 @@ static void drw_shgroup_bone_custom_wire(ArmatureDrawContext *ctx,
Object *custom)
{
/* See comments in #drw_shgroup_bone_custom_solid. */
- Mesh *mesh = BKE_object_get_evaluated_mesh(custom);
+ Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(custom);
if (mesh == NULL) {
return;
}
/* TODO(fclem): arg... less than ideal but we never iter on this object
* to assure batch cache is valid. */
- DRW_mesh_batch_cache_validate(mesh);
+ DRW_mesh_batch_cache_validate(custom, mesh);
struct GPUBatch *geom = DRW_mesh_batch_cache_get_all_edges(mesh);
if (geom) {
@@ -2161,16 +2281,15 @@ static void armature_context_setup(ArmatureDrawContext *ctx,
const bool is_filled = (!pd->armature.transparent && !draw_as_wire) || !is_object_mode;
const bool is_transparent = pd->armature.transparent || (draw_as_wire && !is_object_mode);
bArmature *arm = ob->data;
- OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[is_xray];
+ OVERLAY_ArmatureCallBuffers *cbo = &pd->armature_call_buffers[is_xray];
+ OVERLAY_ArmatureCallBuffersInner *cb = is_transparent ? &cbo->transp : &cbo->solid;
static const float select_const_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
switch (arm->drawtype) {
case ARM_ENVELOPE:
ctx->envelope_outline = cb->envelope_outline;
- ctx->envelope_solid = (is_filled) ?
- (is_transparent ? cb->envelope_transp : cb->envelope_solid) :
- NULL;
+ ctx->envelope_solid = (is_filled) ? cb->envelope_fill : NULL;
ctx->envelope_distance = (do_envelope_dist) ? cb->envelope_distance : NULL;
break;
case ARM_LINE:
@@ -2181,24 +2300,23 @@ static void armature_context_setup(ArmatureDrawContext *ctx,
break;
case ARM_B_BONE:
ctx->outline = cb->box_outline;
- ctx->solid = (is_filled) ? (is_transparent ? cb->box_transp : cb->box_solid) : NULL;
+ ctx->solid = (is_filled) ? cb->box_fill : NULL;
break;
case ARM_OCTA:
ctx->outline = cb->octa_outline;
- ctx->solid = (is_filled) ? (is_transparent ? cb->octa_transp : cb->octa_solid) : NULL;
+ ctx->solid = (is_filled) ? cb->octa_fill : NULL;
break;
}
ctx->ob = ob;
ctx->extras = &pd->extra_call_buffers[is_xray];
ctx->dof_lines = cb->dof_lines;
ctx->dof_sphere = cb->dof_sphere;
- ctx->point_solid = (is_filled) ? (is_transparent ? cb->point_transp : cb->point_solid) : NULL;
+ ctx->point_solid = (is_filled) ? cb->point_fill : NULL;
ctx->point_outline = cb->point_outline;
- ctx->custom_solid = (is_filled) ? (is_transparent ? cb->custom_transp : cb->custom_solid) : NULL;
+ ctx->custom_solid = (is_filled) ? cb->custom_fill : NULL;
ctx->custom_outline = cb->custom_outline;
ctx->custom_wire = cb->custom_wire;
- ctx->custom_shapes_ghash = is_transparent ? cb->custom_shapes_transp_ghash :
- cb->custom_shapes_ghash;
+ ctx->custom_shapes_ghash = cb->custom_shapes_ghash;
ctx->show_relations = pd->armature.show_relations;
ctx->do_relations = !DRW_state_is_select() && pd->armature.show_relations &&
(is_edit_mode | is_pose_mode);
@@ -2282,10 +2400,10 @@ void OVERLAY_armature_cache_finish(OVERLAY_Data *vedata)
OVERLAY_PrivateData *pd = vedata->stl->pd;
for (int i = 0; i < 2; i++) {
- if (pd->armature_call_buffers[i].custom_shapes_ghash) {
+ if (pd->armature_call_buffers[i].solid.custom_shapes_ghash) {
/* TODO(fclem): Do not free it for each frame but reuse it. Avoiding alloc cost. */
- BLI_ghash_free(pd->armature_call_buffers[i].custom_shapes_ghash, NULL, NULL);
- BLI_ghash_free(pd->armature_call_buffers[i].custom_shapes_transp_ghash, NULL, NULL);
+ BLI_ghash_free(pd->armature_call_buffers[i].solid.custom_shapes_ghash, NULL, NULL);
+ BLI_ghash_free(pd->armature_call_buffers[i].transp.custom_shapes_ghash, NULL, NULL);
}
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
index 3a2871249a2..ad929cc0835 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_mesh.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
@@ -28,6 +28,7 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
+#include "BKE_object.h"
#include "draw_cache_impl.h"
#include "draw_manager_text.h"
@@ -229,7 +230,10 @@ static void overlay_edit_mesh_add_ob_to_pass(OVERLAY_PrivateData *pd, Object *ob
Mesh *me = (Mesh *)ob->data;
BMEditMesh *embm = me->edit_mesh;
if (embm) {
- has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final);
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
+
+ has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final);
has_skin_roots = CustomData_get_offset(&embm->bm->vdata, CD_MVERT_SKIN) != -1;
}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c
index 983df1ceac8..f51df908fbf 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_uv.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_uv.c
@@ -412,7 +412,7 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata)
draw_ctx->view_layer, NULL, &objects_len, draw_ctx->object_mode);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *object_eval = DEG_get_evaluated_object(draw_ctx->depsgraph, objects[ob_index]);
- DRW_mesh_batch_cache_validate((Mesh *)object_eval->data);
+ DRW_mesh_batch_cache_validate(object_eval, (Mesh *)object_eval->data);
overlay_edit_uv_cache_populate(vedata, object_eval);
}
MEM_freeN(objects);
@@ -441,22 +441,22 @@ static void overlay_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (has_active_edit_uvmap) {
if (pd->edit_uv.do_uv_overlay) {
- geom = DRW_mesh_batch_cache_get_edituv_edges(ob->data);
+ geom = DRW_mesh_batch_cache_get_edituv_edges(ob, ob->data);
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_edges_grp, geom, NULL);
}
- geom = DRW_mesh_batch_cache_get_edituv_verts(ob->data);
+ geom = DRW_mesh_batch_cache_get_edituv_verts(ob, ob->data);
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_verts_grp, geom, NULL);
}
if (pd->edit_uv.do_faces) {
- geom = DRW_mesh_batch_cache_get_edituv_faces(ob->data);
+ geom = DRW_mesh_batch_cache_get_edituv_faces(ob, ob->data);
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_faces_grp, geom, NULL);
}
}
if (pd->edit_uv.do_face_dots) {
- geom = DRW_mesh_batch_cache_get_edituv_facedots(ob->data);
+ geom = DRW_mesh_batch_cache_get_edituv_facedots(ob, ob->data);
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_face_dots_grp, geom, NULL);
}
@@ -465,14 +465,14 @@ static void overlay_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (pd->edit_uv.do_uv_stretching_overlay) {
if (pd->edit_uv.draw_type == SI_UVDT_STRETCH_ANGLE) {
- geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(me);
+ geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(ob, me);
}
else /* SI_UVDT_STRETCH_AREA */ {
OVERLAY_StretchingAreaTotals *totals = MEM_mallocN(sizeof(OVERLAY_StretchingAreaTotals),
__func__);
BLI_addtail(&pd->edit_uv.totals, totals);
geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_area(
- me, &totals->total_area, &totals->total_area_uv);
+ ob, me, &totals->total_area, &totals->total_area_uv);
}
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_stretching_grp, geom, NULL);
@@ -482,7 +482,7 @@ static void overlay_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (draw_shadows && (has_active_object_uvmap || has_active_edit_uvmap)) {
if (pd->edit_uv.do_uv_shadow_overlay) {
- geom = DRW_mesh_batch_cache_get_uv_edges(ob->data);
+ geom = DRW_mesh_batch_cache_get_uv_edges(ob, ob->data);
if (geom) {
DRW_shgroup_call_obmat(pd->edit_uv_shadow_edges_grp, geom, NULL);
}
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
index 8e7c3094062..c8891a53213 100644
--- a/source/blender/draw/engines/overlay/overlay_private.h
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -216,37 +216,37 @@ typedef struct OVERLAY_ExtraCallBuffers {
DRWShadingGroup *extra_loose_points;
} OVERLAY_ExtraCallBuffers;
-typedef struct OVERLAY_ArmatureCallBuffers {
+typedef struct OVERLAY_ArmatureCallBuffersInner {
DRWCallBuffer *box_outline;
- DRWCallBuffer *box_solid;
- DRWCallBuffer *box_transp;
+ DRWCallBuffer *box_fill;
DRWCallBuffer *dof_lines;
DRWCallBuffer *dof_sphere;
DRWCallBuffer *envelope_distance;
DRWCallBuffer *envelope_outline;
- DRWCallBuffer *envelope_solid;
- DRWCallBuffer *envelope_transp;
+ DRWCallBuffer *envelope_fill;
DRWCallBuffer *octa_outline;
- DRWCallBuffer *octa_solid;
- DRWCallBuffer *octa_transp;
+ DRWCallBuffer *octa_fill;
DRWCallBuffer *point_outline;
- DRWCallBuffer *point_solid;
- DRWCallBuffer *point_transp;
+ DRWCallBuffer *point_fill;
DRWCallBuffer *stick;
DRWCallBuffer *wire;
DRWShadingGroup *custom_outline;
- DRWShadingGroup *custom_solid;
- DRWShadingGroup *custom_transp;
+ DRWShadingGroup *custom_fill;
DRWShadingGroup *custom_wire;
- GHash *custom_shapes_transp_ghash;
+
GHash *custom_shapes_ghash;
+} OVERLAY_ArmatureCallBuffersInner;
+
+typedef struct OVERLAY_ArmatureCallBuffers {
+ OVERLAY_ArmatureCallBuffersInner solid;
+ OVERLAY_ArmatureCallBuffersInner transp;
} OVERLAY_ArmatureCallBuffers;
typedef struct OVERLAY_PrivateData {
@@ -590,11 +590,11 @@ void OVERLAY_extra_line_dashed(OVERLAY_ExtraCallBuffers *cb,
void OVERLAY_extra_line(OVERLAY_ExtraCallBuffers *cb,
const float start[3],
const float end[3],
- const int color_id);
+ int color_id);
void OVERLAY_empty_shape(OVERLAY_ExtraCallBuffers *cb,
const float mat[4][4],
- const float draw_size,
- const char draw_type,
+ float draw_size,
+ char draw_type,
const float color[4]);
void OVERLAY_extra_loose_points(OVERLAY_ExtraCallBuffers *cb,
struct GPUBatch *geom,
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
index 389704b3d66..4c09349c35d 100644
--- a/source/blender/draw/engines/overlay/overlay_shader.c
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -323,7 +323,9 @@ GPUShader *OVERLAY_shader_edit_mesh_vert(void)
datatoc_edit_mesh_common_lib_glsl,
datatoc_edit_mesh_vert_glsl,
NULL},
- .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .frag = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_gpu_shader_point_varying_color_frag_glsl,
+ NULL},
.defs = (const char *[]){sh_cfg->def, "#define VERT\n", NULL},
});
}
@@ -383,7 +385,7 @@ GPUShader *OVERLAY_shader_armature_sphere(bool use_outline)
const DRWContextState *draw_ctx = DRW_context_state_get();
const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- const char extensions[] = "#extension GL_ARB_conservative_depth : enable\n";
+ const char extensions[] = "";
if (use_outline && !sh_data->armature_sphere_outline) {
sh_data->armature_sphere_outline = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
index 449130c4c5b..1eb8fc981cf 100644
--- a/source/blender/draw/engines/overlay/overlay_wireframe.c
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -185,10 +185,11 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
Mesh *me = ob->data;
if (is_edit_mode) {
BLI_assert(me->edit_mesh);
- BMEditMesh *embm = me->edit_mesh;
- has_edit_mesh_cage = embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final);
- if (embm->mesh_eval_final) {
- me = embm->mesh_eval_final;
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
+ has_edit_mesh_cage = editmesh_eval_cage && (editmesh_eval_cage != editmesh_eval_final);
+ if (editmesh_eval_final) {
+ me = editmesh_eval_final;
}
}
is_mesh_verts_only = me->totedge == 0 && me->totvert > 0;
diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl
index e511aab69c1..aedc9bcda61 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl
@@ -1,4 +1,6 @@
+uniform float alpha = 1.0;
+
flat in vec4 finalColor;
layout(location = 0) out vec4 fragColor;
@@ -6,6 +8,6 @@ layout(location = 1) out vec4 lineOutput;
void main()
{
- fragColor = finalColor;
+ fragColor = vec4(finalColor.rgb, finalColor.a * alpha);
lineOutput = vec4(0.0);
}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
index e4a4f0875f8..51cfe6250be 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
@@ -14,7 +14,7 @@ void main()
float n = normalize(normalView).z;
if (isDistance) {
n = 1.0 - clamp(-n, 0.0, 1.0);
- fragColor = vec4(1.0, 1.0, 1.0, 0.2) * n;
+ fragColor = vec4(1.0, 1.0, 1.0, 0.33 * alpha) * n;
}
else {
/* Smooth lighting factor. */
diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
index e7696c1ea7d..85136672180 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
@@ -1,4 +1,6 @@
+uniform float alpha = 1.0;
+
noperspective in float colorFac;
flat in vec4 finalWireColor;
flat in vec4 finalInnerColor;
@@ -10,6 +12,6 @@ void main()
{
float fac = smoothstep(1.0, 0.2, colorFac);
fragColor.rgb = mix(finalInnerColor.rgb, finalWireColor.rgb, fac);
- fragColor.a = 1.0;
+ fragColor.a = alpha;
lineOutput = vec4(0.0);
}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl
index 9413ac0f365..55278515f74 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl
@@ -1,4 +1,6 @@
+uniform float alpha = 1.0;
+
flat in vec4 finalColor;
flat in vec2 edgeStart;
noperspective in vec2 edgePos;
@@ -9,5 +11,5 @@ layout(location = 1) out vec4 lineOutput;
void main()
{
lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
- fragColor = finalColor;
+ fragColor = vec4(finalColor.rgb, finalColor.a * alpha);
}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
index 195d2a5a7b7..418c7bceb63 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
@@ -36,7 +36,7 @@ vec4 EDIT_MESH_edge_vertex_color(int vertex_flag)
return color;
}
-vec4 EDIT_MESH_vertex_color(int vertex_flag)
+vec4 EDIT_MESH_vertex_color(int vertex_flag, float vertex_crease)
{
if ((vertex_flag & VERT_ACTIVE) != 0) {
return vec4(colorEditMeshActive.xyz, 1.0);
@@ -45,6 +45,10 @@ vec4 EDIT_MESH_vertex_color(int vertex_flag)
return colorVertexSelect;
}
else {
+ /* Full crease color if not selected nor active. */
+ if (vertex_crease > 0.0) {
+ return mix(colorVertex, colorEdgeCrease, vertex_crease);
+ }
return colorVertex;
}
}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
index a3ff277b714..5cee976f9a8 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
@@ -13,6 +13,9 @@ in vec4 norAndFlag;
#endif
out vec4 finalColor;
+#ifdef VERT
+out float vertexCrease;
+#endif
#ifdef EDGE
out vec4 finalColorOuter;
#endif
@@ -44,8 +47,9 @@ void main()
ivec4 m_data = data & dataMask;
#if defined(VERT)
- finalColor = EDIT_MESH_vertex_color(m_data.y);
- gl_PointSize = sizeVertex * 2.0;
+ vertexCrease = float(m_data.z >> 4) / 15.0;
+ finalColor = EDIT_MESH_vertex_color(m_data.y, vertexCrease);
+ gl_PointSize = sizeVertex * ((vertexCrease > 0.0) ? 3.0 : 2.0);
/* Make selected and active vertex always on top. */
if ((data.x & VERT_SELECTED) != 0) {
gl_Position.z -= 5e-7 * abs(gl_Position.w);
@@ -65,9 +69,9 @@ void main()
selectOverride = (m_data.y & EDGE_SELECTED);
# endif
- float crease = float(m_data.z) / 255.0;
+ float edge_crease = float(m_data.z & 0xF) / 15.0;
float bweight = float(m_data.w) / 255.0;
- finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, crease, bweight);
+ finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, edge_crease, bweight);
if (finalColorOuter.a > 0.0) {
gl_Position.z -= 5e-7 * abs(gl_Position.w);
diff --git a/source/blender/draw/engines/select/select_draw_utils.c b/source/blender/draw/engines/select/select_draw_utils.c
index e9930dbdb30..2801f2d7720 100644
--- a/source/blender/draw/engines/select/select_draw_utils.c
+++ b/source/blender/draw/engines/select/select_draw_utils.c
@@ -49,7 +49,7 @@ void select_id_object_min_max(Object *obj, float r_min[3], float r_max[3])
BoundBox *bb;
BMEditMesh *em = BKE_editmesh_from_object(obj);
if (em) {
- bb = BKE_editmesh_cage_boundbox_get(em);
+ bb = BKE_editmesh_cage_boundbox_get(obj, em);
}
else {
bb = BKE_object_boundbox_get(obj);
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh
new file mode 100644
index 00000000000..f577ae197b4
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh
@@ -0,0 +1,41 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Base Composite
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_composite)
+ .sampler(0, ImageType::FLOAT_2D, "normalBuffer", Frequency::PASS)
+ .sampler(1, ImageType::FLOAT_2D, "materialBuffer", Frequency::PASS)
+ .uniform_buf(4, "WorldData", "world_data", Frequency::PASS)
+ .push_constant(Type::BOOL, "forceShadowing")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .typedef_source("workbench_shader_shared.h")
+ .fragment_source("workbench_composite_frag.glsl")
+ .additional_info("draw_fullscreen");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lighting Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_composite_studio)
+ .define("V3D_LIGHTING_STUDIO")
+ .additional_info("workbench_composite")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_composite_matcap)
+ .define("V3D_LIGHTING_MATCAP")
+ .sampler(2, ImageType::FLOAT_2D, "matcap_diffuse_tx", Frequency::PASS)
+ .sampler(3, ImageType::FLOAT_2D, "matcap_specular_tx", Frequency::PASS)
+ .additional_info("workbench_composite")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_composite_flat)
+ .define("V3D_LIGHTING_FLAT")
+ .additional_info("workbench_composite")
+ .do_static_compilation(true);
+
+/** \} */
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh
new file mode 100644
index 00000000000..3e0124546b0
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh
@@ -0,0 +1,64 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name TAA
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_taa)
+ .sampler(0, ImageType::FLOAT_2D, "colorBuffer")
+ .push_constant(Type::FLOAT, "samplesWeights", 9)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .fragment_source("workbench_effect_taa_frag.glsl")
+ .additional_info("draw_fullscreen")
+ .do_static_compilation(true);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name SMAA
+ * \{ */
+
+GPU_SHADER_INTERFACE_INFO(workbench_smaa_iface, "")
+ .smooth(Type::VEC2, "uvs")
+ .smooth(Type::VEC2, "pixcoord")
+ .smooth(Type::VEC4, "offset[3]");
+
+GPU_SHADER_CREATE_INFO(workbench_smaa)
+ .define("SMAA_GLSL_3")
+ .define("SMAA_RT_METRICS", "viewportMetrics")
+ .define("SMAA_PRESET_HIGH")
+ .define("SMAA_LUMA_WEIGHT", "float4(1.0, 1.0, 1.0, 1.0)")
+ .define("SMAA_NO_DISCARD")
+ .vertex_out(workbench_smaa_iface)
+ .push_constant(Type::VEC4, "viewportMetrics")
+ .vertex_source("workbench_effect_smaa_vert.glsl")
+ .fragment_source("workbench_effect_smaa_frag.glsl");
+
+GPU_SHADER_CREATE_INFO(workbench_smaa_stage_0)
+ .define("SMAA_STAGE", "0")
+ .sampler(0, ImageType::FLOAT_2D, "colorTex")
+ .fragment_out(0, Type::VEC2, "out_edges")
+ .additional_info("workbench_smaa")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_smaa_stage_1)
+ .define("SMAA_STAGE", "1")
+ .sampler(0, ImageType::FLOAT_2D, "edgesTex")
+ .sampler(1, ImageType::FLOAT_2D, "areaTex")
+ .sampler(2, ImageType::FLOAT_2D, "searchTex")
+ .fragment_out(0, Type::VEC4, "out_weights")
+ .additional_info("workbench_smaa")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_smaa_stage_2)
+ .define("SMAA_STAGE", "2")
+ .sampler(0, ImageType::FLOAT_2D, "colorTex")
+ .sampler(1, ImageType::FLOAT_2D, "blendTex")
+ .push_constant(Type::FLOAT, "mixFactor")
+ .push_constant(Type::FLOAT, "taaAccumulatedWeight")
+ .fragment_out(0, Type::VEC4, "out_color")
+ .additional_info("workbench_smaa")
+ .do_static_compilation(true);
+
+/** \} */
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh
new file mode 100644
index 00000000000..60d79ed50d9
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh
@@ -0,0 +1,31 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(workbench_effect_cavity_common)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .sampler(0, ImageType::DEPTH_2D, "depthBuffer")
+ .sampler(1, ImageType::FLOAT_2D, "normalBuffer")
+ .sampler(2, ImageType::UINT_2D, "objectIdBuffer")
+ .sampler(3, ImageType::FLOAT_2D, "cavityJitter")
+ .uniform_buf(3, "vec4", "samples_coords[512]")
+ .uniform_buf(4, "WorldData", "world_data", Frequency::PASS)
+ .typedef_source("workbench_shader_shared.h")
+ .fragment_source("workbench_effect_cavity_frag.glsl")
+ .additional_info("draw_fullscreen")
+ .additional_info("draw_view");
+
+GPU_SHADER_CREATE_INFO(workbench_effect_cavity)
+ .do_static_compilation(true)
+ .define("USE_CAVITY")
+ .additional_info("workbench_effect_cavity_common");
+
+GPU_SHADER_CREATE_INFO(workbench_effect_curvature)
+ .do_static_compilation(true)
+ .define("USE_CURVATURE")
+ .additional_info("workbench_effect_cavity_common");
+
+GPU_SHADER_CREATE_INFO(workbench_effect_cavity_curvature)
+ .do_static_compilation(true)
+ .define("USE_CAVITY")
+ .define("USE_CURVATURE")
+ .additional_info("workbench_effect_cavity_common");
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_dof_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_dof_info.hh
new file mode 100644
index 00000000000..252a7d4f3a3
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_dof_info.hh
@@ -0,0 +1,55 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof)
+ /* TODO(fclem): Split resources per stage. */
+ .sampler(0, ImageType::FLOAT_2D, "inputCocTex")
+ .sampler(1, ImageType::FLOAT_2D, "maxCocTilesTex")
+ .sampler(2, ImageType::FLOAT_2D, "sceneColorTex")
+ .sampler(3, ImageType::FLOAT_2D, "sceneDepthTex")
+ .sampler(4, ImageType::FLOAT_2D, "backgroundTex")
+ .sampler(5, ImageType::FLOAT_2D, "halfResColorTex")
+ .sampler(6, ImageType::FLOAT_2D, "blurTex")
+ .sampler(7, ImageType::FLOAT_2D, "noiseTex")
+ .push_constant(Type::VEC2, "invertedViewportSize")
+ .push_constant(Type::VEC2, "nearFar")
+ .push_constant(Type::VEC3, "dofParams")
+ .push_constant(Type::FLOAT, "noiseOffset")
+ .fragment_source("workbench_effect_dof_frag.glsl")
+ .additional_info("draw_fullscreen")
+ .additional_info("draw_view");
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof_prepare)
+ .define("PREPARE")
+ .fragment_out(0, Type::VEC4, "halfResColor")
+ .fragment_out(1, Type::VEC2, "normalizedCoc")
+ .additional_info("workbench_effect_dof")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof_downsample)
+ .define("DOWNSAMPLE")
+ .fragment_out(0, Type::VEC4, "outColor")
+ .fragment_out(1, Type::VEC2, "outCocs")
+ .additional_info("workbench_effect_dof")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof_blur1)
+ .define("BLUR1")
+ .define("NUM_SAMPLES", "49")
+ .uniform_buf(1, "vec4", "samples[49]")
+ .fragment_out(0, Type::VEC4, "blurColor")
+ .additional_info("workbench_effect_dof")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof_blur2)
+ .define("BLUR2")
+ .fragment_out(0, Type::VEC4, "finalColor")
+ .additional_info("workbench_effect_dof")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(workbench_effect_dof_resolve)
+ .define("RESOLVE")
+ .fragment_out(0, Type::VEC4, "finalColorAdd", DualBlend::SRC_0)
+ .fragment_out(0, Type::VEC4, "finalColorMul", DualBlend::SRC_1)
+ .additional_info("workbench_effect_dof")
+ .do_static_compilation(true); \ No newline at end of file
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_outline_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_outline_info.hh
new file mode 100644
index 00000000000..3849fe57a25
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_effect_outline_info.hh
@@ -0,0 +1,11 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(workbench_effect_outline)
+ .typedef_source("workbench_shader_shared.h")
+ .fragment_source("workbench_effect_outline_frag.glsl")
+ .sampler(0, ImageType::UINT_2D, "objectIdBuffer")
+ .uniform_buf(4, "WorldData", "world_data", Frequency::PASS)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .additional_info("draw_fullscreen")
+ .do_static_compilation(true);
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh
new file mode 100644
index 00000000000..78403c292f0
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh
@@ -0,0 +1,9 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(workbench_merge_infront)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .sampler(0, ImageType::DEPTH_2D, "depthBuffer")
+ .fragment_source("workbench_merge_infront_frag.glsl")
+ .additional_info("draw_fullscreen")
+ .do_static_compilation(true);
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
new file mode 100644
index 00000000000..29eadc8048a
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
@@ -0,0 +1,149 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Object Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_mesh)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC3, "nor")
+ .vertex_in(2, Type::VEC4, "ac")
+ .vertex_in(3, Type::VEC2, "au")
+ .vertex_source("workbench_prepass_vert.glsl")
+ .additional_info("draw_mesh")
+ .additional_info("draw_resource_handle");
+
+GPU_SHADER_CREATE_INFO(workbench_hair)
+ .sampler(0, ImageType::FLOAT_BUFFER, "ac", Frequency::BATCH)
+ .sampler(1, ImageType::FLOAT_BUFFER, "au", Frequency::BATCH)
+ .vertex_source("workbench_prepass_hair_vert.glsl")
+ .additional_info("draw_hair")
+ .additional_info("draw_resource_handle");
+
+GPU_SHADER_CREATE_INFO(workbench_pointcloud)
+ .vertex_source("workbench_prepass_pointcloud_vert.glsl")
+ .additional_info("draw_pointcloud")
+ .additional_info("draw_resource_handle");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Texture Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_texture_none).define("TEXTURE_NONE");
+
+GPU_SHADER_CREATE_INFO(workbench_texture_single)
+ .sampler(2, ImageType::FLOAT_2D, "imageTexture", Frequency::BATCH)
+ .push_constant(Type::BOOL, "imagePremult")
+ .push_constant(Type::FLOAT, "imageTransparencyCutoff")
+ .define("V3D_SHADING_TEXTURE_COLOR");
+
+GPU_SHADER_CREATE_INFO(workbench_texture_tile)
+ .sampler(2, ImageType::FLOAT_2D_ARRAY, "imageTileArray", Frequency::BATCH)
+ .sampler(3, ImageType::FLOAT_1D_ARRAY, "imageTileData", Frequency::BATCH)
+ .push_constant(Type::BOOL, "imagePremult")
+ .push_constant(Type::FLOAT, "imageTransparencyCutoff")
+ .define("V3D_SHADING_TEXTURE_COLOR")
+ .define("TEXTURE_IMAGE_ARRAY");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lighting Type (only for transparent)
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_lighting_flat).define("V3D_LIGHTING_FLAT");
+GPU_SHADER_CREATE_INFO(workbench_lighting_studio).define("V3D_LIGHTING_STUDIO");
+GPU_SHADER_CREATE_INFO(workbench_lighting_matcap)
+ .define("V3D_LIGHTING_MATCAP")
+ .sampler(4, ImageType::FLOAT_2D, "matcap_diffuse_tx", Frequency::PASS)
+ .sampler(5, ImageType::FLOAT_2D, "matcap_specular_tx", Frequency::PASS);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Material Interface
+ * \{ */
+
+GPU_SHADER_INTERFACE_INFO(workbench_material_iface, "")
+ .smooth(Type::VEC3, "normal_interp")
+ .smooth(Type::VEC3, "color_interp")
+ .smooth(Type::FLOAT, "alpha_interp")
+ .smooth(Type::VEC2, "uv_interp")
+ .flat(Type::INT, "object_id")
+ .flat(Type::FLOAT, "roughness")
+ .flat(Type::FLOAT, "metallic");
+
+GPU_SHADER_CREATE_INFO(workbench_material)
+ .uniform_buf(4, "WorldData", "world_data", Frequency::PASS)
+ .uniform_buf(5, "vec4", "materials_data[4096]", Frequency::PASS)
+ .push_constant(Type::INT, "materialIndex")
+ .push_constant(Type::BOOL, "useMatcap")
+ .vertex_out(workbench_material_iface);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pipeline Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_transparent_accum)
+ /* Note: Blending will be skipped on objectId because output is a
+ non-normalized integer buffer. */
+ .fragment_out(0, Type::VEC4, "transparentAccum")
+ .fragment_out(1, Type::VEC4, "revealageAccum")
+ .fragment_out(2, Type::UINT, "objectId")
+ .push_constant(Type::BOOL, "forceShadowing")
+ .typedef_source("workbench_shader_shared.h")
+ .fragment_source("workbench_transparent_accum_frag.glsl");
+
+GPU_SHADER_CREATE_INFO(workbench_opaque)
+ .fragment_out(0, Type::VEC4, "materialData")
+ .fragment_out(1, Type::VEC2, "normalData")
+ .fragment_out(2, Type::UINT, "objectId")
+ .typedef_source("workbench_shader_shared.h")
+ .fragment_source("workbench_prepass_frag.glsl");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Variations Declaration
+ * \{ */
+
+#define WORKBENCH_FINAL_VARIATION(name, ...) \
+ GPU_SHADER_CREATE_INFO(name).additional_info(__VA_ARGS__).do_static_compilation(true);
+
+#define WORKBENCH_CLIPPING_VARIATIONS(prefix, ...) \
+ WORKBENCH_FINAL_VARIATION(prefix##_clip, "drw_clipped", __VA_ARGS__) \
+ WORKBENCH_FINAL_VARIATION(prefix##_no_clip, __VA_ARGS__)
+
+#define WORKBENCH_TEXTURE_VARIATIONS(prefix, ...) \
+ WORKBENCH_CLIPPING_VARIATIONS(prefix##_tex_none, "workbench_texture_none", __VA_ARGS__) \
+ WORKBENCH_CLIPPING_VARIATIONS(prefix##_tex_single, "workbench_texture_single", __VA_ARGS__) \
+ WORKBENCH_CLIPPING_VARIATIONS(prefix##_tex_tile, "workbench_texture_tile", __VA_ARGS__)
+
+#define WORKBENCH_DATATYPE_VARIATIONS(prefix, ...) \
+ WORKBENCH_TEXTURE_VARIATIONS(prefix##_mesh, "workbench_mesh", __VA_ARGS__) \
+ WORKBENCH_TEXTURE_VARIATIONS(prefix##_hair, "workbench_hair", __VA_ARGS__) \
+ WORKBENCH_TEXTURE_VARIATIONS(prefix##_ptcloud, "workbench_pointcloud", __VA_ARGS__)
+
+#define WORKBENCH_PIPELINE_VARIATIONS(prefix, ...) \
+ WORKBENCH_DATATYPE_VARIATIONS(prefix##_transp_studio, \
+ "workbench_transparent_accum", \
+ "workbench_lighting_studio", \
+ __VA_ARGS__) \
+ WORKBENCH_DATATYPE_VARIATIONS(prefix##_transp_matcap, \
+ "workbench_transparent_accum", \
+ "workbench_lighting_matcap", \
+ __VA_ARGS__) \
+ WORKBENCH_DATATYPE_VARIATIONS(prefix##_transp_flat, \
+ "workbench_transparent_accum", \
+ "workbench_lighting_flat", \
+ __VA_ARGS__) \
+ WORKBENCH_DATATYPE_VARIATIONS(prefix##_opaque, "workbench_opaque", __VA_ARGS__)
+
+WORKBENCH_PIPELINE_VARIATIONS(workbench, "workbench_material");
+
+/** \} */
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh
new file mode 100644
index 00000000000..c26d3c3aaf8
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_shadow_info.hh
@@ -0,0 +1,98 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Common
+ * \{ */
+
+GPU_SHADER_INTERFACE_INFO(workbench_shadow_iface, "vData")
+ .smooth(Type::VEC3, "pos")
+ .smooth(Type::VEC4, "frontPosition")
+ .smooth(Type::VEC4, "backPosition");
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_common)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_out(workbench_shadow_iface)
+ .push_constant(Type::FLOAT, "lightDistance")
+ .push_constant(Type::VEC3, "lightDirection")
+ .vertex_source("workbench_shadow_vert.glsl")
+ .additional_info("draw_mesh");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Manifold Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_manifold)
+ .geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::TRIANGLE_STRIP, 4, 1)
+ .geometry_source("workbench_shadow_geom.glsl");
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_no_manifold)
+ .geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::TRIANGLE_STRIP, 4, 2)
+ .geometry_source("workbench_shadow_geom.glsl");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Caps Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_caps)
+ .geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3, 2)
+ .geometry_source("workbench_shadow_caps_geom.glsl");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Debug Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_no_debug)
+ .fragment_source("gpu_shader_depth_only_frag.glsl");
+
+GPU_SHADER_CREATE_INFO(workbench_shadow_debug)
+ .fragment_out(0, Type::VEC4, "materialData")
+ .fragment_out(1, Type::VEC4, "normalData")
+ .fragment_out(2, Type::UINT, "objectId")
+ .fragment_source("workbench_shadow_debug_frag.glsl");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Variations Declaration
+ * \{ */
+
+#define WORKBENCH_SHADOW_VARIATIONS(suffix, ...) \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_pass_manifold_no_caps##suffix) \
+ .define("SHADOW_PASS") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_manifold", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_pass_no_manifold_no_caps##suffix) \
+ .define("SHADOW_PASS") \
+ .define("DOUBLE_MANIFOLD") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_no_manifold", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_fail_manifold_caps##suffix) \
+ .define("SHADOW_FAIL") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_caps", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_fail_manifold_no_caps##suffix) \
+ .define("SHADOW_FAIL") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_manifold", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_fail_no_manifold_caps##suffix) \
+ .define("SHADOW_FAIL") \
+ .define("DOUBLE_MANIFOLD") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_caps", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(workbench_shadow_fail_no_manifold_no_caps##suffix) \
+ .define("SHADOW_FAIL") \
+ .define("DOUBLE_MANIFOLD") \
+ .additional_info("workbench_shadow_common", "workbench_shadow_no_manifold", __VA_ARGS__) \
+ .do_static_compilation(true);
+
+WORKBENCH_SHADOW_VARIATIONS(, "workbench_shadow_no_debug")
+WORKBENCH_SHADOW_VARIATIONS(_debug, "workbench_shadow_debug")
+
+/** \} */
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_transparent_resolve_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_transparent_resolve_info.hh
new file mode 100644
index 00000000000..e5b7bc8e2a7
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_transparent_resolve_info.hh
@@ -0,0 +1,10 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(workbench_transparent_resolve)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .sampler(0, ImageType::FLOAT_2D, "transparentAccum")
+ .sampler(1, ImageType::FLOAT_2D, "transparentRevealage")
+ .fragment_source("workbench_transparent_resolve_frag.glsl")
+ .additional_info("draw_fullscreen")
+ .do_static_compilation(true);
diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh
new file mode 100644
index 00000000000..dd9492481ec
--- /dev/null
+++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_volume_info.hh
@@ -0,0 +1,114 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Volume shader base
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_volume)
+ .vertex_in(0, Type::VEC3, "pos")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .sampler(0, ImageType::DEPTH_2D, "depthBuffer")
+ .sampler(1, ImageType::FLOAT_3D, "densityTexture")
+ .push_constant(Type::INT, "samplesLen")
+ .push_constant(Type::FLOAT, "noiseOfs")
+ .push_constant(Type::FLOAT, "stepLength")
+ .push_constant(Type::FLOAT, "densityScale")
+ .vertex_source("workbench_volume_vert.glsl")
+ .fragment_source("workbench_volume_frag.glsl")
+ .additional_info("draw_object_infos");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smoke variation
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_volume_smoke)
+ .define("VOLUME_SMOKE")
+ .sampler(2, ImageType::FLOAT_3D, "flameTexture")
+ .sampler(3, ImageType::FLOAT_1D, "flameColorTexture")
+ .additional_info("draw_mesh", "draw_resource_id_varying");
+
+GPU_SHADER_CREATE_INFO(workbench_volume_object)
+ .define("VOLUME_OBJECT")
+ .push_constant(Type::MAT4, "volumeTextureToObject")
+ /* FIXME(fclem): This overflow the push_constant limit. */
+ .push_constant(Type::MAT4, "volumeObjectToTexture")
+ .additional_info("draw_volume", "draw_resource_id_varying");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Color Band variation
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_volume_coba)
+ .define("USE_COBA")
+ .sampler(4, ImageType::UINT_3D, "flagTexture")
+ .sampler(5, ImageType::FLOAT_1D, "transferTexture")
+ .push_constant(Type::BOOL, "showPhi")
+ .push_constant(Type::BOOL, "showFlags")
+ .push_constant(Type::BOOL, "showPressure")
+ .push_constant(Type::FLOAT, "gridScale");
+
+GPU_SHADER_CREATE_INFO(workbench_volume_no_coba)
+ .sampler(4, ImageType::FLOAT_3D, "shadowTexture")
+ .sampler(5, ImageType::UINT_2D, "transferTexture")
+ .push_constant(Type::VEC3, "activeColor");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sampling variation
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(workbench_volume_linear).define("USE_TRILINEAR");
+GPU_SHADER_CREATE_INFO(workbench_volume_cubic).define("USE_TRICUBIC");
+GPU_SHADER_CREATE_INFO(workbench_volume_closest).define("USE_CLOSEST");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Slice variation
+ * \{ */
+
+GPU_SHADER_INTERFACE_INFO(workbench_volume_iface, "").smooth(Type::VEC3, "localPos");
+
+GPU_SHADER_CREATE_INFO(workbench_volume_slice)
+ .define("VOLUME_SLICE")
+ .vertex_in(1, Type::VEC3, "uvs")
+ .vertex_out(workbench_volume_iface)
+ .push_constant(Type::INT, "sliceAxis") /* -1 is no slice. */
+ .push_constant(Type::FLOAT, "slicePosition");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Variations Declaration
+ * \{ */
+
+#define WORKBENCH_VOLUME_SLICE_VARIATIONS(prefix, ...) \
+ GPU_SHADER_CREATE_INFO(prefix##_slice) \
+ .additional_info("workbench_volume_slice", __VA_ARGS__) \
+ .do_static_compilation(true); \
+ GPU_SHADER_CREATE_INFO(prefix##_no_slice) \
+ .additional_info(__VA_ARGS__) \
+ .do_static_compilation(true);
+
+#define WORKBENCH_VOLUME_COBA_VARIATIONS(prefix, ...) \
+ WORKBENCH_VOLUME_SLICE_VARIATIONS(prefix##_coba, "workbench_volume_coba", __VA_ARGS__) \
+ WORKBENCH_VOLUME_SLICE_VARIATIONS(prefix##_no_coba, "workbench_volume_no_coba", __VA_ARGS__)
+
+#define WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix, ...) \
+ WORKBENCH_VOLUME_COBA_VARIATIONS(prefix##_linear, "workbench_volume_linear", __VA_ARGS__) \
+ WORKBENCH_VOLUME_COBA_VARIATIONS(prefix##_cubic, "workbench_volume_cubic", __VA_ARGS__) \
+ WORKBENCH_VOLUME_COBA_VARIATIONS(prefix##_closest, "workbench_volume_closest", __VA_ARGS__)
+
+#define WORKBENCH_VOLUME_SMOKE_VARIATIONS(prefix, ...) \
+ WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix##_smoke, "workbench_volume_smoke", __VA_ARGS__) \
+ WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix##_object, "workbench_volume_object", __VA_ARGS__)
+
+WORKBENCH_VOLUME_SMOKE_VARIATIONS(workbench_volume, "workbench_volume")
+
+/** \} */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
index 9038aae533b..ad83d6f39e5 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
@@ -1,15 +1,7 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
-layout(std140) uniform samples_block
-{
- vec4 samples_coords[512];
-};
-
-uniform sampler2D cavityJitter;
-
/* From The Alchemy screen-space ambient obscurance algorithm
* http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
index 8cbc8608f5b..9b142fe56b5 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl
@@ -3,10 +3,6 @@
#define CAVITY_BUFFER_RANGE 4.0
-#ifdef WORKBENCH_ENCODE_NORMALS
-
-# define WB_Normal vec2
-
/* From http://aras-p.info/texts/CompactNormalStorage.html
* Using Method #4: Spheremap Transform */
vec3 workbench_normal_decode(vec4 enc)
@@ -22,7 +18,7 @@ vec3 workbench_normal_decode(vec4 enc)
/* From http://aras-p.info/texts/CompactNormalStorage.html
* Using Method #4: Spheremap Transform */
-WB_Normal workbench_normal_encode(bool front_face, vec3 n)
+vec2 workbench_normal_encode(bool front_face, vec3 n)
{
n = normalize(front_face ? n : -n);
float p = sqrt(n.z * 8.0 + 8.0);
@@ -30,13 +26,6 @@ WB_Normal workbench_normal_encode(bool front_face, vec3 n)
return n.xy;
}
-#else
-# define WB_Normal vec3
-/* Well just do nothing... */
-# define workbench_normal_encode(f, a) (a)
-# define workbench_normal_decode(a) (a.xyz)
-#endif /* WORKBENCH_ENCODE_NORMALS */
-
/* Encoding into the alpha of a RGBA16F texture. (10bit mantissa) */
#define TARGET_BITCOUNT 8u
#define METALLIC_BITS 3u /* Metallic channel is less important. */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
index c5b2ce0fd99..5e43fe27f38 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl
@@ -4,13 +4,6 @@
#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl)
-uniform sampler2D materialBuffer;
-uniform sampler2D normalBuffer;
-
-in vec4 uvcoordsvar;
-
-out vec4 fragColor;
-
void main()
{
/* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */
@@ -27,7 +20,7 @@ void main()
/* When using matcaps, mat_data.a is the back-face sign. */
N = (mat_data.a > 0.0) ? N : -N;
- fragColor.rgb = get_matcap_lighting(base_color, N, I);
+ fragColor.rgb = get_matcap_lighting(matcap_diffuse_tx, matcap_specular_tx, base_color, N, I);
#endif
#ifdef V3D_LIGHTING_STUDIO
@@ -38,7 +31,7 @@ void main()
fragColor.rgb = base_color;
#endif
- fragColor.rgb *= get_shadow(N);
+ fragColor.rgb *= get_shadow(N, forceShadowing);
fragColor.a = 1.0;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
index a4d81393dbc..18a093275c5 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
@@ -1,6 +1,4 @@
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
-
float curvature_soft_clamp(float curvature, float control)
{
if (curvature < 0.5 / control) {
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
index 328d50e69e0..59222b588a0 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
@@ -4,14 +4,6 @@
#pragma BLENDER_REQUIRE(workbench_cavity_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_curvature_lib.glsl)
-uniform sampler2D depthBuffer;
-uniform sampler2D normalBuffer;
-uniform usampler2D objectIdBuffer;
-
-in vec4 uvcoordsvar;
-
-out vec4 fragColor;
-
void main()
{
float cavity = 0.0, edges = 0.0, curvature = 0.0;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
index c4580e6ffc3..e9525ce9de0 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
@@ -7,19 +7,6 @@
* Converted and adapted from HLSL to GLSL by Clément Foucault
*/
-uniform vec2 invertedViewportSize;
-uniform vec2 nearFar;
-uniform vec3 dofParams;
-uniform float noiseOffset;
-uniform sampler2D inputCocTex;
-uniform sampler2D maxCocTilesTex;
-uniform sampler2D sceneColorTex;
-uniform sampler2D sceneDepthTex;
-uniform sampler2D backgroundTex;
-uniform sampler2D halfResColorTex;
-uniform sampler2D blurTex;
-uniform sampler2D noiseTex;
-
#define dof_aperturesize dofParams.x
#define dof_distance dofParams.y
#define dof_invsensorsize dofParams.z
@@ -53,9 +40,6 @@ float decode_signed_coc(vec2 cocs)
*/
#ifdef PREPARE
-layout(location = 0) out vec4 halfResColor;
-layout(location = 1) out vec2 normalizedCoc;
-
void main()
{
ivec4 texel = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
@@ -99,9 +83,6 @@ void main()
*/
#ifdef DOWNSAMPLE
-layout(location = 0) out vec4 outColor;
-layout(location = 1) out vec2 outCocs;
-
void main()
{
vec4 texel = vec4(gl_FragCoord.xyxy) * 2.0 + vec4(0.0, 0.0, 1.0, 1.0);
@@ -216,14 +197,6 @@ void main()
* Outputs vertical blur and combined blur in MRT
*/
#ifdef BLUR1
-layout(location = 0) out vec4 blurColor;
-
-# define NUM_SAMPLES 49
-
-layout(std140) uniform dofSamplesBlock
-{
- vec4 samples[NUM_SAMPLES];
-};
vec2 get_random_vector(float offset)
{
@@ -308,7 +281,6 @@ void main()
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef BLUR2
-out vec4 finalColor;
void main()
{
@@ -385,9 +357,6 @@ void main()
*/
#ifdef RESOLVE
-layout(location = 0, index = 0) out vec4 finalColorAdd;
-layout(location = 0, index = 1) out vec4 finalColorMul;
-
void main()
{
/* Fullscreen pass */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl
index fb6fdb93462..5d74933abf4 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl
@@ -1,12 +1,4 @@
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
-
-uniform usampler2D objectIdBuffer;
-
-in vec4 uvcoordsvar;
-
-out vec4 fragColor;
-
void main()
{
vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl
index 9797a5e3301..8b9e3f968ea 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl
@@ -1,50 +1,35 @@
-uniform sampler2D edgesTex;
-uniform sampler2D areaTex;
-uniform sampler2D searchTex;
-uniform sampler2D blendTex;
-uniform sampler2D colorTex;
-uniform float mixFactor;
-uniform float taaAccumulatedWeight;
-
-in vec2 uvs;
-in vec2 pixcoord;
-in vec4 offset[3];
-
-#if SMAA_STAGE == 0
-out vec2 fragColor;
-#else
-out vec4 fragColor;
-#endif
+#pragma BLENDER_REQUIRE(common_smaa_lib.glsl)
void main()
{
#if SMAA_STAGE == 0
/* Detect edges in color and revealage buffer. */
- fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex);
+ out_edges = SMAALumaEdgeDetectionPS(uvs, offset, colorTex);
/* Discard if there is no edge. */
- if (dot(fragColor, float2(1.0, 1.0)) == 0.0) {
+ if (dot(out_edges, float2(1.0, 1.0)) == 0.0) {
discard;
}
#elif SMAA_STAGE == 1
- fragColor = SMAABlendingWeightCalculationPS(
+ out_weights = SMAABlendingWeightCalculationPS(
uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0));
#elif SMAA_STAGE == 2
- fragColor = vec4(0.0);
+ out_color = vec4(0.0);
if (mixFactor > 0.0) {
- fragColor += SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex) * mixFactor;
+ out_color += SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex) * mixFactor;
}
if (mixFactor < 1.0) {
- fragColor += texture(colorTex, uvs) * (1.0 - mixFactor);
+ out_color += texture(colorTex, uvs) * (1.0 - mixFactor);
}
- fragColor /= taaAccumulatedWeight;
- fragColor = exp2(fragColor) - 0.5;
+ out_color /= taaAccumulatedWeight;
+ /* Exit log2 space used for Antialiasing. */
+ out_color = exp2(out_color) - 0.5;
/* Avoid float precision issue. */
- if (fragColor.a > 0.999) {
- fragColor.a = 1.0;
+ if (out_color.a > 0.999) {
+ out_color.a = 1.0;
}
#endif
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl
index 07734d19972..b76433a23e5 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl
@@ -1,7 +1,5 @@
-out vec2 uvs;
-out vec2 pixcoord;
-out vec4 offset[3];
+#pragma BLENDER_REQUIRE(common_smaa_lib.glsl)
void main()
{
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
index d021e4696f7..0c4dee11756 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl
@@ -1,9 +1,4 @@
-uniform sampler2D colorBuffer;
-uniform float samplesWeights[9];
-
-out vec4 fragColor;
-
void main()
{
vec2 texel_size = 1.0 / vec2(textureSize(colorBuffer, 0));
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
index 57d648d3565..78782bdc777 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
@@ -25,13 +25,6 @@ bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
return true;
}
-uniform sampler2DArray imageTileArray;
-uniform sampler1DArray imageTileData;
-uniform sampler2D imageTexture;
-
-uniform float imageTransparencyCutoff = 0.1;
-uniform bool imagePremult;
-
vec3 workbench_image_color(vec2 uvs)
{
#ifdef V3D_SHADING_TEXTURE_COLOR
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl
index 2d18cc1b014..a0cec54251d 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl
@@ -1,6 +1,4 @@
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
-
vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
{
/* Quick creation of an orthonormal basis */
@@ -15,16 +13,14 @@ vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped)
return matcap_uv * 0.496 + 0.5;
}
-uniform sampler2D matcapDiffuseImage;
-uniform sampler2D matcapSpecularImage;
-
-vec3 get_matcap_lighting(vec3 base_color, vec3 N, vec3 I)
+vec3 get_matcap_lighting(
+ sampler2D diffuse_matcap, sampler2D specular_matcap, vec3 base_color, vec3 N, vec3 I)
{
bool flipped = world_data.matcap_orientation != 0;
vec2 uv = matcap_uv_compute(I, N, flipped);
- vec3 diffuse = textureLod(matcapDiffuseImage, uv, 0.0).rgb;
- vec3 specular = textureLod(matcapSpecularImage, uv, 0.0).rgb;
+ vec3 diffuse = textureLod(diffuse_matcap, uv, 0.0).rgb;
+ vec3 specular = textureLod(specular_matcap, uv, 0.0).rgb;
return diffuse * base_color + specular * float(world_data.use_specular);
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl
index 1d8950e34b3..b6dc26ecc65 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl
@@ -1,17 +1,9 @@
-layout(std140) uniform material_block
-{
- vec4 mat_data[4096];
-};
-
-/* If set to -1, the resource handle is used instead. */
-uniform int materialIndex;
-
void workbench_material_data_get(
int handle, out vec3 color, out float alpha, out float roughness, out float metallic)
{
handle = (materialIndex != -1) ? materialIndex : handle;
- vec4 data = mat_data[uint(handle) & 0xFFFu];
+ vec4 data = materials_data[uint(handle) & 0xFFFu];
color = data.rgb;
uint encoded_data = floatBitsToUint(data.w);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
index 856654549ca..ae564435258 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
@@ -1,10 +1,4 @@
-uniform sampler2D depthBuffer;
-
-in vec4 uvcoordsvar;
-
-out vec4 fragColor;
-
void main()
{
float depth = texture(depthBuffer, uvcoordsvar.st).r;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
index 6d24b001d4d..1b20171b3ff 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl
@@ -1,20 +1,13 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
-layout(location = 0) out vec4 materialData;
-layout(location = 1) out WB_Normal normalData;
-layout(location = 2) out uint objectId;
-
-uniform bool useMatcap = false;
-
void main()
{
normalData = workbench_normal_encode(gl_FrontFacing, normal_interp);
- materialData = vec4(color_interp, packed_rough_metal);
+ materialData = vec4(color_interp, workbench_float_pair_encode(roughness, metallic));
objectId = uint(object_id);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl
index 3e1ea14f47c..65b9f4de4b6 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl
@@ -1,13 +1,10 @@
#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
-uniform samplerBuffer ac; /* active color layer */
-uniform samplerBuffer au; /* active texture layer */
-
/* From http://libnoise.sourceforge.net/noisegen/index.html */
float integer_noise(int n)
{
@@ -63,17 +60,12 @@ void main()
float hair_rand = integer_noise(hair_get_strand_id());
vec3 nor = workbench_hair_random_normal(tan, binor, hair_rand);
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
+ view_clipping_distances(world_pos);
uv_interp = hair_get_customdata_vec2(au);
normal_interp = normalize(normal_world_to_view(nor));
-#ifdef OPAQUE_MATERIAL
- float metallic, roughness;
-#endif
workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
if (materialIndex == 0) {
@@ -86,9 +78,5 @@ void main()
workbench_hair_random_material(hair_rand, color_interp, roughness, metallic);
-#ifdef OPAQUE_MATERIAL
- packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
-#endif
-
object_id = int(uint(resource_handle) & 0xFFFFu) + 1;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl
index 6f61874b8f5..911d6f5b036 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_pointcloud_vert.glsl
@@ -1,7 +1,7 @@
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
@@ -15,24 +15,15 @@ void main()
gl_Position = point_world_to_ndc(world_pos);
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
+ view_clipping_distances(world_pos);
uv_interp = vec2(0.0);
-#ifdef OPAQUE_MATERIAL
- float metallic, roughness;
-#endif
workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
if (materialIndex == 0) {
color_interp = vec3(1.0);
}
-#ifdef OPAQUE_MATERIAL
- packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
-#endif
-
object_id = int(uint(resource_handle) & 0xFFFFu) + 1;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
index 1192081caf1..3a63b141c5f 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl
@@ -1,40 +1,26 @@
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_material_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
-in vec3 pos;
-in vec3 nor;
-in vec4 ac; /* active color */
-in vec2 au; /* active texture layer */
-
void main()
{
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance(world_pos);
-#endif
+ view_clipping_distances(world_pos);
uv_interp = au;
normal_interp = normalize(normal_object_to_view(nor));
-#ifdef OPAQUE_MATERIAL
- float metallic, roughness;
-#endif
workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic);
if (materialIndex == 0) {
color_interp = ac.rgb;
}
-#ifdef OPAQUE_MATERIAL
- packed_rough_metal = workbench_float_pair_encode(roughness, metallic);
-#endif
-
object_id = int(uint(resource_handle) & 0xFFFFu) + 1;
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl
deleted file mode 100644
index 6bfa351aeb0..00000000000
--- a/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl
+++ /dev/null
@@ -1,15 +0,0 @@
-
-IN_OUT ShaderStageInterface
-{
- vec3 normal_interp;
- vec3 color_interp;
- float alpha_interp;
- vec2 uv_interp;
-#ifdef TRANSPARENT_MATERIAL
- flat float roughness;
- flat float metallic;
-#else
- flat float packed_rough_metal;
-#endif
- flat int object_id;
-};
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl
index 09bafb8ff11..4a7b1522426 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_caps_geom.glsl
@@ -1,41 +1,7 @@
-#extension GL_ARB_gpu_shader5 : enable
-
-#ifdef GL_ARB_gpu_shader5
+#ifdef GPU_ARB_gpu_shader5
# define USE_INVOC_EXT
#endif
-#ifdef DOUBLE_MANIFOLD
-# ifdef USE_INVOC_EXT
-# define invoc_len 2
-# else
-# define vert_len 6
-# endif
-#else
-# ifdef USE_INVOC_EXT
-# define invoc_len 2
-# else
-# define vert_len 6
-# endif
-#endif
-
-#ifdef USE_INVOC_EXT
-layout(triangles, invocations = invoc_len) in;
-layout(triangle_strip, max_vertices = 3) out;
-#else
-layout(triangles) in;
-layout(triangle_strip, max_vertices = vert_len) out;
-#endif
-
-uniform vec3 lightDirection = vec3(0.57, 0.57, -0.57);
-
-in VertexData
-{
- vec3 pos; /* local position */
- vec4 frontPosition; /* final ndc position */
- vec4 backPosition;
-}
-vData[];
-
vec4 get_pos(int v, bool backface)
{
return (backface) ? vData[v].backPosition : vData[v].frontPosition;
@@ -76,18 +42,19 @@ void main()
/* In case of non manifold geom, we only increase/decrease
* the stencil buffer by one but do every faces as they were facing the light. */
bool invert = backface;
+ const bool is_manifold = false;
#else
const bool invert = false;
- if (!backface) {
+ const bool is_manifold = true;
#endif
+
+ if (!is_manifold || !backface) {
#ifdef USE_INVOC_EXT
- bool do_front = (gl_InvocationID & 1) == 0;
- emit_cap(do_front, invert);
+ bool do_front = (gl_InvocationID & 1) == 0;
+ emit_cap(do_front, invert);
#else
emit_cap(true, invert);
emit_cap(false, invert);
#endif
-#ifndef DOUBLE_MANIFOLD
-}
-#endif
+ }
}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl
index 6fa76510e6e..c9977a8d91a 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl
@@ -1,10 +1,4 @@
-out vec4 fragColor;
-
-layout(location = 0) out vec4 materialData;
-layout(location = 1) out vec4 normalData;
-layout(location = 2) out uint objectId;
-
void main()
{
const float a = 0.25;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl
index 2c9190bfcf4..9902884fc12 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_geom.glsl
@@ -1,41 +1,7 @@
-#extension GL_ARB_gpu_shader5 : enable
-
-#ifdef GL_ARB_gpu_shader5
+#ifdef GPU_ARB_gpu_shader5
# define USE_INVOC_EXT
#endif
-#ifdef DOUBLE_MANIFOLD
-# ifdef USE_INVOC_EXT
-# define invoc_len 2
-# else
-# define vert_len 8
-# endif
-#else
-# ifdef USE_INVOC_EXT
-# define invoc_len 1
-# else
-# define vert_len 4
-# endif
-#endif
-
-#ifdef USE_INVOC_EXT
-layout(lines_adjacency, invocations = invoc_len) in;
-layout(triangle_strip, max_vertices = 4) out;
-#else
-layout(lines_adjacency) in;
-layout(triangle_strip, max_vertices = vert_len) out;
-#endif
-
-uniform vec3 lightDirection = vec3(0.57, 0.57, -0.57);
-
-in VertexData
-{
- vec3 pos; /* local position */
- vec4 frontPosition; /* final ndc position */
- vec4 backPosition;
-}
-vData[];
-
#define DEGENERATE_TRIS_WORKAROUND
#define DEGENERATE_TRIS_AREA_THRESHOLD 4e-17
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl
index e07f87525e2..a220434ec45 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl
@@ -1,17 +1,5 @@
-#define INFINITE 1000.0
-uniform vec3 lightDirection = vec3(0.57, 0.57, -0.57);
-uniform float lightDistance = 1e4;
-
-in vec3 pos;
-
-out VertexData
-{
- vec3 pos; /* local position */
- vec4 frontPosition; /* final ndc position */
- vec4 backPosition;
-}
-vData;
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
void main()
{
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 3f113fd4b2e..9c0f93c67d9 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
@@ -1,19 +1,10 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_image_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl)
-/* Revealage is actually stored in transparentAccum alpha channel.
- * This is a workaround to older hardware not having separate blend equation per render target. */
-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. */
-layout(location = 2) out uint objectId;
-
/* Special function only to be used with calculate_transparent_weight(). */
float linear_zdepth(float depth, vec4 viewvecs[2], mat4 proj_mat)
{
@@ -67,7 +58,7 @@ void main()
#endif
#ifdef V3D_LIGHTING_MATCAP
- vec3 shaded_color = get_matcap_lighting(color, N, I);
+ vec3 shaded_color = get_matcap_lighting(matcap_diffuse_tx, matcap_specular_tx, color, N, I);
#endif
#ifdef V3D_LIGHTING_STUDIO
@@ -78,7 +69,7 @@ void main()
vec3 shaded_color = color;
#endif
- shaded_color *= get_shadow(N);
+ shaded_color *= get_shadow(N, forceShadowing);
/* Listing 4 */
float weight = calculate_transparent_weight() * alpha_interp;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
index d985737a35b..a2c45d2f8e3 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
@@ -1,11 +1,4 @@
-uniform sampler2D transparentAccum;
-uniform sampler2D transparentRevealage;
-
-in vec4 uvcoordsvar;
-
-out vec4 fragColor;
-
/* Based on :
* McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of
* Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
index 48102b4dcca..076f6e80104 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -1,40 +1,8 @@
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl)
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
#pragma BLENDER_REQUIRE(workbench_common_lib.glsl)
-uniform sampler2D depthBuffer;
-
-uniform sampler3D densityTexture;
-uniform sampler3D shadowTexture;
-uniform sampler3D flameTexture;
-uniform usampler3D flagTexture;
-uniform sampler1D flameColorTexture;
-uniform sampler1D transferTexture;
-uniform mat4 volumeObjectToTexture;
-
-uniform int samplesLen = 256;
-uniform float noiseOfs = 0.0;
-uniform float stepLength; /* Step length in local space. */
-uniform float densityScale; /* Simple Opacity multiplicator. */
-uniform float gridScale; /* Multiplicator for grid scaling. */
-uniform vec3 activeColor;
-
-uniform float slicePosition;
-uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
-
-uniform bool showPhi = false;
-uniform bool showFlags = false;
-uniform bool showPressure = false;
-
-#ifdef VOLUME_SLICE
-in vec3 localPos;
-#endif
-
-out vec4 fragColor;
-
float phase_function_isotropic()
{
return 1.0 / (4.0 * M_PI);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
index 7327a92e04f..d2b12f41421 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
@@ -1,22 +1,8 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl)
-
-uniform float slicePosition;
-uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */
-
-uniform mat4 volumeTextureToObject;
-
-in vec3 pos;
RESOURCE_ID_VARYING
-#ifdef VOLUME_SLICE
-in vec3 uvs;
-
-out vec3 localPos;
-#endif
-
void main()
{
#ifdef VOLUME_SLICE
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
index 41ef516ee4d..531ed461057 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
@@ -1,6 +1,4 @@
-#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
-
/* [Drobot2014a] Low Level Optimizations for GCN */
vec4 fast_rcp(vec4 v)
{
@@ -120,12 +118,10 @@ vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N
return diffuse_light + specular_light;
}
-uniform bool forceShadowing = false;
-
-float get_shadow(vec3 N)
+float get_shadow(vec3 N, bool force_shadowing)
{
float light_factor = -dot(N, world_data.shadow_direction_vs.xyz);
float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor);
- shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul;
+ shadow_mix *= force_shadowing ? 0.0 : world_data.shadow_mul;
return shadow_mix + world_data.shadow_add;
}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_cavity.c b/source/blender/draw/engines/workbench/workbench_effect_cavity.c
index b294b9a62ca..6ab74d179f6 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_cavity.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_cavity.c
@@ -165,7 +165,7 @@ void workbench_cavity_cache_init(WORKBENCH_Data *data)
grp = DRW_shgroup_create(sh, psl->cavity_ps);
DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx);
DRW_shgroup_uniform_block(grp, "samples_block", wpd->vldata->cavity_sample_ubo);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
if (SSAO_ENABLED(wpd)) {
DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth);
diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c
index 2261790226a..b5f43251a43 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_dof.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c
@@ -328,7 +328,7 @@ void workbench_dof_cache_init(WORKBENCH_Data *vedata)
float offset = wpd->taa_sample / (float)max_ii(1, wpd->taa_sample_len);
DRWShadingGroup *grp = DRW_shgroup_create(blur1_sh, psl->dof_blur1_ps);
- DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->vldata->dof_sample_ubo);
+ DRW_shgroup_uniform_block(grp, "samples", wpd->vldata->dof_sample_ubo);
DRW_shgroup_uniform_texture(grp, "noiseTex", wpd->vldata->cavity_jitter_tx);
DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
diff --git a/source/blender/draw/engines/workbench/workbench_effect_outline.c b/source/blender/draw/engines/workbench/workbench_effect_outline.c
index d1bc6b6c435..4f716c5a7bc 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_outline.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_outline.c
@@ -46,7 +46,7 @@ void workbench_outline_cache_init(WORKBENCH_Data *data)
grp = DRW_shgroup_create(sh, psl->outline_ps);
DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx);
DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
else {
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index 5bc2c53e253..0a0c20b0d6a 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -51,8 +51,6 @@ void workbench_engine_init(void *ved)
WORKBENCH_StorageList *stl = vedata->stl;
WORKBENCH_TextureList *txl = vedata->txl;
- workbench_shader_library_ensure();
-
workbench_private_data_alloc(stl);
WORKBENCH_PrivateData *wpd = stl->wpd;
workbench_private_data_init(wpd);
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index d70633eaa85..1b12e29617c 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -198,7 +198,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
}
DRWShadingGroup **grp_mat = NULL;
- /* A hashmap stores material shgroups to pack all similar drawcalls together. */
+ /* A hash-map stores material shgroups to pack all similar drawcalls together. */
if (BLI_ghash_ensure_p(prepass->material_hash, ma, (void ***)&grp_mat)) {
return *grp_mat;
}
@@ -210,7 +210,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp = prepass->common_shgrp;
*grp_mat = grp = DRW_shgroup_create_sub(grp);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", mat_id);
return grp;
}
@@ -234,7 +234,7 @@ DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd,
DRWShadingGroup **grp = &wpd->prepass[transp][infront][datatype].common_shgrp;
if (resource_changed) {
*grp = DRW_shgroup_create_sub(*grp);
- DRW_shgroup_uniform_block(*grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(*grp, "materials_data", wpd->material_ubo_curr);
}
if (r_transp && transp) {
*r_transp = true;
@@ -277,7 +277,7 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][datatype];
DRWShadingGroup **grp_tex = NULL;
- /* A hashmap stores image shgroups to pack all similar drawcalls together. */
+ /* A hash-map stores image shgroups to pack all similar drawcalls together. */
if (BLI_ghash_ensure_p(prepass->material_hash, tex, (void ***)&grp_tex)) {
return *grp_tex;
}
@@ -293,5 +293,6 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
DRW_shgroup_uniform_texture_ex(grp, "imageTexture", tex, sampler);
}
DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL));
+ DRW_shgroup_uniform_float_copy(grp, "imageTransparencyCutoff", 0.1f);
return grp;
}
diff --git a/source/blender/draw/engines/workbench/workbench_opaque.c b/source/blender/draw/engines/workbench/workbench_opaque.c
index 9fdefed019f..e4534d923ab 100644
--- a/source/blender/draw/engines/workbench/workbench_opaque.c
+++ b/source/blender/draw/engines/workbench/workbench_opaque.c
@@ -88,26 +88,26 @@ void workbench_opaque_cache_init(WORKBENCH_Data *vedata)
sh = workbench_shader_opaque_get(wpd, data);
wpd->prepass[opaque][infront][data].common_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1);
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
wpd->prepass[opaque][infront][data].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
sh = workbench_shader_opaque_image_get(wpd, data, false);
wpd->prepass[opaque][infront][data].image_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
sh = workbench_shader_opaque_image_get(wpd, data, true);
wpd->prepass[opaque][infront][data].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
}
@@ -121,7 +121,7 @@ void workbench_opaque_cache_init(WORKBENCH_Data *vedata)
sh = workbench_shader_composite_get(wpd);
grp = DRW_shgroup_create(sh, psl->composite_ps);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_texture(grp, "materialBuffer", wpd->material_buffer_tx);
DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx);
DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false);
@@ -135,8 +135,8 @@ void workbench_opaque_cache_init(WORKBENCH_Data *vedata)
struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
- DRW_shgroup_uniform_texture(grp, "matcapDiffuseImage", diff_tx);
- DRW_shgroup_uniform_texture(grp, "matcapSpecularImage", spec_tx);
+ DRW_shgroup_uniform_texture(grp, "matcap_diffuse_tx", diff_tx);
+ DRW_shgroup_uniform_texture(grp, "matcap_specular_tx", spec_tx);
}
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index 42c873c7691..2cf96a8e139 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -423,7 +423,7 @@ void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data);
/* workbench_shadow.c */
void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd);
void workbench_shadow_cache_init(WORKBENCH_Data *data);
-void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat);
+void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, bool has_transp_mat);
/* workbench_shader.c */
GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, eWORKBENCH_DataType data);
@@ -459,7 +459,6 @@ void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
GPUShader **blur2_sh,
GPUShader **resolve_sh);
-void workbench_shader_library_ensure(void);
void workbench_shader_free(void);
/* workbench_effect_antialiasing.c */
diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c
deleted file mode 100644
index ad610a6a885..00000000000
--- a/source/blender/draw/engines/workbench/workbench_shader.c
+++ /dev/null
@@ -1,562 +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.
- *
- * Copyright 2020, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw_engine
- */
-
-#include "DRW_render.h"
-
-#include "BLI_dynstr.h"
-#include "BLI_string_utils.h"
-
-#include "workbench_engine.h"
-#include "workbench_private.h"
-
-extern char datatoc_common_math_lib_glsl[];
-extern char datatoc_common_math_geom_lib_glsl[];
-extern char datatoc_common_hair_lib_glsl[];
-extern char datatoc_common_pointcloud_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-extern char datatoc_common_smaa_lib_glsl[];
-
-extern char datatoc_workbench_prepass_vert_glsl[];
-extern char datatoc_workbench_prepass_hair_vert_glsl[];
-extern char datatoc_workbench_prepass_pointcloud_vert_glsl[];
-extern char datatoc_workbench_prepass_frag_glsl[];
-
-extern char datatoc_workbench_effect_cavity_frag_glsl[];
-extern char datatoc_workbench_effect_outline_frag_glsl[];
-extern char datatoc_workbench_effect_dof_frag_glsl[];
-extern char datatoc_workbench_effect_taa_frag_glsl[];
-extern char datatoc_workbench_effect_smaa_frag_glsl[];
-extern char datatoc_workbench_effect_smaa_vert_glsl[];
-
-extern char datatoc_workbench_composite_frag_glsl[];
-
-extern char datatoc_workbench_transparent_accum_frag_glsl[];
-extern char datatoc_workbench_transparent_resolve_frag_glsl[];
-
-extern char datatoc_workbench_merge_infront_frag_glsl[];
-
-extern char datatoc_workbench_shadow_vert_glsl[];
-extern char datatoc_workbench_shadow_geom_glsl[];
-extern char datatoc_workbench_shadow_caps_geom_glsl[];
-extern char datatoc_workbench_shadow_debug_frag_glsl[];
-
-extern char datatoc_workbench_volume_vert_glsl[];
-extern char datatoc_workbench_volume_frag_glsl[];
-
-extern char datatoc_workbench_cavity_lib_glsl[];
-extern char datatoc_workbench_common_lib_glsl[];
-extern char datatoc_workbench_curvature_lib_glsl[];
-extern char datatoc_workbench_data_lib_glsl[];
-extern char datatoc_workbench_image_lib_glsl[];
-extern char datatoc_workbench_matcap_lib_glsl[];
-extern char datatoc_workbench_material_lib_glsl[];
-extern char datatoc_workbench_shader_interface_lib_glsl[];
-extern char datatoc_workbench_world_light_lib_glsl[];
-
-extern char datatoc_gpu_shader_depth_only_frag_glsl[];
-extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
-
-/* Maximum number of variations. */
-#define MAX_LIGHTING 3
-#define MAX_COLOR 3
-
-enum {
- VOLUME_SH_SLICE = 0,
- VOLUME_SH_COBA,
- VOLUME_SH_CUBIC,
-};
-
-#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1))
-
-static struct {
- struct GPUShader *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX][MAX_COLOR];
- struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX]
- [MAX_LIGHTING][MAX_COLOR];
-
- struct GPUShader *opaque_composite_sh[MAX_LIGHTING];
- struct GPUShader *oit_resolve_sh;
- struct GPUShader *outline_sh;
- struct GPUShader *merge_infront_sh;
-
- struct GPUShader *shadow_depth_pass_sh[2];
- struct GPUShader *shadow_depth_fail_sh[2][2];
-
- struct GPUShader *cavity_sh[2][2];
-
- struct GPUShader *dof_prepare_sh;
- struct GPUShader *dof_downsample_sh;
- struct GPUShader *dof_blur1_sh;
- struct GPUShader *dof_blur2_sh;
- struct GPUShader *dof_resolve_sh;
-
- struct GPUShader *aa_accum_sh;
- struct GPUShader *smaa_sh[3];
-
- struct GPUShader *volume_sh[2][2][3][2];
-
- struct DRWShaderLibrary *lib;
-} e_data = {{{{NULL}}}};
-
-void workbench_shader_library_ensure(void)
-{
- if (e_data.lib == NULL) {
- e_data.lib = DRW_shader_library_create();
- /* NOTE: These need to be ordered by dependencies. */
- DRW_SHADER_LIB_ADD(e_data.lib, common_math_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, common_math_geom_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, common_hair_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, common_pointcloud_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_shader_interface_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_common_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_image_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_material_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_data_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_matcap_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_cavity_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_curvature_lib);
- DRW_SHADER_LIB_ADD(e_data.lib, workbench_world_light_lib);
- }
-}
-
-static char *workbench_build_defines(
- WORKBENCH_PrivateData *wpd, bool textured, bool tiled, bool cavity, bool curvature)
-{
- char *str = NULL;
-
- DynStr *ds = BLI_dynstr_new();
-
- if (wpd && wpd->shading.light == V3D_LIGHTING_STUDIO) {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n");
- }
- else if (wpd && wpd->shading.light == V3D_LIGHTING_MATCAP) {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n");
- }
- else {
- BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n");
- }
-
- if (NORMAL_ENCODING_ENABLED()) {
- BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n");
- }
-
- if (textured) {
- BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n");
- }
- if (tiled) {
- BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n");
- }
- if (cavity) {
- BLI_dynstr_append(ds, "#define USE_CAVITY\n");
- }
- if (curvature) {
- BLI_dynstr_append(ds, "#define USE_CURVATURE\n");
- }
-
- str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
- return str;
-}
-
-static int workbench_color_index(WORKBENCH_PrivateData *UNUSED(wpd), bool textured, bool tiled)
-{
- BLI_assert(2 < MAX_COLOR);
- return (textured) ? (tiled ? 2 : 1) : 0;
-}
-
-static GPUShader *workbench_shader_get_ex(WORKBENCH_PrivateData *wpd,
- bool transp,
- eWORKBENCH_DataType datatype,
- bool textured,
- bool tiled)
-{
- int color = workbench_color_index(wpd, textured, tiled);
- int light = wpd->shading.light;
- BLI_assert(light < MAX_LIGHTING);
- struct GPUShader **shader =
- (transp) ? &e_data.transp_prepass_sh_cache[wpd->sh_cfg][datatype][light][color] :
- &e_data.opaque_prepass_sh_cache[wpd->sh_cfg][datatype][color];
-
- if (*shader == NULL) {
- char *defines = workbench_build_defines(wpd, textured, tiled, false, false);
-
- char *frag_file = transp ? datatoc_workbench_transparent_accum_frag_glsl :
- datatoc_workbench_prepass_frag_glsl;
- char *frag_src = DRW_shader_library_create_shader_string(e_data.lib, frag_file);
-
- char *vert_file = (datatype == WORKBENCH_DATATYPE_HAIR) ?
- datatoc_workbench_prepass_hair_vert_glsl :
- ((datatype == WORKBENCH_DATATYPE_POINTCLOUD) ?
- datatoc_workbench_prepass_pointcloud_vert_glsl :
- datatoc_workbench_prepass_vert_glsl);
- char *vert_src = DRW_shader_library_create_shader_string(e_data.lib, vert_file);
-
- const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[wpd->sh_cfg];
-
- *shader = GPU_shader_create_from_arrays({
- .vert = (const char *[]){sh_cfg_data->lib, vert_src, NULL},
- .frag = (const char *[]){frag_src, NULL},
- .defs = (const char *[]){sh_cfg_data->def,
- defines,
- transp ? "#define TRANSPARENT_MATERIAL\n" :
- "#define OPAQUE_MATERIAL\n",
- (datatype == WORKBENCH_DATATYPE_POINTCLOUD) ?
- "#define UNIFORM_RESOURCE_ID\n"
- "#define INSTANCED_ATTR\n" :
- NULL,
- NULL},
- });
-
- MEM_freeN(defines);
- MEM_freeN(frag_src);
- MEM_freeN(vert_src);
- }
- return *shader;
-}
-
-GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, eWORKBENCH_DataType datatype)
-{
- return workbench_shader_get_ex(wpd, false, datatype, false, false);
-}
-
-GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd,
- eWORKBENCH_DataType datatype,
- bool tiled)
-{
- return workbench_shader_get_ex(wpd, false, datatype, true, tiled);
-}
-
-GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd,
- eWORKBENCH_DataType datatype)
-{
- return workbench_shader_get_ex(wpd, true, datatype, false, false);
-}
-
-GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
- eWORKBENCH_DataType datatype,
- bool tiled)
-{
- return workbench_shader_get_ex(wpd, true, datatype, true, tiled);
-}
-
-GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd)
-{
- int light = wpd->shading.light;
- struct GPUShader **shader = &e_data.opaque_composite_sh[light];
- BLI_assert(light < MAX_LIGHTING);
-
- if (*shader == NULL) {
- char *defines = workbench_build_defines(wpd, false, false, false, false);
- char *frag = DRW_shader_library_create_shader_string(e_data.lib,
- datatoc_workbench_composite_frag_glsl);
-
- *shader = DRW_shader_create_fullscreen(frag, defines);
-
- MEM_freeN(defines);
- MEM_freeN(frag);
- }
- return *shader;
-}
-
-GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *UNUSED(wpd))
-{
- if (e_data.merge_infront_sh == NULL) {
- char *frag = DRW_shader_library_create_shader_string(
- e_data.lib, datatoc_workbench_merge_infront_frag_glsl);
-
- e_data.merge_infront_sh = DRW_shader_create_fullscreen(frag, NULL);
-
- MEM_freeN(frag);
- }
- return e_data.merge_infront_sh;
-}
-
-GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd)
-{
- if (e_data.oit_resolve_sh == NULL) {
- char *defines = workbench_build_defines(wpd, false, false, false, false);
-
- e_data.oit_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_workbench_transparent_resolve_frag_glsl, defines);
-
- MEM_freeN(defines);
- }
- return e_data.oit_resolve_sh;
-}
-
-static GPUShader *workbench_shader_shadow_pass_get_ex(bool depth_pass, bool manifold, bool cap)
-{
- struct GPUShader **shader = (depth_pass) ? &e_data.shadow_depth_pass_sh[manifold] :
- &e_data.shadow_depth_fail_sh[manifold][cap];
-
- if (*shader == NULL) {
-#if DEBUG_SHADOW_VOLUME
- const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl;
-#else
- const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl;
-#endif
-
- *shader = GPU_shader_create_from_arrays({
- .vert = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_workbench_shadow_vert_glsl,
- NULL},
- .geom = (const char *[]){(cap) ? datatoc_workbench_shadow_caps_geom_glsl :
- datatoc_workbench_shadow_geom_glsl,
- NULL},
- .frag = (const char *[]){shadow_frag, NULL},
- .defs = (const char *[]){(depth_pass) ? "#define SHADOW_PASS\n" : "#define SHADOW_FAIL\n",
- (manifold) ? "" : "#define DOUBLE_MANIFOLD\n",
- NULL},
- });
- }
- return *shader;
-}
-
-GPUShader *workbench_shader_shadow_pass_get(bool manifold)
-{
- return workbench_shader_shadow_pass_get_ex(true, manifold, false);
-}
-
-GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap)
-{
- return workbench_shader_shadow_pass_get_ex(false, manifold, cap);
-}
-
-GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature)
-{
- BLI_assert(cavity || curvature);
- struct GPUShader **shader = &e_data.cavity_sh[cavity][curvature];
-
- if (*shader == NULL) {
- char *defines = workbench_build_defines(NULL, false, false, cavity, curvature);
- char *frag = DRW_shader_library_create_shader_string(
- e_data.lib, datatoc_workbench_effect_cavity_frag_glsl);
-
- *shader = DRW_shader_create_fullscreen(frag, defines);
-
- MEM_freeN(defines);
- MEM_freeN(frag);
- }
- return *shader;
-}
-
-GPUShader *workbench_shader_outline_get(void)
-{
- if (e_data.outline_sh == NULL) {
- char *frag = DRW_shader_library_create_shader_string(
- e_data.lib, datatoc_workbench_effect_outline_frag_glsl);
-
- e_data.outline_sh = DRW_shader_create_fullscreen(frag, NULL);
-
- MEM_freeN(frag);
- }
- return e_data.outline_sh;
-}
-
-void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
- GPUShader **downsample_sh,
- GPUShader **blur1_sh,
- GPUShader **blur2_sh,
- GPUShader **resolve_sh)
-{
- if (e_data.dof_prepare_sh == NULL) {
- e_data.dof_prepare_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define PREPARE\n");
- e_data.dof_downsample_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define DOWNSAMPLE\n");
-#if 0 /* TODO(fclem): finish COC min_max optimization */
- e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define FLATTEN_VERTICAL\n");
- e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define FLATTEN_HORIZONTAL\n");
- e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define DILATE_VERTICAL\n");
- e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define DILATE_HORIZONTAL\n");
-#endif
- e_data.dof_blur1_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define BLUR1\n");
- e_data.dof_blur2_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define BLUR2\n");
- e_data.dof_resolve_sh = DRW_shader_create_fullscreen_with_shaderlib(
- datatoc_workbench_effect_dof_frag_glsl, e_data.lib, "#define RESOLVE\n");
- }
-
- *prepare_sh = e_data.dof_prepare_sh;
- *downsample_sh = e_data.dof_downsample_sh;
- *blur1_sh = e_data.dof_blur1_sh;
- *blur2_sh = e_data.dof_blur2_sh;
- *resolve_sh = e_data.dof_resolve_sh;
-}
-
-GPUShader *workbench_shader_antialiasing_accumulation_get(void)
-{
- if (e_data.aa_accum_sh == NULL) {
- char *frag = DRW_shader_library_create_shader_string(e_data.lib,
- datatoc_workbench_effect_taa_frag_glsl);
-
- e_data.aa_accum_sh = DRW_shader_create_fullscreen(frag, NULL);
-
- MEM_freeN(frag);
- }
- return e_data.aa_accum_sh;
-}
-
-GPUShader *workbench_shader_antialiasing_get(int stage)
-{
- BLI_assert(stage < 3);
- if (!e_data.smaa_sh[stage]) {
- char stage_define[32];
- BLI_snprintf(stage_define, sizeof(stage_define), "#define SMAA_STAGE %d\n", stage);
-
- e_data.smaa_sh[stage] = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){
- "#define SMAA_INCLUDE_VS 1\n",
- "#define SMAA_INCLUDE_PS 0\n",
- "uniform vec4 viewportMetrics;\n",
- datatoc_common_smaa_lib_glsl,
- datatoc_workbench_effect_smaa_vert_glsl,
- NULL,
- },
- .frag =
- (const char *[]){
- "#define SMAA_INCLUDE_VS 0\n",
- "#define SMAA_INCLUDE_PS 1\n",
- "uniform vec4 viewportMetrics;\n",
- datatoc_common_smaa_lib_glsl,
- datatoc_workbench_effect_smaa_frag_glsl,
- NULL,
- },
- .defs =
- (const char *[]){
- "#define SMAA_GLSL_3\n",
- "#define SMAA_RT_METRICS viewportMetrics\n",
- "#define SMAA_PRESET_HIGH\n",
- "#define SMAA_LUMA_WEIGHT float4(1.0, 1.0, 1.0, 1.0)\n",
- "#define SMAA_NO_DISCARD\n",
- stage_define,
- NULL,
- },
- });
- }
- return e_data.smaa_sh[stage];
-}
-
-GPUShader *workbench_shader_volume_get(bool slice,
- bool coba,
- eWORKBENCH_VolumeInterpType interp_type,
- bool smoke)
-{
- GPUShader **shader = &e_data.volume_sh[slice][coba][interp_type][smoke];
-
- if (*shader == NULL) {
- DynStr *ds = BLI_dynstr_new();
-
- if (slice) {
- BLI_dynstr_append(ds, "#define VOLUME_SLICE\n");
- }
- if (coba) {
- BLI_dynstr_append(ds, "#define USE_COBA\n");
- }
- switch (interp_type) {
- case WORKBENCH_VOLUME_INTERP_LINEAR:
- BLI_dynstr_append(ds, "#define USE_TRILINEAR\n");
- break;
- case WORKBENCH_VOLUME_INTERP_CUBIC:
- BLI_dynstr_append(ds, "#define USE_TRICUBIC\n");
- break;
- case WORKBENCH_VOLUME_INTERP_CLOSEST:
- BLI_dynstr_append(ds, "#define USE_CLOSEST\n");
- break;
- }
- if (smoke) {
- BLI_dynstr_append(ds, "#define VOLUME_SMOKE\n");
- }
-
- char *defines = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- char *vert = DRW_shader_library_create_shader_string(e_data.lib,
- datatoc_workbench_volume_vert_glsl);
- char *frag = DRW_shader_library_create_shader_string(e_data.lib,
- datatoc_workbench_volume_frag_glsl);
-
- *shader = DRW_shader_create(vert, NULL, frag, defines);
-
- MEM_freeN(vert);
- MEM_freeN(frag);
- MEM_freeN(defines);
- }
- return *shader;
-}
-
-void workbench_shader_free(void)
-{
- for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) {
- struct GPUShader **sh_array = &e_data.opaque_prepass_sh_cache[0][0][0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < sizeof(e_data.transp_prepass_sh_cache) / sizeof(void *); j++) {
- struct GPUShader **sh_array = &e_data.transp_prepass_sh_cache[0][0][0][0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < ARRAY_SIZE(e_data.opaque_composite_sh); j++) {
- struct GPUShader **sh_array = &e_data.opaque_composite_sh[0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < ARRAY_SIZE(e_data.shadow_depth_pass_sh); j++) {
- struct GPUShader **sh_array = &e_data.shadow_depth_pass_sh[0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < sizeof(e_data.shadow_depth_fail_sh) / sizeof(void *); j++) {
- struct GPUShader **sh_array = &e_data.shadow_depth_fail_sh[0][0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < sizeof(e_data.cavity_sh) / sizeof(void *); j++) {
- struct GPUShader **sh_array = &e_data.cavity_sh[0][0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < ARRAY_SIZE(e_data.smaa_sh); j++) {
- struct GPUShader **sh_array = &e_data.smaa_sh[0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
- for (int j = 0; j < sizeof(e_data.volume_sh) / sizeof(void *); j++) {
- struct GPUShader **sh_array = &e_data.volume_sh[0][0][0][0];
- DRW_SHADER_FREE_SAFE(sh_array[j]);
- }
-
- DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh);
- DRW_SHADER_FREE_SAFE(e_data.outline_sh);
- DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh);
-
- DRW_SHADER_FREE_SAFE(e_data.dof_prepare_sh);
- DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
- DRW_SHADER_FREE_SAFE(e_data.dof_blur1_sh);
- DRW_SHADER_FREE_SAFE(e_data.dof_blur2_sh);
- DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh);
-
- DRW_SHADER_FREE_SAFE(e_data.aa_accum_sh);
-
- DRW_SHADER_LIB_FREE_SAFE(e_data.lib);
-}
diff --git a/source/blender/draw/engines/workbench/workbench_shader.cc b/source/blender/draw/engines/workbench/workbench_shader.cc
new file mode 100644
index 00000000000..011a3fd3b13
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_shader.cc
@@ -0,0 +1,398 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include <string>
+
+#include "workbench_engine.h"
+#include "workbench_private.h"
+
+/* Maximum number of variations. */
+#define MAX_LIGHTING 3
+
+enum eWORKBENCH_TextureType {
+ TEXTURE_SH_NONE = 0,
+ TEXTURE_SH_SINGLE,
+ TEXTURE_SH_TILED,
+ TEXTURE_SH_MAX,
+};
+
+static struct {
+ struct GPUShader
+ *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX][TEXTURE_SH_MAX];
+ struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][WORKBENCH_DATATYPE_MAX]
+ [MAX_LIGHTING][TEXTURE_SH_MAX];
+
+ struct GPUShader *opaque_composite_sh[MAX_LIGHTING];
+ struct GPUShader *oit_resolve_sh;
+ struct GPUShader *outline_sh;
+ struct GPUShader *merge_infront_sh;
+
+ struct GPUShader *shadow_depth_pass_sh[2];
+ struct GPUShader *shadow_depth_fail_sh[2][2];
+
+ struct GPUShader *cavity_sh[2][2];
+
+ struct GPUShader *dof_prepare_sh;
+ struct GPUShader *dof_downsample_sh;
+ struct GPUShader *dof_blur1_sh;
+ struct GPUShader *dof_blur2_sh;
+ struct GPUShader *dof_resolve_sh;
+
+ struct GPUShader *aa_accum_sh;
+ struct GPUShader *smaa_sh[3];
+
+ struct GPUShader *volume_sh[2][2][3][2];
+
+} e_data = {{{{NULL}}}};
+
+/* -------------------------------------------------------------------- */
+/** \name Conversions
+ * \{ */
+
+static const char *workbench_lighting_mode_to_str(int light)
+{
+ switch (light) {
+ default:
+ BLI_assert_msg(0, "Error: Unknown lighting mode.");
+ ATTR_FALLTHROUGH;
+ case V3D_LIGHTING_STUDIO:
+ return "_studio";
+ case V3D_LIGHTING_MATCAP:
+ return "_matcap";
+ case V3D_LIGHTING_FLAT:
+ return "_flat";
+ return "";
+ }
+}
+
+static const char *workbench_datatype_mode_to_str(eWORKBENCH_DataType datatype)
+{
+ switch (datatype) {
+ default:
+ BLI_assert_msg(0, "Error: Unknown data mode.");
+ ATTR_FALLTHROUGH;
+ case WORKBENCH_DATATYPE_MESH:
+ return "_mesh";
+ case WORKBENCH_DATATYPE_HAIR:
+ return "_hair";
+ case WORKBENCH_DATATYPE_POINTCLOUD:
+ return "_ptcloud";
+ }
+}
+
+static const char *workbench_volume_interp_to_str(eWORKBENCH_VolumeInterpType interp_type)
+{
+ switch (interp_type) {
+ default:
+ BLI_assert_msg(0, "Error: Unknown lighting mode.");
+ ATTR_FALLTHROUGH;
+ case WORKBENCH_VOLUME_INTERP_LINEAR:
+ return "_linear";
+ case WORKBENCH_VOLUME_INTERP_CUBIC:
+ return "_cubic";
+ case WORKBENCH_VOLUME_INTERP_CLOSEST:
+ return "_closest";
+ }
+}
+
+static const char *workbench_texture_type_to_str(eWORKBENCH_TextureType tex_type)
+{
+ switch (tex_type) {
+ default:
+ BLI_assert_msg(0, "Error: Unknown texture mode.");
+ ATTR_FALLTHROUGH;
+ case TEXTURE_SH_NONE:
+ return "_tex_none";
+ case TEXTURE_SH_TILED:
+ return "_tex_tile";
+ case TEXTURE_SH_SINGLE:
+ return "_tex_single";
+ }
+}
+
+static eWORKBENCH_TextureType workbench_texture_type_get(bool textured, bool tiled)
+{
+ return textured ? (tiled ? TEXTURE_SH_TILED : TEXTURE_SH_SINGLE) : TEXTURE_SH_NONE;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shader request
+ * \{ */
+
+static GPUShader *workbench_shader_get_ex(WORKBENCH_PrivateData *wpd,
+ bool transp,
+ eWORKBENCH_DataType datatype,
+ bool textured,
+ bool tiled)
+{
+ eWORKBENCH_TextureType tex_type = workbench_texture_type_get(textured, tiled);
+ int light = wpd->shading.light;
+ BLI_assert(light < MAX_LIGHTING);
+ struct GPUShader **shader =
+ (transp) ? &e_data.transp_prepass_sh_cache[wpd->sh_cfg][datatype][light][tex_type] :
+ &e_data.opaque_prepass_sh_cache[wpd->sh_cfg][datatype][tex_type];
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench";
+ create_info_name += (transp) ? "_transp" : "_opaque";
+ if (transp) {
+ create_info_name += workbench_lighting_mode_to_str(light);
+ }
+ create_info_name += workbench_datatype_mode_to_str(datatype);
+ create_info_name += workbench_texture_type_to_str(tex_type);
+ create_info_name += (wpd->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? "_clip" : "_no_clip";
+
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, eWORKBENCH_DataType datatype)
+{
+ return workbench_shader_get_ex(wpd, false, datatype, false, false);
+}
+
+GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd,
+ eWORKBENCH_DataType datatype,
+ bool tiled)
+{
+ return workbench_shader_get_ex(wpd, false, datatype, true, tiled);
+}
+
+GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd,
+ eWORKBENCH_DataType datatype)
+{
+ return workbench_shader_get_ex(wpd, true, datatype, false, false);
+}
+
+GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd,
+ eWORKBENCH_DataType datatype,
+ bool tiled)
+{
+ return workbench_shader_get_ex(wpd, true, datatype, true, tiled);
+}
+
+GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd)
+{
+ int light = wpd->shading.light;
+ struct GPUShader **shader = &e_data.opaque_composite_sh[light];
+ BLI_assert(light < MAX_LIGHTING);
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench_composite";
+ create_info_name += workbench_lighting_mode_to_str(light);
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *UNUSED(wpd))
+{
+ if (e_data.merge_infront_sh == nullptr) {
+ e_data.merge_infront_sh = GPU_shader_create_from_info_name("workbench_merge_infront");
+ }
+ return e_data.merge_infront_sh;
+}
+
+GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *UNUSED(wpd))
+{
+ if (e_data.oit_resolve_sh == nullptr) {
+ e_data.oit_resolve_sh = GPU_shader_create_from_info_name("workbench_transparent_resolve");
+ }
+ return e_data.oit_resolve_sh;
+}
+
+static GPUShader *workbench_shader_shadow_pass_get_ex(bool depth_pass, bool manifold, bool cap)
+{
+ struct GPUShader **shader = (depth_pass) ? &e_data.shadow_depth_pass_sh[manifold] :
+ &e_data.shadow_depth_fail_sh[manifold][cap];
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench_shadow";
+ create_info_name += (depth_pass) ? "_pass" : "_fail";
+ create_info_name += (manifold) ? "_manifold" : "_no_manifold";
+ create_info_name += (cap) ? "_caps" : "_no_caps";
+#if DEBUG_SHADOW_VOLUME
+ create_info_name += "_debug";
+#endif
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_shadow_pass_get(bool manifold)
+{
+ return workbench_shader_shadow_pass_get_ex(true, manifold, false);
+}
+
+GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap)
+{
+ return workbench_shader_shadow_pass_get_ex(false, manifold, cap);
+}
+
+GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature)
+{
+ BLI_assert(cavity || curvature);
+ struct GPUShader **shader = &e_data.cavity_sh[cavity][curvature];
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench_effect";
+ create_info_name += (cavity) ? "_cavity" : "";
+ create_info_name += (curvature) ? "_curvature" : "";
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return *shader;
+}
+
+GPUShader *workbench_shader_outline_get(void)
+{
+ if (e_data.outline_sh == nullptr) {
+ e_data.outline_sh = GPU_shader_create_from_info_name("workbench_effect_outline");
+ }
+ return e_data.outline_sh;
+}
+
+void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
+ GPUShader **downsample_sh,
+ GPUShader **blur1_sh,
+ GPUShader **blur2_sh,
+ GPUShader **resolve_sh)
+{
+ if (e_data.dof_prepare_sh == nullptr) {
+ e_data.dof_prepare_sh = GPU_shader_create_from_info_name("workbench_effect_dof_prepare");
+ e_data.dof_downsample_sh = GPU_shader_create_from_info_name("workbench_effect_dof_downsample");
+#if 0 /* TODO(fclem): finish COC min_max optimization */
+ e_data.dof_flatten_v_sh = GPU_shader_create_from_info_name("workbench_effect_dof_flatten_v");
+ e_data.dof_flatten_h_sh = GPU_shader_create_from_info_name("workbench_effect_dof_flatten_h");
+ e_data.dof_dilate_v_sh = GPU_shader_create_from_info_name("workbench_effect_dof_dilate_v");
+ e_data.dof_dilate_h_sh = GPU_shader_create_from_info_name("workbench_effect_dof_dilate_h");
+#endif
+ e_data.dof_blur1_sh = GPU_shader_create_from_info_name("workbench_effect_dof_blur1");
+ e_data.dof_blur2_sh = GPU_shader_create_from_info_name("workbench_effect_dof_blur2");
+ e_data.dof_resolve_sh = GPU_shader_create_from_info_name("workbench_effect_dof_resolve");
+ }
+
+ *prepare_sh = e_data.dof_prepare_sh;
+ *downsample_sh = e_data.dof_downsample_sh;
+ *blur1_sh = e_data.dof_blur1_sh;
+ *blur2_sh = e_data.dof_blur2_sh;
+ *resolve_sh = e_data.dof_resolve_sh;
+}
+
+GPUShader *workbench_shader_antialiasing_accumulation_get(void)
+{
+ if (e_data.aa_accum_sh == nullptr) {
+ e_data.aa_accum_sh = GPU_shader_create_from_info_name("workbench_taa");
+ }
+ return e_data.aa_accum_sh;
+}
+
+GPUShader *workbench_shader_antialiasing_get(int stage)
+{
+ BLI_assert(stage < 3);
+ GPUShader **shader = &e_data.smaa_sh[stage];
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench_smaa_stage_";
+ create_info_name += std::to_string(stage);
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return e_data.smaa_sh[stage];
+}
+
+GPUShader *workbench_shader_volume_get(bool slice,
+ bool coba,
+ eWORKBENCH_VolumeInterpType interp_type,
+ bool smoke)
+{
+ GPUShader **shader = &e_data.volume_sh[slice][coba][interp_type][smoke];
+
+ if (*shader == nullptr) {
+ std::string create_info_name = "workbench_volume";
+ create_info_name += (smoke) ? "_smoke" : "_object";
+ create_info_name += workbench_volume_interp_to_str(interp_type);
+ create_info_name += (coba) ? "_coba" : "_no_coba";
+ create_info_name += (slice) ? "_slice" : "_no_slice";
+ *shader = GPU_shader_create_from_info_name(create_info_name.c_str());
+ }
+ return *shader;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cleanup
+ * \{ */
+
+void workbench_shader_free(void)
+{
+ for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.opaque_prepass_sh_cache[0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.transp_prepass_sh_cache) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.transp_prepass_sh_cache[0][0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < ARRAY_SIZE(e_data.opaque_composite_sh); j++) {
+ struct GPUShader **sh_array = &e_data.opaque_composite_sh[0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < ARRAY_SIZE(e_data.shadow_depth_pass_sh); j++) {
+ struct GPUShader **sh_array = &e_data.shadow_depth_pass_sh[0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.shadow_depth_fail_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.shadow_depth_fail_sh[0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.cavity_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.cavity_sh[0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < ARRAY_SIZE(e_data.smaa_sh); j++) {
+ struct GPUShader **sh_array = &e_data.smaa_sh[0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+ for (int j = 0; j < sizeof(e_data.volume_sh) / sizeof(void *); j++) {
+ struct GPUShader **sh_array = &e_data.volume_sh[0][0][0][0];
+ DRW_SHADER_FREE_SAFE(sh_array[j]);
+ }
+
+ DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh);
+ DRW_SHADER_FREE_SAFE(e_data.outline_sh);
+ DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.dof_prepare_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_blur1_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_blur2_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh);
+
+ DRW_SHADER_FREE_SAFE(e_data.aa_accum_sh);
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/workbench_shader_shared.h
index 2e229d4d83a..0bfd5957834 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl
+++ b/source/blender/draw/engines/workbench/workbench_shader_shared.h
@@ -1,20 +1,27 @@
+
+#ifndef GPU_SHADER
+# include "gpu_shader_shared_utils.h"
+#endif
+
+#define WORKBENCH_SHADER_SHARED_H
+
struct LightData {
- vec4 direction;
- vec4 specular_color;
- vec4 diffuse_color_wrap; /* rgb: diffuse col a: wrapped lighting factor */
+ float4 direction;
+ float4 specular_color;
+ float4 diffuse_color_wrap; /* rgb: diffuse col a: wrapped lighting factor */
};
struct WorldData {
- vec4 viewport_size;
- vec4 object_outline_color;
- vec4 shadow_direction_vs;
+ float4 viewport_size;
+ float4 object_outline_color;
+ float4 shadow_direction_vs;
float shadow_focus;
float shadow_shift;
float shadow_mul;
float shadow_add;
/* - 16 bytes alignment - */
LightData lights[4];
- vec4 ambient_color;
+ float4 ambient_color;
int cavity_sample_start;
int cavity_sample_end;
@@ -38,8 +45,3 @@ struct WorldData {
};
#define viewport_size_inv viewport_size.zw
-
-layout(std140) uniform world_block
-{
- WorldData world_data;
-};
diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c
index 3be005b43d0..2f9b85acf31 100644
--- a/source/blender/draw/engines/workbench/workbench_transparent.c
+++ b/source/blender/draw/engines/workbench/workbench_transparent.c
@@ -65,7 +65,7 @@ void workbench_transparent_engine_init(WORKBENCH_Data *data)
static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp)
{
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false);
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
@@ -76,8 +76,8 @@ static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd,
struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
- DRW_shgroup_uniform_texture(grp, "matcapDiffuseImage", diff_tx);
- DRW_shgroup_uniform_texture(grp, "matcapSpecularImage", spec_tx);
+ DRW_shgroup_uniform_texture(grp, "matcap_diffuse_tx", diff_tx);
+ DRW_shgroup_uniform_texture(grp, "matcap_specular_tx", spec_tx);
}
}
@@ -111,25 +111,25 @@ void workbench_transparent_cache_init(WORKBENCH_Data *vedata)
sh = workbench_shader_transparent_get(wpd, data);
wpd->prepass[transp][infront][data].common_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1);
workbench_transparent_lighting_uniforms(wpd, grp);
wpd->prepass[transp][infront][data].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
sh = workbench_shader_transparent_image_get(wpd, data, false);
wpd->prepass[transp][infront][data].image_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
workbench_transparent_lighting_uniforms(wpd, grp);
sh = workbench_shader_transparent_image_get(wpd, data, true);
wpd->prepass[transp][infront][data].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "materials_data", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
workbench_transparent_lighting_uniforms(wpd, grp);
}
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index daeadce3059..9632060d69c 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -129,7 +129,7 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata,
float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_float_copy(grp, "slicePosition", fds->slice_depth);
DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
@@ -148,7 +148,7 @@ static void workbench_volume_modifier_cache_populate(WORKBENCH_Data *vedata,
step_length = len_v3(dim);
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs);
@@ -272,7 +272,7 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata,
const float slice_position = volume->display.slice_depth;
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_float_copy(grp, "slicePosition", slice_position);
DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
@@ -299,7 +299,7 @@ static void workbench_volume_object_cache_populate(WORKBENCH_Data *vedata,
/* Set uniforms. */
grp = DRW_shgroup_create(sh, vedata->psl->volume_ps);
- DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_data", wpd->world_ubo);
DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice);
DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length);
DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs);
diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh
new file mode 100644
index 00000000000..7a9bdb377fe
--- /dev/null
+++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh
@@ -0,0 +1,812 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2022, Blender Foundation.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup draw
+ *
+ * Wrapper classes that make it easier to use GPU objects in C++.
+ *
+ * All Buffers need to be sent to GPU memory before being used. This is done by using the
+ * `push_update()`.
+ *
+ * A Storage[Array]Buffer can hold much more data than a Uniform[Array]Buffer
+ * which can only holds 16KB of data.
+ *
+ * All types are not copyable and Buffers are not Movable.
+ *
+ * `drw::UniformArrayBuffer<T, len>`
+ * Uniform buffer object containing an array of T with len elements.
+ * Data can be accessed using the [] operator.
+ *
+ * `drw::UniformBuffer<T>`
+ * A uniform buffer object class inheriting from T.
+ * Data can be accessed just like a normal T object.
+ *
+ * `drw::StorageArrayBuffer<T, len>`
+ * Storage buffer object containing an array of T with len elements.
+ * The item count can be changed after creation using `resize()`.
+ * However, this requires the invalidation of the whole buffer and
+ * discarding all data inside it.
+ * Data can be accessed using the [] operator.
+ *
+ * `drw::StorageBuffer<T>`
+ * A storage buffer object class inheriting from T.
+ * Data can be accessed just like a normal T object.
+ *
+ * `drw::Texture`
+ * A simple wrapper to #GPUTexture. A #drw::Texture can be created without allocation.
+ * The `ensure_[1d|2d|3d|cube][_array]()` method is here to make sure the underlying texture
+ * will meet the requirements and create (or recreate) the #GPUTexture if needed.
+ *
+ * `drw::TextureFromPool`
+ * A GPUTexture from the viewport texture pool. This texture can be shared with other engines
+ * and its content is undefined when acquiring it.
+ * A #drw::TextureFromPool is acquired for rendering using `acquire()` and released once the
+ * rendering is done using `release()`. The same texture can be acquired & released multiple
+ * time in one draw loop.
+ * The `sync()` method *MUST* be called once during the cache populate (aka: Sync) phase.
+ *
+ * `drw::Framebuffer`
+ * Simple wrapper to #GPUFramebuffer that can be moved.
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "draw_texture_pool.h"
+
+#include "BLI_float4.hh"
+#include "BLI_int2.hh"
+#include "BLI_int3.hh"
+#include "BLI_int4.hh"
+#include "BLI_span.hh"
+#include "BLI_utildefines.h"
+#include "BLI_utility_mixins.hh"
+
+#include "GPU_framebuffer.h"
+#include "GPU_texture.h"
+#include "GPU_uniform_buffer.h"
+#include "GPU_vertex_buffer.h"
+
+namespace blender::draw {
+
+/* -------------------------------------------------------------------- */
+/** \name Implementation Details
+ * \{ */
+
+namespace detail {
+
+template<
+ /** Type of the values stored in this uniform buffer. */
+ typename T,
+ /** The number of values that can be stored in this uniform buffer. */
+ int64_t len,
+ /** True if the buffer only resides on GPU memory and cannot be accessed. */
+ bool device_only>
+class DataBuffer {
+ protected:
+ T *data_ = nullptr;
+ int64_t len_ = len;
+
+ BLI_STATIC_ASSERT((sizeof(T) % 16) == 0, "Type need to be aligned to size of float4.");
+
+ public:
+ /**
+ * Get the value at the given index. This invokes undefined behavior when the
+ * index is out of bounds.
+ */
+ const T &operator[](int64_t index) const
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ BLI_assert(index >= 0);
+ BLI_assert(index < len);
+ return data_[index];
+ }
+
+ T &operator[](int64_t index)
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ BLI_assert(index >= 0);
+ BLI_assert(index < len);
+ return data_[index];
+ }
+
+ /**
+ * Get a pointer to the beginning of the array.
+ */
+ const T *data() const
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_;
+ }
+ T *data()
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_;
+ }
+
+ /**
+ * Iterator
+ */
+ const T *begin() const
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_;
+ }
+ const T *end() const
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_ + len;
+ }
+
+ T *begin()
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_;
+ }
+ T *end()
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return data_ + len;
+ }
+
+ operator Span<T>() const
+ {
+ BLI_STATIC_ASSERT(!device_only, "");
+ return Span<T>(data_, len);
+ }
+};
+
+template<typename T, int64_t len, bool device_only>
+class UniformCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable {
+ protected:
+ GPUUniformBuf *ubo_;
+
+#ifdef DEBUG
+ const char *name_ = typeid(T).name();
+#else
+ constexpr static const char *name_ = "UniformBuffer";
+#endif
+
+ public:
+ UniformCommon()
+ {
+ ubo_ = GPU_uniformbuf_create_ex(sizeof(T) * len, nullptr, name_);
+ }
+
+ ~UniformCommon()
+ {
+ GPU_uniformbuf_free(ubo_);
+ }
+
+ void push_update(void)
+ {
+ GPU_uniformbuf_update(ubo_, this->data_);
+ }
+
+ /* To be able to use it with DRW_shgroup_*_ref(). */
+ operator GPUUniformBuf *() const
+ {
+ return ubo_;
+ }
+
+ /* To be able to use it with DRW_shgroup_*_ref(). */
+ GPUUniformBuf **operator&()
+ {
+ return &ubo_;
+ }
+};
+
+template<typename T, int64_t len, bool device_only>
+class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable {
+ protected:
+ /* Use vertex buffer for now. Until there is a complete GPUStorageBuf implementation. */
+ GPUVertBuf *ssbo_;
+
+#ifdef DEBUG
+ const char *name_ = typeid(T).name();
+#else
+ constexpr static const char *name_ = "StorageBuffer";
+#endif
+
+ public:
+ StorageCommon()
+ {
+ init(len);
+ }
+
+ ~StorageCommon()
+ {
+ GPU_vertbuf_discard(ssbo_);
+ }
+
+ void resize(int64_t new_size)
+ {
+ BLI_assert(new_size > 0);
+ if (new_size != this->len_) {
+ GPU_vertbuf_discard(ssbo_);
+ this->init(new_size);
+ }
+ }
+
+ operator GPUVertBuf *() const
+ {
+ return ssbo_;
+ }
+ /* To be able to use it with DRW_shgroup_*_ref(). */
+ GPUVertBuf **operator&()
+ {
+ return &ssbo_;
+ }
+
+ private:
+ void init(int64_t new_size)
+ {
+ this->len_ = new_size;
+
+ GPUVertFormat format = {0};
+ GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+
+ GPUUsageType usage = device_only ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_DYNAMIC;
+ ssbo_ = GPU_vertbuf_create_with_format_ex(&format, usage);
+ GPU_vertbuf_data_alloc(ssbo_, divide_ceil_u(sizeof(T) * this->len_, 4));
+ if (!device_only) {
+ this->data_ = (T *)GPU_vertbuf_get_data(ssbo_);
+ GPU_vertbuf_use(ssbo_);
+ }
+ }
+};
+
+} // namespace detail
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Uniform Buffers
+ * \{ */
+
+template<
+ /** Type of the values stored in this uniform buffer. */
+ typename T,
+ /** The number of values that can be stored in this uniform buffer. */
+ int64_t len
+ /** True if the buffer only resides on GPU memory and cannot be accessed. */
+ /* TODO(fclem): Currently unsupported. */
+ /* bool device_only = false */>
+class UniformArrayBuffer : public detail::UniformCommon<T, len, false> {
+ public:
+ UniformArrayBuffer()
+ {
+ /* TODO(fclem) We should map memory instead. */
+ this->data_ = MEM_mallocN_aligned(this->name_);
+ }
+};
+
+template<
+ /** Type of the values stored in this uniform buffer. */
+ typename T
+ /** True if the buffer only resides on GPU memory and cannot be accessed. */
+ /* TODO(fclem): Currently unsupported. */
+ /* bool device_only = false */>
+class UniformBuffer : public T, public detail::UniformCommon<T, 1, false> {
+ public:
+ UniformBuffer()
+ {
+ /* TODO(fclem) How could we map this? */
+ this->data_ = static_cast<T *>(this);
+ }
+
+ UniformBuffer<T> &operator=(const T &other)
+ {
+ *static_cast<T *>(this) = other;
+ return *this;
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Storage Buffer
+ * \{ */
+
+template<
+ /** Type of the values stored in this uniform buffer. */
+ typename T,
+ /** The number of values that can be stored in this uniform buffer. */
+ int64_t len,
+ /** True if created on device and no memory host memory is allocated. */
+ bool device_only = false>
+class StorageArrayBuffer : public detail::StorageCommon<T, len, device_only> {
+ public:
+ void push_update(void)
+ {
+ BLI_assert(!device_only);
+ /* Get the data again to tag for update. The actual pointer should not
+ * change. */
+ this->data_ = (T *)GPU_vertbuf_get_data(this->ssbo_);
+ GPU_vertbuf_use(this->ssbo_);
+ }
+};
+
+template<
+ /** Type of the values stored in this uniform buffer. */
+ typename T,
+ /** True if created on device and no memory host memory is allocated. */
+ bool device_only = false>
+class StorageBuffer : public T, public detail::StorageCommon<T, 1, device_only> {
+ public:
+ void push_update(void)
+ {
+ BLI_assert(!device_only);
+ /* TODO(fclem): Avoid a full copy. */
+ T &vert_data = *(T *)GPU_vertbuf_get_data(this->ssbo_);
+ vert_data = *this;
+
+ GPU_vertbuf_use(this->ssbo_);
+ }
+
+ StorageBuffer<T> &operator=(const T &other)
+ {
+ *static_cast<T *>(this) = other;
+ return *this;
+ }
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Texture
+ * \{ */
+
+class Texture : NonCopyable {
+ protected:
+ GPUTexture *tx_ = nullptr;
+ const char *name_;
+
+ public:
+ Texture(const char *name = "gpu::Texture") : name_(name)
+ {
+ }
+
+ Texture(const char *name,
+ eGPUTextureFormat format,
+ int extent,
+ float *data = nullptr,
+ bool cubemap = false,
+ int mips = 1)
+ : name_(name)
+ {
+ tx_ = create(extent, 0, 0, mips, format, data, false, cubemap);
+ }
+
+ Texture(const char *name,
+ eGPUTextureFormat format,
+ int extent,
+ int layers,
+ float *data = nullptr,
+ bool cubemap = false,
+ int mips = 1)
+ : name_(name)
+ {
+ tx_ = create(extent, layers, 0, mips, format, data, true, cubemap);
+ }
+
+ Texture(
+ const char *name, eGPUTextureFormat format, int2 extent, float *data = nullptr, int mips = 1)
+ : name_(name)
+ {
+ tx_ = create(UNPACK2(extent), 0, mips, format, data, false, false);
+ }
+
+ Texture(const char *name,
+ eGPUTextureFormat format,
+ int2 extent,
+ int layers,
+ float *data = nullptr,
+ int mips = 1)
+ : name_(name)
+ {
+ tx_ = create(UNPACK2(extent), layers, mips, format, data, true, false);
+ }
+
+ Texture(
+ const char *name, eGPUTextureFormat format, int3 extent, float *data = nullptr, int mips = 1)
+ : name_(name)
+ {
+ tx_ = create(UNPACK3(extent), mips, format, data, false, false);
+ }
+
+ ~Texture()
+ {
+ free();
+ }
+
+ /* To be able to use it with DRW_shgroup_uniform_texture(). */
+ operator GPUTexture *() const
+ {
+ BLI_assert(tx_ != nullptr);
+ return tx_;
+ }
+
+ /* To be able to use it with DRW_shgroup_uniform_texture_ref(). */
+ GPUTexture **operator&()
+ {
+ return &tx_;
+ }
+
+ Texture &operator=(Texture &&a)
+ {
+ if (*this != a) {
+ this->tx_ = a.tx_;
+ this->name_ = a.name_;
+ a.tx_ = nullptr;
+ }
+ return *this;
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_1d(eGPUTextureFormat format, int extent, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(extent, 0, 0, mips, format, data, false, false);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_1d_array(
+ eGPUTextureFormat format, int extent, int layers, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(extent, layers, 0, mips, format, data, true, false);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_2d(eGPUTextureFormat format, const int2 &extent, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(UNPACK2(extent), 0, mips, format, data, false, false);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_2d_array(eGPUTextureFormat format,
+ const int2 &extent,
+ int layers,
+ float *data = nullptr,
+ int mips = 1)
+ {
+ return ensure_impl(UNPACK2(extent), layers, mips, format, data, true, false);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_3d(eGPUTextureFormat format, const int3 &extent, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(UNPACK3(extent), mips, format, data, false, false);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_cube(eGPUTextureFormat format, int extent, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(extent, extent, 0, mips, format, data, false, true);
+ }
+
+ /**
+ * Ensure the texture has the correct properties. Recreating it if needed.
+ * Return true if a texture has been created.
+ */
+ bool ensure_cube_array(
+ eGPUTextureFormat format, int extent, int layers, float *data = nullptr, int mips = 1)
+ {
+ return ensure_impl(extent, extent, layers, mips, format, data, false, true);
+ }
+
+ /**
+ * Returns true if the texture has been allocated or acquired from the pool.
+ */
+ bool is_valid(void) const
+ {
+ return tx_ != nullptr;
+ }
+
+ int width(void) const
+ {
+ return GPU_texture_width(tx_);
+ }
+
+ int height(void) const
+ {
+ return GPU_texture_height(tx_);
+ }
+
+ bool depth(void) const
+ {
+ return GPU_texture_depth(tx_);
+ }
+
+ bool is_stencil(void) const
+ {
+ return GPU_texture_stencil(tx_);
+ }
+
+ bool is_integer(void) const
+ {
+ return GPU_texture_integer(tx_);
+ }
+
+ bool is_cube(void) const
+ {
+ return GPU_texture_cube(tx_);
+ }
+
+ bool is_array(void) const
+ {
+ return GPU_texture_array(tx_);
+ }
+
+ int3 size(int miplvl = 0) const
+ {
+ int3 size(0);
+ GPU_texture_get_mipmap_size(tx_, miplvl, size);
+ return size;
+ }
+
+ /**
+ * Clear the entirety of the texture using one pixel worth of data.
+ */
+ void clear(float4 values)
+ {
+ GPU_texture_clear(tx_, GPU_DATA_FLOAT, &values[0]);
+ }
+
+ /**
+ * Clear the entirety of the texture using one pixel worth of data.
+ */
+ void clear(uint4 values)
+ {
+ GPU_texture_clear(tx_, GPU_DATA_UINT, &values[0]);
+ }
+
+ /**
+ * Clear the entirety of the texture using one pixel worth of data.
+ */
+ void clear(uchar4 values)
+ {
+ GPU_texture_clear(tx_, GPU_DATA_UBYTE, &values[0]);
+ }
+
+ /**
+ * Clear the entirety of the texture using one pixel worth of data.
+ */
+ void clear(int4 values)
+ {
+ GPU_texture_clear(tx_, GPU_DATA_INT, &values[0]);
+ }
+
+ /**
+ * Returns a buffer containing the texture data for the specified miplvl.
+ * The memory block needs to be manually freed by MEM_freeN().
+ */
+ template<typename T> T *read(eGPUDataFormat format, int miplvl = 0)
+ {
+ return reinterpret_cast<T *>(GPU_texture_read(tx_, format, miplvl));
+ }
+
+ void filter_mode(bool do_filter)
+ {
+ GPU_texture_filter_mode(tx_, do_filter);
+ }
+
+ /**
+ * Free the internal texture but not the #drw::Texture itself.
+ */
+ void free()
+ {
+ GPU_TEXTURE_FREE_SAFE(tx_);
+ }
+
+ private:
+ bool ensure_impl(int w,
+ int h = 0,
+ int d = 0,
+ int mips = 1,
+ eGPUTextureFormat format = GPU_RGBA8,
+ float *data = nullptr,
+ bool layered = false,
+ bool cubemap = false)
+
+ {
+ /* TODO(fclem) In the future, we need to check if mip_count did not change.
+ * For now it's ok as we always define all MIP level. */
+ if (tx_) {
+ int3 size = this->size();
+ if (size != int3(w, h, d) || GPU_texture_format(tx_) != format ||
+ GPU_texture_cube(tx_) != cubemap || GPU_texture_array(tx_) != layered) {
+ GPU_TEXTURE_FREE_SAFE(tx_);
+ }
+ }
+ if (tx_ == nullptr) {
+ tx_ = create(w, h, d, mips, format, data, layered, cubemap);
+ if (mips > 1) {
+ /* TODO(fclem) Remove once we have immutable storage or when mips are
+ * generated on creation. */
+ GPU_texture_generate_mipmap(tx_);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ GPUTexture *create(int w,
+ int h,
+ int d,
+ int mips,
+ eGPUTextureFormat format,
+ float *data,
+ bool layered,
+ bool cubemap)
+ {
+ if (h == 0) {
+ return GPU_texture_create_1d(name_, w, mips, format, data);
+ }
+ else if (d == 0) {
+ if (layered) {
+ return GPU_texture_create_1d_array(name_, w, h, mips, format, data);
+ }
+ else {
+ return GPU_texture_create_2d(name_, w, h, mips, format, data);
+ }
+ }
+ else if (cubemap) {
+ if (layered) {
+ return GPU_texture_create_cube_array(name_, w, d, mips, format, data);
+ }
+ else {
+ return GPU_texture_create_cube(name_, w, mips, format, data);
+ }
+ }
+ else {
+ if (layered) {
+ return GPU_texture_create_2d_array(name_, w, h, d, mips, format, data);
+ }
+ else {
+ return GPU_texture_create_3d(name_, w, h, d, mips, format, GPU_DATA_FLOAT, data);
+ }
+ }
+ }
+};
+
+class TextureFromPool : public Texture, NonMovable {
+ private:
+ GPUTexture *tx_tmp_saved_ = nullptr;
+
+ public:
+ TextureFromPool(const char *name = "gpu::Texture") : Texture(name){};
+
+ /* Always use `release()` after rendering. */
+ void acquire(int w, int h, eGPUTextureFormat format, void *owner_)
+ {
+ if (this->tx_ == nullptr) {
+ if (tx_tmp_saved_ != nullptr) {
+ this->tx_ = tx_tmp_saved_;
+ return;
+ }
+ DrawEngineType *owner = (DrawEngineType *)owner_;
+ this->tx_ = DRW_texture_pool_query_2d(w, h, format, owner);
+ }
+ }
+
+ void release(void)
+ {
+ tx_tmp_saved_ = this->tx_;
+ this->tx_ = nullptr;
+ }
+
+ /**
+ * Clears any reference. Workaround for pool texture not being able to release on demand.
+ * Needs to be called at during the sync phase.
+ */
+ void sync(void)
+ {
+ tx_tmp_saved_ = nullptr;
+ }
+
+ /** Remove methods that are forbidden with this type of textures. */
+ bool ensure_1d(int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_1d_array(int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_2d(int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_2d_array(int, int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_3d(int, int, int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_cube(int, int, eGPUTextureFormat, float *) = delete;
+ bool ensure_cube_array(int, int, int, eGPUTextureFormat, float *) = delete;
+ void filter_mode(bool) = delete;
+ void free() = delete;
+ /**
+ * Forbid the use of DRW_shgroup_uniform_texture.
+ * Use DRW_shgroup_uniform_texture_ref instead.
+ */
+ operator GPUTexture *() const = delete;
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Framebuffer
+ * \{ */
+
+class Framebuffer : NonCopyable {
+ private:
+ GPUFrameBuffer *fb_ = nullptr;
+ const char *name_;
+
+ public:
+ Framebuffer() : name_(""){};
+ Framebuffer(const char *name) : name_(name){};
+
+ ~Framebuffer()
+ {
+ GPU_FRAMEBUFFER_FREE_SAFE(fb_);
+ }
+
+ void ensure(GPUAttachment depth = GPU_ATTACHMENT_NONE,
+ GPUAttachment color1 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color2 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color3 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color4 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color5 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color6 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color7 = GPU_ATTACHMENT_NONE,
+ GPUAttachment color8 = GPU_ATTACHMENT_NONE)
+ {
+ GPU_framebuffer_ensure_config(
+ &fb_, {depth, color1, color2, color3, color4, color5, color6, color7, color8});
+ }
+
+ Framebuffer &operator=(Framebuffer &&a)
+ {
+ if (*this != a) {
+ this->fb_ = a.fb_;
+ this->name_ = a.name_;
+ a.fb_ = nullptr;
+ }
+ return *this;
+ }
+
+ operator GPUFrameBuffer *() const
+ {
+ return fb_;
+ }
+};
+
+/** \} */
+
+} // namespace blender::draw
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 961aed3f284..b16caf49209 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -226,9 +226,9 @@ struct GPUShader *DRW_shader_create_with_shaderlib_ex(const char *vert,
struct GPUShader *DRW_shader_create_with_transform_feedback(const char *vert,
const char *geom,
const char *defines,
- const eGPUShaderTFBType prim_type,
+ eGPUShaderTFBType prim_type,
const char **varying_names,
- const int varying_count);
+ int varying_count);
struct GPUShader *DRW_shader_create_fullscreen_ex(const char *frag,
const char *defines,
const char *name);
@@ -249,18 +249,18 @@ struct GPUShader *DRW_shader_create_fullscreen_with_shaderlib_ex(const char *fra
struct GPUMaterial *DRW_shader_find_from_world(struct World *wo,
const void *engine_type,
- const int options,
+ int options,
bool deferred);
struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma,
const void *engine_type,
- const int options,
+ int options,
bool deferred);
struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
struct World *wo,
struct bNodeTree *ntree,
const void *engine_type,
- const int options,
- const bool is_volume_shader,
+ int options,
+ bool is_volume_shader,
const char *vert,
const char *geom,
const char *frag_lib,
@@ -271,8 +271,8 @@ struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
struct Material *ma,
struct bNodeTree *ntree,
const void *engine_type,
- const int options,
- const bool is_volume_shader,
+ int options,
+ bool is_volume_shader,
const char *vert,
const char *geom,
const char *frag_lib,
@@ -351,7 +351,7 @@ typedef enum {
DRW_STATE_BLEND_ADD_FULL = (2 << 11),
/** Standard alpha blending. */
DRW_STATE_BLEND_ALPHA = (3 << 11),
- /** Use that if color is already premult by alpha. */
+ /** Use that if color is already pre-multiply by alpha. */
DRW_STATE_BLEND_ALPHA_PREMUL = (4 << 11),
DRW_STATE_BLEND_BACKGROUND = (5 << 11),
DRW_STATE_BLEND_OIT = (6 << 11),
@@ -609,12 +609,12 @@ void DRW_shgroup_uniform_image_ref(DRWShadingGroup *shgroup, const char *name, G
/* Store value instead of referencing it. */
-void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, const int value);
+void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, 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);
void DRW_shgroup_uniform_ivec4_copy(DRWShadingGroup *shgroup, const char *name, const int *value);
-void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value);
-void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value);
+void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, bool value);
+void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, float value);
void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 03fb3b92277..a4564ce2668 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -923,7 +923,7 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob)
GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob)
{
- Mesh *me = BKE_object_get_evaluated_mesh(ob);
+ Mesh *me = BKE_object_get_evaluated_mesh_no_subsurf(ob);
short type = (me != NULL) ? OB_MESH : ob->type;
switch (type) {
@@ -950,7 +950,7 @@ int DRW_cache_object_material_count_get(struct Object *ob)
{
short type = ob->type;
- Mesh *me = BKE_object_get_evaluated_mesh(ob);
+ Mesh *me = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (me != NULL && type != OB_POINTCLOUD) {
/* Some object types can have one data type in ob->data, but will be rendered as mesh.
* For point clouds this never happens. Ideally this check would happen at another level
@@ -960,7 +960,7 @@ int DRW_cache_object_material_count_get(struct Object *ob)
switch (type) {
case OB_MESH:
- return DRW_mesh_material_count_get((me != NULL) ? me : ob->data);
+ return DRW_mesh_material_count_get(ob, (me != NULL) ? me : ob->data);
case OB_CURVE:
case OB_SURF:
case OB_FONT:
@@ -2875,7 +2875,7 @@ GPUBatch *DRW_cache_mesh_surface_get(Object *ob)
GPUBatch *DRW_cache_mesh_surface_edges_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_edges(ob->data);
+ return DRW_mesh_batch_cache_get_surface_edges(ob, ob->data);
}
GPUBatch **DRW_cache_mesh_surface_shaded_get(Object *ob,
@@ -2883,31 +2883,31 @@ GPUBatch **DRW_cache_mesh_surface_shaded_get(Object *ob,
uint gpumat_array_len)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_shaded(ob->data, gpumat_array, gpumat_array_len);
+ return DRW_mesh_batch_cache_get_surface_shaded(ob, ob->data, gpumat_array, gpumat_array_len);
}
GPUBatch **DRW_cache_mesh_surface_texpaint_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_texpaint(ob->data);
+ return DRW_mesh_batch_cache_get_surface_texpaint(ob, ob->data);
}
GPUBatch *DRW_cache_mesh_surface_texpaint_single_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_texpaint_single(ob->data);
+ return DRW_mesh_batch_cache_get_surface_texpaint_single(ob, ob->data);
}
GPUBatch *DRW_cache_mesh_surface_vertpaint_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_vertpaint(ob->data);
+ return DRW_mesh_batch_cache_get_surface_vertpaint(ob, ob->data);
}
GPUBatch *DRW_cache_mesh_surface_sculptcolors_get(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
- return DRW_mesh_batch_cache_get_surface_sculpt(ob->data);
+ return DRW_mesh_batch_cache_get_surface_sculpt(ob, ob->data);
}
GPUBatch *DRW_cache_mesh_surface_weights_get(Object *ob)
@@ -3021,7 +3021,7 @@ GPUBatch *DRW_cache_surf_surface_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_surface(mesh_eval);
}
@@ -3034,7 +3034,7 @@ GPUBatch *DRW_cache_surf_edge_wire_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_loose_edges(mesh_eval);
}
@@ -3047,7 +3047,7 @@ GPUBatch *DRW_cache_surf_face_wireframe_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_wireframes_face(mesh_eval);
}
@@ -3059,7 +3059,7 @@ GPUBatch *DRW_cache_surf_edge_detection_get(Object *ob, bool *r_is_manifold)
{
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_edge_detection(mesh_eval, r_is_manifold);
}
@@ -3072,7 +3072,7 @@ GPUBatch *DRW_cache_surf_loose_edges_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_loose_edges(mesh_eval);
}
@@ -3089,9 +3089,9 @@ GPUBatch **DRW_cache_surf_surface_shaded_get(Object *ob,
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
- return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len);
+ return DRW_mesh_batch_cache_get_surface_shaded(ob, mesh_eval, gpumat_array, gpumat_array_len);
}
return DRW_curve_batch_cache_get_surface_shaded(cu, gpumat_array, gpumat_array_len);
@@ -3382,10 +3382,10 @@ GPUBatch *DRW_cache_cursor_get(bool crosshair_lines)
void drw_batch_cache_validate(Object *ob)
{
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
switch (ob->type) {
case OB_MESH:
- DRW_mesh_batch_cache_validate((Mesh *)ob->data);
+ DRW_mesh_batch_cache_validate(ob, (Mesh *)ob->data);
break;
case OB_CURVE:
case OB_FONT:
@@ -3393,7 +3393,7 @@ void drw_batch_cache_validate(Object *ob)
break;
case OB_SURF:
if (mesh_eval != NULL) {
- DRW_mesh_batch_cache_validate(mesh_eval);
+ DRW_mesh_batch_cache_validate(ob, mesh_eval);
}
DRW_curve_batch_cache_validate((Curve *)ob->data);
break;
@@ -3431,7 +3431,7 @@ void drw_batch_cache_generate_requested(Object *ob)
DRW_object_use_hide_faces(ob)) ||
((mode == CTX_MODE_EDIT_MESH) && DRW_object_is_in_edit_mode(ob))));
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
switch (ob->type) {
case OB_MESH:
DRW_mesh_batch_cache_create_requested(
@@ -3470,7 +3470,7 @@ void drw_batch_cache_generate_requested_evaluated_mesh(Object *ob)
DRW_object_use_hide_faces(ob)) ||
((mode == CTX_MODE_EDIT_MESH) && DRW_object_is_in_edit_mode(ob))));
- Mesh *mesh = BKE_object_get_evaluated_mesh(ob);
+ Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(ob);
DRW_mesh_batch_cache_create_requested(DST.task_graph, ob, mesh, scene, is_paint_mode, use_hide);
}
@@ -3481,7 +3481,7 @@ void drw_batch_cache_generate_requested_delayed(Object *ob)
void DRW_batch_cache_free_old(Object *ob, int ctime)
{
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
switch (ob->type) {
case OB_MESH:
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 7fcd86669ec..30e5a10df91 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -67,7 +67,7 @@ struct GPUBatch *DRW_cache_quad_wires_get(void);
struct GPUBatch *DRW_cache_cube_get(void);
struct GPUBatch *DRW_cache_normal_arrow_get(void);
-struct GPUBatch *DRW_cache_sphere_get(const eDRWLevelOfDetail level_of_detail);
+struct GPUBatch *DRW_cache_sphere_get(eDRWLevelOfDetail level_of_detail);
/* Dummy VBOs */
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index ba42cdf66e7..e7f66ebacd0 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -22,11 +22,13 @@
#pragma once
+struct DRWSubdivCache;
struct TaskGraph;
#include "DNA_customdata_types.h"
#include "BKE_attribute.h"
+#include "BKE_object.h"
#include "GPU_batch.h"
#include "GPU_index_buffer.h"
@@ -106,11 +108,13 @@ ENUM_OPERATORS(eMRDataType, MR_DATA_POLYS_SORTED)
extern "C" {
#endif
-BLI_INLINE int mesh_render_mat_len_get(const Mesh *me)
+BLI_INLINE int mesh_render_mat_len_get(const Object *object, const Mesh *me)
{
- /* In edit mode, the displayed mesh is stored in the edit-mesh. */
- if (me->edit_mesh && me->edit_mesh->mesh_eval_final) {
- return MAX2(1, me->edit_mesh->mesh_eval_final->totcol);
+ if (me->edit_mesh != NULL) {
+ const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
+ if (editmesh_eval_final != NULL) {
+ return MAX2(1, editmesh_eval_final->totcol);
+ }
}
return MAX2(1, me->totcol);
}
@@ -244,6 +248,13 @@ typedef enum DRWBatchFlag {
BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields");
+typedef struct MeshExtractLooseGeom {
+ int edge_len;
+ int vert_len;
+ int *verts;
+ int *edges;
+} MeshExtractLooseGeom;
+
/**
* Data that are kept around between extractions to reduce rebuilding time.
*
@@ -252,12 +263,7 @@ BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of b
typedef struct MeshBufferCache {
MeshBufferList buff;
- struct {
- int edge_len;
- int vert_len;
- int *verts;
- int *edges;
- } loose_geom;
+ MeshExtractLooseGeom loose_geom;
struct {
int *tri_first_index;
@@ -283,6 +289,8 @@ typedef struct MeshBatchCache {
GPUBatch **surface_per_mat;
+ struct DRWSubdivCache *subdiv_cache;
+
DRWBatchFlag batch_requested; /* DRWBatchFlag */
DRWBatchFlag batch_ready; /* DRWBatchFlag */
@@ -323,17 +331,23 @@ typedef struct MeshBatchCache {
void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
+ Object *object,
Mesh *me,
- const bool is_editmode,
- const bool is_paint_mode,
- const bool is_mode_active,
+ bool is_editmode,
+ bool is_paint_mode,
+ bool is_mode_active,
const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
- const bool use_subsurf_fdots,
+ bool do_final,
+ bool do_uvedit,
+ bool use_subsurf_fdots,
const Scene *scene,
- const ToolSettings *ts,
- const bool use_hide);
+ const struct ToolSettings *ts,
+ bool use_hide);
+
+void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ struct DRWSubdivCache *subdiv_cache,
+ const struct ToolSettings *ts);
#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 485b803310c..987ddf3a938 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -42,6 +42,7 @@
#include "draw_cache_extract.h"
#include "draw_cache_inline.h"
+#include "draw_subdivision.h"
#include "mesh_extractors/extract_mesh.h"
@@ -569,6 +570,7 @@ static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *t
static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
+ Object *object,
Mesh *me,
const bool is_editmode,
@@ -614,7 +616,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
*/
const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
GPU_use_hq_normals_workaround();
- const bool override_single_mat = mesh_render_mat_len_get(me) <= 1;
+ const bool override_single_mat = mesh_render_mat_len_get(object, me) <= 1;
/* Create an array containing all the extractors that needs to be executed. */
ExtractorRunDatas extractors;
@@ -699,7 +701,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
#endif
MeshRenderData *mr = mesh_render_data_create(
- me, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts);
+ object, me, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts);
mr->use_hide = use_hide;
mr->use_subsurf_fdots = use_subsurf_fdots;
mr->use_final_mesh = do_final;
@@ -783,12 +785,125 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
/** \} */
+/* ---------------------------------------------------------------------- */
+/** \name Subdivision Extract Loop
+ * \{ */
+
+static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ DRWSubdivCache *subdiv_cache,
+ const ToolSettings *ts)
+{
+ /* Create an array containing all the extractors that needs to be executed. */
+ ExtractorRunDatas extractors;
+
+ MeshBufferList *mbuflist = &mbc->buff;
+
+#define EXTRACT_ADD_REQUESTED(type, name) \
+ do { \
+ if (DRW_##type##_requested(mbuflist->type.name)) { \
+ const MeshExtract *extractor = &extract_##name; \
+ extractors.append(extractor); \
+ } \
+ } while (0)
+
+ /* The order in which extractors are added to the list matters somewhat, as some buffers are
+ * reused when building others. */
+ EXTRACT_ADD_REQUESTED(ibo, tris);
+ EXTRACT_ADD_REQUESTED(vbo, pos_nor);
+ EXTRACT_ADD_REQUESTED(vbo, lnor);
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ EXTRACT_ADD_REQUESTED(vbo, attr[i]);
+ }
+
+ /* We use only one extractor for face dots, as the work is done in a single compute shader. */
+ if (DRW_vbo_requested(mbuflist->vbo.fdots_nor) || DRW_vbo_requested(mbuflist->vbo.fdots_pos) ||
+ DRW_ibo_requested(mbuflist->ibo.fdots)) {
+ extractors.append(&extract_fdots_pos);
+ }
+
+ EXTRACT_ADD_REQUESTED(ibo, lines);
+ EXTRACT_ADD_REQUESTED(ibo, edituv_points);
+ EXTRACT_ADD_REQUESTED(ibo, edituv_tris);
+ EXTRACT_ADD_REQUESTED(ibo, edituv_lines);
+ EXTRACT_ADD_REQUESTED(vbo, vert_idx);
+ EXTRACT_ADD_REQUESTED(vbo, edge_idx);
+ EXTRACT_ADD_REQUESTED(vbo, poly_idx);
+ EXTRACT_ADD_REQUESTED(vbo, edge_fac);
+ EXTRACT_ADD_REQUESTED(ibo, points);
+ EXTRACT_ADD_REQUESTED(vbo, edit_data);
+ EXTRACT_ADD_REQUESTED(vbo, edituv_data);
+ /* Make sure UVs are computed before edituv stuffs. */
+ EXTRACT_ADD_REQUESTED(vbo, uv);
+ EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_area);
+ EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
+ EXTRACT_ADD_REQUESTED(ibo, lines_adjacency);
+ EXTRACT_ADD_REQUESTED(vbo, vcol);
+ EXTRACT_ADD_REQUESTED(vbo, weights);
+ EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
+
+#undef EXTRACT_ADD_REQUESTED
+
+ if (extractors.is_empty()) {
+ return;
+ }
+
+ MeshRenderData mr;
+ memset(&mr, 0, sizeof(MeshRenderData));
+ draw_subdiv_init_mesh_render_data(subdiv_cache, &mr, ts);
+ mesh_render_data_update_loose_geom(&mr, mbc, MR_ITER_LEDGE | MR_ITER_LVERT, MR_DATA_LOOSE_GEOM);
+
+ void *data_stack = MEM_mallocN(extractors.data_size_total(), __func__);
+ uint32_t data_offset = 0;
+ for (const ExtractorRunData &run_data : extractors) {
+ const MeshExtract *extractor = run_data.extractor;
+ void *buffer = mesh_extract_buffer_get(extractor, mbuflist);
+ void *data = POINTER_OFFSET(data_stack, data_offset);
+
+ extractor->init_subdiv(subdiv_cache, &mr, cache, buffer, data);
+
+ if (extractor->iter_subdiv_mesh || extractor->iter_subdiv_bm) {
+ int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index;
+ if (subdiv_cache->bm) {
+ for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) {
+ /* Multiply by 4 to have the start index of the quad's loop, as subdiv_loop_poly_index is
+ * based on the subdivision loops. */
+ const int poly_origindex = subdiv_loop_poly_index[i * 4];
+ const BMFace *efa = bm_original_face_get(&mr, poly_origindex);
+ extractor->iter_subdiv_bm(subdiv_cache, &mr, data, i, efa);
+ }
+ }
+ else {
+ for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) {
+ /* Multiply by 4 to have the start index of the quad's loop, as subdiv_loop_poly_index is
+ * based on the subdivision loops. */
+ const int poly_origindex = subdiv_loop_poly_index[i * 4];
+ const MPoly *mp = &mr.mpoly[poly_origindex];
+ extractor->iter_subdiv_mesh(subdiv_cache, &mr, data, i, mp);
+ }
+ }
+ }
+
+ if (extractor->iter_loose_geom_subdiv) {
+ extractor->iter_loose_geom_subdiv(subdiv_cache, &mr, &mbc->loose_geom, buffer, data);
+ }
+
+ if (extractor->finish_subdiv) {
+ extractor->finish_subdiv(subdiv_cache, &mr, cache, buffer, data);
+ }
+ }
+ MEM_freeN(data_stack);
+}
+
+/** \} */
+
} // namespace blender::draw
extern "C" {
void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
+ Object *object,
Mesh *me,
const bool is_editmode,
@@ -805,6 +920,7 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
blender::draw::mesh_buffer_cache_create_requested(task_graph,
cache,
mbc,
+ object,
me,
is_editmode,
is_paint_mode,
@@ -818,4 +934,12 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
use_hide);
}
+void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ DRWSubdivCache *subdiv_cache,
+ const ToolSettings *ts)
+{
+ blender::draw::mesh_buffer_cache_create_requested_subdiv(cache, mbc, subdiv_cache, ts);
+}
+
} // extern "C"
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
index 8b0fbf86360..a47a124bd24 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
@@ -379,14 +379,15 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
if (mr->extract_type != MR_EXTRACT_BMESH) {
/* Mesh */
+ mr->vert_normals = BKE_mesh_vertex_normals_ensure(mr->me);
if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
- BKE_mesh_ensure_normals_for_display(mr->me);
- mr->poly_normals = CustomData_get_layer(&mr->me->pdata, CD_NORMAL);
+ mr->poly_normals = BKE_mesh_poly_normals_ensure(mr->me);
}
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL);
BKE_mesh_normals_loop_split(mr->me->mvert,
+ mr->vert_normals,
mr->vert_len,
mr->me->medge,
mr->edge_len,
@@ -437,7 +438,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
}
}
-MeshRenderData *mesh_render_data_create(Mesh *me,
+MeshRenderData *mesh_render_data_create(Object *object,
+ Mesh *me,
const bool is_editmode,
const bool is_paint_mode,
const bool is_mode_active,
@@ -448,15 +450,18 @@ MeshRenderData *mesh_render_data_create(Mesh *me,
{
MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
mr->toolsettings = ts;
- mr->mat_len = mesh_render_mat_len_get(me);
+ mr->mat_len = mesh_render_mat_len_get(object, me);
copy_m4_m4(mr->obmat, obmat);
if (is_editmode) {
- BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final);
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(object);
+
+ BLI_assert(editmesh_eval_cage && editmesh_eval_final);
mr->bm = me->edit_mesh->bm;
mr->edit_bmesh = me->edit_mesh;
- mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage;
+ mr->me = (do_final) ? editmesh_eval_final : editmesh_eval_cage;
mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL;
if (mr->edit_data) {
@@ -486,7 +491,8 @@ MeshRenderData *mesh_render_data_create(Mesh *me,
mr->eed_act = BM_mesh_active_edge_get(mr->bm);
mr->eve_act = BM_mesh_active_vert_get(mr->bm);
- mr->crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE);
+ mr->vert_crease_ofs = CustomData_get_offset(&mr->bm->vdata, CD_CREASE);
+ mr->edge_crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE);
mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT);
#ifdef WITH_FREESTYLE
mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE);
@@ -505,7 +511,7 @@ MeshRenderData *mesh_render_data_create(Mesh *me,
/* Seems like the mesh_eval_final do not have the right origin indices.
* Force not mapped in this case. */
- if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
+ if (has_mdata && do_final && editmesh_eval_final != editmesh_eval_cage) {
// mr->edit_bmesh = NULL;
mr->extract_type = MR_EXTRACT_MESH;
}
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 80b8c0506e7..6a2f4b91ad1 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -60,7 +60,7 @@ void DRW_curve_batch_cache_validate(struct Curve *cu);
void DRW_curve_batch_cache_free(struct Curve *cu);
void DRW_mesh_batch_cache_dirty_tag(struct Mesh *me, eMeshBatchDirtyMode mode);
-void DRW_mesh_batch_cache_validate(struct Mesh *me);
+void DRW_mesh_batch_cache_validate(struct Object *object, struct Mesh *me);
void DRW_mesh_batch_cache_free(struct Mesh *me);
void DRW_lattice_batch_cache_dirty_tag(struct Lattice *lt, int mode);
@@ -105,7 +105,7 @@ void DRW_mesh_batch_cache_free_old(struct Mesh *me, int ctime);
/** \name Generic
* \{ */
-void DRW_vertbuf_create_wiredata(struct GPUVertBuf *vbo, const int vert_len);
+void DRW_vertbuf_create_wiredata(struct GPUVertBuf *vbo, int vert_len);
/** \} */
@@ -178,7 +178,7 @@ void DRW_displist_indexbuf_create_edges_adjacency_lines(struct ListBase *lb,
struct GPUBatch *DRW_lattice_batch_cache_get_all_edges(struct Lattice *lt,
bool use_weight,
- const int actdef);
+ 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);
@@ -228,22 +228,26 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
struct Object *ob,
struct Mesh *me,
const struct Scene *scene,
- const bool is_paint_mode,
- const bool use_hide);
+ bool is_paint_mode,
+ bool use_hide);
struct GPUBatch *DRW_mesh_batch_cache_get_all_verts(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_all_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_loose_edges(struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edge_detection(struct Mesh *me, bool *r_is_manifold);
struct GPUBatch *DRW_mesh_batch_cache_get_surface(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_surface_edges(struct Mesh *me);
-struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(struct Mesh *me,
+struct GPUBatch *DRW_mesh_batch_cache_get_surface_edges(struct Object *object, struct Mesh *me);
+struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(struct Object *object,
+ struct Mesh *me,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len);
-struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me);
-struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me);
-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_texpaint(struct Object *object,
+ struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Object *object,
+ struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Object *object,
+ struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(struct Object *object, 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);
@@ -293,14 +297,16 @@ struct GPUBatch *DRW_mesh_batch_cache_get_wireframes_face(struct Mesh *me);
* 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,
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(struct Object *object,
+ struct Mesh *me,
float **tot_area,
float **tot_uv_area);
-struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(struct Mesh *me);
-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);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(struct Object *object,
+ struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(struct Object *object, struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(struct Object *object, struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(struct Object *object, struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(struct Object *object, struct Mesh *me);
/** \} */
@@ -308,7 +314,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(struct Mesh *me);
/** \name For Image UV Editor
* \{ */
-struct GPUBatch *DRW_mesh_batch_cache_get_uv_edges(struct Mesh *me);
+struct GPUBatch *DRW_mesh_batch_cache_get_uv_edges(struct Object *object, struct Mesh *me);
struct GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(struct Mesh *me);
/** \} */
@@ -321,7 +327,7 @@ 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);
-int DRW_mesh_material_count_get(const struct Mesh *me);
+int DRW_mesh_material_count_get(const struct Object *object, const struct Mesh *me);
/* See 'common_globals_lib.glsl' for duplicate defines. */
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc
index 1108d40125b..33cf0e9a3cd 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curve.cc
@@ -26,8 +26,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
-#include "BLI_float3.hh"
#include "BLI_listbase.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_math_vector.h"
#include "BLI_span.hh"
#include "BLI_utildefines.h"
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
index 483e52ed547..ddad07a7476 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -642,7 +642,7 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_
float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__);
/* Triangulate in 2D. */
for (int i = 0; i < vert_len; i++) {
- copy_v2_v2(tpoints2d[i], &tpoints[i].x);
+ copy_v2_v2(tpoints2d[i], tpoints[i].m_xy);
}
/* Compute directly inside the IBO data buffer. */
/* OPTI: This is a bottleneck if the stroke is very long. */
diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.cc
index ed0c46ad45a..d236f0c2f59 100644
--- a/source/blender/draw/intern/draw_cache_impl_hair.c
+++ b/source/blender/draw/intern/draw_cache_impl_hair.cc
@@ -23,7 +23,7 @@
* \brief Hair API for render engines
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -49,27 +49,28 @@ static void hair_batch_cache_clear(Hair *hair);
/* ---------------------------------------------------------------------- */
/* Hair GPUBatch Cache */
-typedef struct HairBatchCache {
+struct HairBatchCache {
ParticleHairCache hair;
/* settings to determine if cache is invalid */
bool is_dirty;
-} HairBatchCache;
+};
/* GPUBatch cache management. */
static bool hair_batch_cache_valid(Hair *hair)
{
- HairBatchCache *cache = hair->batch_cache;
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
return (cache && cache->is_dirty == false);
}
static void hair_batch_cache_init(Hair *hair)
{
- HairBatchCache *cache = hair->batch_cache;
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
if (!cache) {
- cache = hair->batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ cache = MEM_cnew<HairBatchCache>(__func__);
+ hair->batch_cache = cache;
}
else {
memset(cache, 0, sizeof(*cache));
@@ -89,13 +90,13 @@ void DRW_hair_batch_cache_validate(Hair *hair)
static HairBatchCache *hair_batch_cache_get(Hair *hair)
{
DRW_hair_batch_cache_validate(hair);
- return hair->batch_cache;
+ return static_cast<HairBatchCache *>(hair->batch_cache);
}
void DRW_hair_batch_cache_dirty_tag(Hair *hair, int mode)
{
- HairBatchCache *cache = hair->batch_cache;
- if (cache == NULL) {
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
+ if (cache == nullptr) {
return;
}
switch (mode) {
@@ -109,7 +110,7 @@ void DRW_hair_batch_cache_dirty_tag(Hair *hair, int mode)
static void hair_batch_cache_clear(Hair *hair)
{
- HairBatchCache *cache = hair->batch_cache;
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
if (!cache) {
return;
}
@@ -125,8 +126,8 @@ void DRW_hair_batch_cache_free(Hair *hair)
static void ensure_seg_pt_count(Hair *hair, ParticleHairCache *hair_cache)
{
- if ((hair_cache->pos != NULL && hair_cache->indices != NULL) ||
- (hair_cache->proc_point_buf != NULL)) {
+ if ((hair_cache->pos != nullptr && hair_cache->indices != nullptr) ||
+ (hair_cache->proc_point_buf != nullptr)) {
return;
}
@@ -153,7 +154,7 @@ static void hair_batch_cache_fill_segments_proc_pos(Hair *hair,
for (int i = 0; i < num_curves; i++, curve++) {
float(*curve_co)[3] = hair->co + curve->firstpoint;
float total_len = 0.0f;
- float *co_prev = NULL, *seg_data_first;
+ float *co_prev = nullptr, *seg_data_first;
for (int j = 0; j < curve->numpoints; j++) {
float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
copy_v3_v3(seg_data, curve_co[j]);
@@ -166,7 +167,7 @@ static void hair_batch_cache_fill_segments_proc_pos(Hair *hair,
seg_data[3] = total_len;
co_prev = curve_co[j];
}
- /* Assign length value*/
+ /* Assign length value. */
*(float *)GPU_vertbuf_raw_step(length_step) = total_len;
if (total_len > 0.0f) {
/* Divide by total length to have a [0-1] number. */
@@ -181,7 +182,7 @@ static void hair_batch_cache_ensure_procedural_pos(Hair *hair,
ParticleHairCache *cache,
GPUMaterial *gpu_material)
{
- if (cache->proc_point_buf == NULL) {
+ if (cache->proc_point_buf == nullptr) {
/* initialize vertex format */
GPUVertFormat format = {0};
uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
@@ -209,7 +210,7 @@ static void hair_batch_cache_ensure_procedural_pos(Hair *hair,
cache->point_tex = GPU_texture_create_from_vertbuf("hair_point", cache->proc_point_buf);
}
- if (gpu_material && cache->proc_length_buf != NULL && cache->length_tex) {
+ if (gpu_material && cache->proc_length_buf != nullptr && cache->length_tex) {
ListBase gpu_attrs = GPU_material_attributes(gpu_material);
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) {
if (attr->type == CD_HAIRLENGTH) {
@@ -306,7 +307,7 @@ static void hair_batch_cache_ensure_procedural_indices(Hair *hair,
{
BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */
- if (cache->final[subdiv].proc_hairs[thickness_res - 1] != NULL) {
+ if (cache->final[subdiv].proc_hairs[thickness_res - 1] != nullptr) {
return;
}
@@ -340,7 +341,7 @@ bool hair_ensure_procedural_data(Object *object,
int thickness_res)
{
bool need_ft_update = false;
- Hair *hair = object->data;
+ Hair *hair = static_cast<Hair *>(object->data);
HairBatchCache *cache = hair_batch_cache_get(hair);
*r_hair_cache = &cache->hair;
@@ -349,23 +350,23 @@ bool hair_ensure_procedural_data(Object *object,
(*r_hair_cache)->final[subdiv].strands_res = 1 << (steps + subdiv);
/* Refreshed on combing and simulation. */
- if ((*r_hair_cache)->proc_point_buf == NULL) {
+ if ((*r_hair_cache)->proc_point_buf == nullptr) {
ensure_seg_pt_count(hair, &cache->hair);
hair_batch_cache_ensure_procedural_pos(hair, &cache->hair, gpu_material);
need_ft_update = true;
}
/* Refreshed if active layer or custom data changes. */
- if ((*r_hair_cache)->strand_tex == NULL) {
+ if ((*r_hair_cache)->strand_tex == nullptr) {
hair_batch_cache_ensure_procedural_strand_data(hair, &cache->hair);
}
/* Refreshed only on subdiv count change. */
- if ((*r_hair_cache)->final[subdiv].proc_buf == NULL) {
+ if ((*r_hair_cache)->final[subdiv].proc_buf == nullptr) {
hair_batch_cache_ensure_procedural_final_points(&cache->hair, subdiv);
need_ft_update = true;
}
- if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == NULL) {
+ if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == nullptr) {
hair_batch_cache_ensure_procedural_indices(hair, &cache->hair, thickness_res, subdiv);
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 82b3b5aee41..f57921d058c 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -54,6 +54,7 @@
#include "BKE_object_deform.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_subdiv_modifier.h"
#include "atomic_ops.h"
@@ -69,6 +70,7 @@
#include "draw_cache_extract.h"
#include "draw_cache_inline.h"
+#include "draw_subdivision.h"
#include "draw_cache_impl.h" /* own include */
@@ -278,9 +280,16 @@ BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a)
*((uint32_t *)a) = 0;
}
-BLI_INLINE const Mesh *editmesh_final_or_this(const Mesh *me)
+BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *me)
{
- return (me->edit_mesh && me->edit_mesh->mesh_eval_final) ? me->edit_mesh->mesh_eval_final : me;
+ if (me->edit_mesh != NULL) {
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
+ if (editmesh_eval_final != NULL) {
+ return editmesh_eval_final;
+ }
+ }
+
+ return me;
}
static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *cd_used)
@@ -380,6 +389,7 @@ static void drw_mesh_attributes_add_request(DRW_MeshAttributes *attrs,
BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->ldata;
break;
@@ -395,6 +405,7 @@ BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->pdata;
break;
@@ -410,6 +421,7 @@ BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me)
BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->edata;
break;
@@ -425,6 +437,7 @@ BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me)
BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->vdata;
break;
@@ -437,9 +450,11 @@ BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me)
return &me->vdata;
}
-static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
+static void mesh_cd_calc_active_uv_layer(const Object *object,
+ const Mesh *me,
+ DRW_MeshCDMask *cd_used)
{
- const Mesh *me_final = editmesh_final_or_this(me);
+ const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
@@ -447,9 +462,11 @@ static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used
}
}
-static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
+static void mesh_cd_calc_active_mask_uv_layer(const Object *object,
+ const Mesh *me,
+ DRW_MeshCDMask *cd_used)
{
- const Mesh *me_final = editmesh_final_or_this(me);
+ const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
@@ -457,9 +474,11 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd
}
}
-static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshAttributes *attrs_used)
+static void mesh_cd_calc_active_vcol_layer(const Object *object,
+ const Mesh *me,
+ DRW_MeshAttributes *attrs_used)
{
- const Mesh *me_final = editmesh_final_or_this(me);
+ const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR);
@@ -468,9 +487,11 @@ static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshAttributes *a
}
}
-static void mesh_cd_calc_active_mloopcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
+static void mesh_cd_calc_active_mloopcol_layer(const Object *object,
+ const Mesh *me,
+ DRW_MeshCDMask *cd_used)
{
- const Mesh *me_final = editmesh_final_or_this(me);
+ const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
@@ -508,12 +529,13 @@ static bool custom_data_match_attribute(const CustomData *custom_data,
return false;
}
-static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
+static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
+ const Mesh *me,
struct GPUMaterial **gpumat_array,
int gpumat_array_len,
DRW_MeshAttributes *attributes)
{
- const Mesh *me_final = editmesh_final_or_this(me);
+ const Mesh *me_final = editmesh_final_or_this(object, me);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
const CustomData *cd_pdata = mesh_cd_pdata_get_from_mesh(me_final);
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
@@ -787,7 +809,7 @@ BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag
/* GPUBatch cache management. */
-static bool mesh_batch_cache_valid(Mesh *me)
+static bool mesh_batch_cache_valid(Object *object, Mesh *me)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@@ -803,14 +825,14 @@ static bool mesh_batch_cache_valid(Mesh *me)
return false;
}
- if (cache->mat_len != mesh_render_mat_len_get(me)) {
+ if (cache->mat_len != mesh_render_mat_len_get(object, me)) {
return false;
}
return true;
}
-static void mesh_batch_cache_init(Mesh *me)
+static void mesh_batch_cache_init(Object *object, Mesh *me)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@@ -830,7 +852,7 @@ static void mesh_batch_cache_init(Mesh *me)
// cache->vert_len = mesh_render_verts_len_get(me);
}
- cache->mat_len = mesh_render_mat_len_get(me);
+ cache->mat_len = mesh_render_mat_len_get(object, me);
cache->surface_per_mat = MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__);
cache->tris_per_mat = MEM_callocN(sizeof(*cache->tris_per_mat) * cache->mat_len, __func__);
@@ -841,11 +863,11 @@ static void mesh_batch_cache_init(Mesh *me)
drw_mesh_weight_state_clear(&cache->weight_state);
}
-void DRW_mesh_batch_cache_validate(Mesh *me)
+void DRW_mesh_batch_cache_validate(Object *object, Mesh *me)
{
- if (!mesh_batch_cache_valid(me)) {
+ if (!mesh_batch_cache_valid(object, me)) {
mesh_batch_cache_clear(me);
- mesh_batch_cache_init(me);
+ mesh_batch_cache_init(object, me);
}
}
@@ -1037,6 +1059,15 @@ static void mesh_buffer_cache_clear(MeshBufferCache *mbc)
mbc->poly_sorted.visible_tri_len = 0;
}
+static void mesh_batch_cache_free_subdiv_cache(MeshBatchCache *cache)
+{
+ if (cache->subdiv_cache) {
+ draw_subdiv_cache_free(cache->subdiv_cache);
+ MEM_freeN(cache->subdiv_cache);
+ cache->subdiv_cache = NULL;
+ }
+}
+
static void mesh_batch_cache_clear(Mesh *me)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@@ -1064,6 +1095,8 @@ static void mesh_batch_cache_clear(Mesh *me)
cache->batch_ready = 0;
drw_mesh_weight_state_clear(&cache->weight_state);
+
+ mesh_batch_cache_free_subdiv_cache(cache);
}
void DRW_mesh_batch_cache_free(Mesh *me)
@@ -1078,24 +1111,24 @@ void DRW_mesh_batch_cache_free(Mesh *me)
/** \name Public API
* \{ */
-static void texpaint_request_active_uv(MeshBatchCache *cache, Mesh *me)
+static void texpaint_request_active_uv(MeshBatchCache *cache, Object *object, Mesh *me)
{
DRW_MeshCDMask cd_needed;
mesh_cd_layers_type_clear(&cd_needed);
- mesh_cd_calc_active_uv_layer(me, &cd_needed);
+ mesh_cd_calc_active_uv_layer(object, me, &cd_needed);
BLI_assert(cd_needed.uv != 0 &&
"No uv layer available in texpaint, but batches requested anyway!");
- mesh_cd_calc_active_mask_uv_layer(me, &cd_needed);
+ mesh_cd_calc_active_mask_uv_layer(object, me, &cd_needed);
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
}
-static void texpaint_request_active_vcol(MeshBatchCache *cache, Mesh *me)
+static void texpaint_request_active_vcol(MeshBatchCache *cache, Object *object, Mesh *me)
{
DRW_MeshCDMask cd_needed;
mesh_cd_layers_type_clear(&cd_needed);
- mesh_cd_calc_active_mloopcol_layer(me, &cd_needed);
+ mesh_cd_calc_active_mloopcol_layer(object, me, &cd_needed);
BLI_assert(cd_needed.vcol != 0 &&
"No MLOOPCOL layer available in vertpaint, but batches requested anyway!");
@@ -1103,11 +1136,11 @@ static void texpaint_request_active_vcol(MeshBatchCache *cache, Mesh *me)
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
}
-static void sculpt_request_active_vcol(MeshBatchCache *cache, Mesh *me)
+static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Mesh *me)
{
DRW_MeshAttributes attrs_needed;
drw_mesh_attributes_clear(&attrs_needed);
- mesh_cd_calc_active_vcol_layer(me, &attrs_needed);
+ mesh_cd_calc_active_vcol_layer(object, me, &attrs_needed);
BLI_assert(attrs_needed.num_requests != 0 &&
"No MPropCol layer available in Sculpt, but batches requested anyway!");
@@ -1180,7 +1213,8 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(Mesh *me)
return DRW_batch_request(&cache->batch.edit_mesh_analysis);
}
-GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
+GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object,
+ Mesh *me,
struct GPUMaterial **gpumat_array,
uint gpumat_array_len)
{
@@ -1188,7 +1222,7 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
DRW_MeshAttributes attrs_needed;
drw_mesh_attributes_clear(&attrs_needed);
DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers(
- me, gpumat_array, gpumat_array_len, &attrs_needed);
+ object, me, gpumat_array, gpumat_array_len, &attrs_needed);
BLI_assert(gpumat_array_len == cache->mat_len);
@@ -1199,41 +1233,41 @@ GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Mesh *me,
return cache->surface_per_mat;
}
-GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Mesh *me)
+GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ texpaint_request_active_uv(cache, object, me);
mesh_batch_cache_request_surface_batches(cache);
return cache->surface_per_mat;
}
-GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ texpaint_request_active_uv(cache, object, me);
mesh_batch_cache_request_surface_batches(cache);
return cache->batch.surface;
}
-GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_vcol(cache, me);
+ texpaint_request_active_vcol(cache, object, me);
mesh_batch_cache_request_surface_batches(cache);
return cache->batch.surface;
}
-GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- sculpt_request_active_vcol(cache, me);
+ sculpt_request_active_vcol(cache, object, me);
mesh_batch_cache_request_surface_batches(cache);
return cache->batch.surface;
}
-int DRW_mesh_material_count_get(const Mesh *me)
+int DRW_mesh_material_count_get(const Object *object, const Mesh *me)
{
- return mesh_render_mat_len_get(me);
+ return mesh_render_mat_len_get(object, me);
}
GPUBatch *DRW_mesh_batch_cache_get_sculpt_overlays(Mesh *me)
@@ -1358,26 +1392,27 @@ GPUBatch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me)
/** \name UV Image editor API
* \{ */
-static void edituv_request_active_uv(MeshBatchCache *cache, Mesh *me)
+static void edituv_request_active_uv(MeshBatchCache *cache, Object *object, Mesh *me)
{
DRW_MeshCDMask cd_needed;
mesh_cd_layers_type_clear(&cd_needed);
- mesh_cd_calc_active_uv_layer(me, &cd_needed);
+ mesh_cd_calc_active_uv_layer(object, me, &cd_needed);
mesh_cd_calc_edit_uv_layer(me, &cd_needed);
BLI_assert(cd_needed.edit_uv != 0 &&
"No uv layer available in edituv, but batches requested anyway!");
- mesh_cd_calc_active_mask_uv_layer(me, &cd_needed);
+ mesh_cd_calc_active_mask_uv_layer(object, me, &cd_needed);
mesh_cd_layers_type_merge(&cache->cd_needed, cd_needed);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me,
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Object *object,
+ Mesh *me,
float **tot_area,
float **tot_uv_area)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA);
if (tot_area != NULL) {
@@ -1389,58 +1424,58 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Mesh *me,
return DRW_batch_request(&cache->batch.edituv_faces_stretch_area);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_ANGLE);
return DRW_batch_request(&cache->batch.edituv_faces_stretch_angle);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_faces(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES);
return DRW_batch_request(&cache->batch.edituv_faces);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_edges(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_EDGES);
return DRW_batch_request(&cache->batch.edituv_edges);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_verts(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_VERTS);
return DRW_batch_request(&cache->batch.edituv_verts);
}
-GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_edituv_facedots(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACEDOTS);
return DRW_batch_request(&cache->batch.edituv_fdots);
}
-GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_uv_edges(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- edituv_request_active_uv(cache, me);
+ edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS_UVS);
return DRW_batch_request(&cache->batch.wire_loops_uvs);
}
-GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Mesh *me)
+GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Object *object, Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
- texpaint_request_active_uv(cache, me);
+ texpaint_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_WIRE_LOOPS);
return DRW_batch_request(&cache->batch.wire_loops);
}
@@ -1543,20 +1578,12 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
/* Sanity check. */
if ((me->edit_mesh != NULL) && (ob->mode & OB_MODE_EDIT)) {
- BLI_assert(me->edit_mesh->mesh_eval_final != NULL);
+ BLI_assert(BKE_object_get_editmesh_eval_final(ob) != NULL);
}
- /* Don't check `DRW_object_is_in_edit_mode(ob)` here because it means the same mesh
- * may draw with edit-mesh data and regular mesh data.
- * In this case the custom-data layers used won't always match in `me->runtime.batch_cache`.
- * If we want to display regular mesh data, we should have a separate cache for the edit-mesh.
- * See T77359. */
const bool is_editmode = (me->edit_mesh != NULL) &&
- /* In rare cases we have the edit-mode data but not the generated cache.
- * This can happen when switching an objects data to a mesh which
- * happens to be in edit-mode in another scene, see: T82952. */
- (me->edit_mesh->mesh_eval_final !=
- NULL) /* && DRW_object_is_in_edit_mode(ob) */;
+ (BKE_object_get_editmesh_eval_final(ob) != NULL) &&
+ DRW_object_is_in_edit_mode(ob);
/* This could be set for paint mode too, currently it's only used for edit-mode. */
const bool is_mode_active = is_editmode && DRW_object_is_in_edit_mode(ob);
@@ -1582,7 +1609,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
/* Modifiers will only generate an orco layer if the mesh is deformed. */
if (cache->cd_needed.orco != 0) {
/* Orco is always extracted from final mesh. */
- Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
+ Mesh *me_final = (me->edit_mesh) ? BKE_object_get_editmesh_eval_final(ob) : me;
if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) {
/* Skip orco calculation */
cache->cd_needed.orco = 0;
@@ -1688,10 +1715,18 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
cache->batch_ready |= batch_requested;
- const bool do_cage = (is_editmode &&
- (me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage));
+ bool do_cage = false, do_uvcage = false;
+ if (is_editmode) {
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
+
+ do_cage = editmesh_eval_final != editmesh_eval_cage;
+ do_uvcage = !editmesh_eval_final->runtime.is_original;
+ }
- const bool do_uvcage = is_editmode && !me->edit_mesh->mesh_eval_final->runtime.is_original;
+ const int required_mode = BKE_subsurf_modifier_eval_required_mode(DRW_state_is_scene_render(),
+ is_editmode);
+ const bool do_subdivision = BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ob, required_mode);
MeshBufferList *mbuflist = &cache->final.buff;
@@ -2008,6 +2043,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mesh_buffer_cache_create_requested(task_graph,
cache,
&cache->uv_cage,
+ ob,
me,
is_editmode,
is_paint_mode,
@@ -2025,6 +2061,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mesh_buffer_cache_create_requested(task_graph,
cache,
&cache->cage,
+ ob,
me,
is_editmode,
is_paint_mode,
@@ -2038,9 +2075,19 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
true);
}
+ if (do_subdivision) {
+ DRW_create_subdivision(scene, ob, me, cache, &cache->final, ts);
+ }
+ else {
+ /* The subsurf modifier may have been recently removed, or another modifier was added after it,
+ * so free any potential subdivision cache as it is not needed anymore. */
+ mesh_batch_cache_free_subdiv_cache(cache);
+ }
+
mesh_buffer_cache_create_requested(task_graph,
cache,
&cache->final,
+ ob,
me,
is_editmode,
is_paint_mode,
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 4583b90b144..9493a6debeb 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -634,7 +634,7 @@ static void particle_batch_cache_fill_segments_proc_pos(ParticleCacheKey **path_
seg_data[3] = total_len;
co_prev = path[j].co;
}
- /* Assign length value*/
+ /* Assign length value. */
*(float *)GPU_vertbuf_raw_step(length_step) = total_len;
if (total_len > 0.0f) {
/* Divide by total length to have a [0-1] number. */
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
new file mode 100644
index 00000000000..a24a3a5a3a7
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -0,0 +1,1944 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "draw_subdivision.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_eval.h"
+#include "BKE_subdiv_foreach.h"
+#include "BKE_subdiv_mesh.h"
+#include "BKE_subdiv_modifier.h"
+
+#include "BLI_linklist.h"
+
+#include "BLI_string.h"
+
+#include "PIL_time.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "GPU_capabilities.h"
+#include "GPU_compute.h"
+#include "GPU_index_buffer.h"
+#include "GPU_state.h"
+#include "GPU_vertex_buffer.h"
+
+#include "opensubdiv_capi.h"
+#include "opensubdiv_capi_type.h"
+#include "opensubdiv_converter_capi.h"
+#include "opensubdiv_evaluator_capi.h"
+#include "opensubdiv_topology_refiner_capi.h"
+
+#include "draw_cache_extract.h"
+#include "draw_cache_impl.h"
+#include "draw_cache_inline.h"
+#include "mesh_extractors/extract_mesh.h"
+
+extern "C" char datatoc_common_subdiv_custom_data_interp_comp_glsl[];
+extern "C" char datatoc_common_subdiv_ibo_lines_comp_glsl[];
+extern "C" char datatoc_common_subdiv_ibo_tris_comp_glsl[];
+extern "C" char datatoc_common_subdiv_lib_glsl[];
+extern "C" char datatoc_common_subdiv_normals_accumulate_comp_glsl[];
+extern "C" char datatoc_common_subdiv_normals_finalize_comp_glsl[];
+extern "C" char datatoc_common_subdiv_patch_evaluation_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_edge_fac_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_lnor_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_sculpt_data_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_edituv_strech_angle_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_edituv_strech_area_comp_glsl[];
+
+enum {
+ SHADER_BUFFER_LINES,
+ SHADER_BUFFER_LINES_LOOSE,
+ SHADER_BUFFER_EDGE_FAC,
+ SHADER_BUFFER_LNOR,
+ SHADER_BUFFER_TRIS,
+ SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS,
+ SHADER_BUFFER_NORMALS_ACCUMULATE,
+ SHADER_BUFFER_NORMALS_FINALIZE,
+ SHADER_PATCH_EVALUATION,
+ SHADER_PATCH_EVALUATION_LIMIT_NORMALS,
+ SHADER_PATCH_EVALUATION_FVAR,
+ SHADER_PATCH_EVALUATION_FACE_DOTS,
+ SHADER_COMP_CUSTOM_DATA_INTERP_1D,
+ SHADER_COMP_CUSTOM_DATA_INTERP_2D,
+ SHADER_COMP_CUSTOM_DATA_INTERP_3D,
+ SHADER_COMP_CUSTOM_DATA_INTERP_4D,
+ SHADER_BUFFER_SCULPT_DATA,
+ SHADER_BUFFER_UV_STRETCH_ANGLE,
+ SHADER_BUFFER_UV_STRETCH_AREA,
+
+ NUM_SHADERS,
+};
+
+static GPUShader *g_subdiv_shaders[NUM_SHADERS];
+
+static const char *get_shader_code(int shader_type)
+{
+ switch (shader_type) {
+ case SHADER_BUFFER_LINES:
+ case SHADER_BUFFER_LINES_LOOSE: {
+ return datatoc_common_subdiv_ibo_lines_comp_glsl;
+ }
+ case SHADER_BUFFER_EDGE_FAC: {
+ return datatoc_common_subdiv_vbo_edge_fac_comp_glsl;
+ }
+ case SHADER_BUFFER_LNOR: {
+ return datatoc_common_subdiv_vbo_lnor_comp_glsl;
+ }
+ case SHADER_BUFFER_TRIS:
+ case SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS: {
+ return datatoc_common_subdiv_ibo_tris_comp_glsl;
+ }
+ case SHADER_BUFFER_NORMALS_ACCUMULATE: {
+ return datatoc_common_subdiv_normals_accumulate_comp_glsl;
+ }
+ case SHADER_BUFFER_NORMALS_FINALIZE: {
+ return datatoc_common_subdiv_normals_finalize_comp_glsl;
+ }
+ case SHADER_PATCH_EVALUATION:
+ case SHADER_PATCH_EVALUATION_LIMIT_NORMALS:
+ case SHADER_PATCH_EVALUATION_FVAR:
+ case SHADER_PATCH_EVALUATION_FACE_DOTS: {
+ return datatoc_common_subdiv_patch_evaluation_comp_glsl;
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_1D:
+ case SHADER_COMP_CUSTOM_DATA_INTERP_2D:
+ case SHADER_COMP_CUSTOM_DATA_INTERP_3D:
+ case SHADER_COMP_CUSTOM_DATA_INTERP_4D: {
+ return datatoc_common_subdiv_custom_data_interp_comp_glsl;
+ }
+ case SHADER_BUFFER_SCULPT_DATA: {
+ return datatoc_common_subdiv_vbo_sculpt_data_comp_glsl;
+ }
+ case SHADER_BUFFER_UV_STRETCH_ANGLE: {
+ return datatoc_common_subdiv_vbo_edituv_strech_angle_comp_glsl;
+ }
+ case SHADER_BUFFER_UV_STRETCH_AREA: {
+ return datatoc_common_subdiv_vbo_edituv_strech_area_comp_glsl;
+ }
+ }
+ return nullptr;
+}
+
+static const char *get_shader_name(int shader_type)
+{
+ switch (shader_type) {
+ case SHADER_BUFFER_LINES: {
+ return "subdiv lines build";
+ }
+ case SHADER_BUFFER_LINES_LOOSE: {
+ return "subdiv lines loose build";
+ }
+ case SHADER_BUFFER_LNOR: {
+ return "subdiv lnor build";
+ }
+ case SHADER_BUFFER_EDGE_FAC: {
+ return "subdiv edge fac build";
+ }
+ case SHADER_BUFFER_TRIS:
+ case SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS: {
+ return "subdiv tris";
+ }
+ case SHADER_BUFFER_NORMALS_ACCUMULATE: {
+ return "subdiv normals accumulate";
+ }
+ case SHADER_BUFFER_NORMALS_FINALIZE: {
+ return "subdiv normals finalize";
+ }
+ case SHADER_PATCH_EVALUATION: {
+ return "subdiv patch evaluation";
+ }
+ case SHADER_PATCH_EVALUATION_LIMIT_NORMALS: {
+ return "subdiv patch evaluation limit normals";
+ }
+ case SHADER_PATCH_EVALUATION_FVAR: {
+ return "subdiv patch evaluation face-varying";
+ }
+ case SHADER_PATCH_EVALUATION_FACE_DOTS: {
+ return "subdiv patch evaluation face dots";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_1D: {
+ return "subdiv custom data interp 1D";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_2D: {
+ return "subdiv custom data interp 2D";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_3D: {
+ return "subdiv custom data interp 3D";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_4D: {
+ return "subdiv custom data interp 4D";
+ }
+ case SHADER_BUFFER_SCULPT_DATA: {
+ return "subdiv sculpt data";
+ }
+ case SHADER_BUFFER_UV_STRETCH_ANGLE: {
+ return "subdiv uv stretch angle";
+ }
+ case SHADER_BUFFER_UV_STRETCH_AREA: {
+ return "subdiv uv stretch area";
+ }
+ }
+ return nullptr;
+}
+
+static GPUShader *get_patch_evaluation_shader(int shader_type)
+{
+ if (g_subdiv_shaders[shader_type] == nullptr) {
+ const char *compute_code = get_shader_code(shader_type);
+
+ const char *defines = nullptr;
+ if (shader_type == SHADER_PATCH_EVALUATION_LIMIT_NORMALS) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define LIMIT_NORMALS\n";
+ }
+ else if (shader_type == SHADER_PATCH_EVALUATION_FVAR) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define FVAR_EVALUATION\n";
+ }
+ else if (shader_type == SHADER_PATCH_EVALUATION_FACE_DOTS) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define FDOTS_EVALUATION\n";
+ }
+ else {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n";
+ }
+
+ /* Merge OpenSubdiv library code with our own library code. */
+ const char *patch_basis_source = openSubdiv_getGLSLPatchBasisSource();
+ const char *subdiv_lib_code = datatoc_common_subdiv_lib_glsl;
+ char *library_code = static_cast<char *>(
+ MEM_mallocN(strlen(patch_basis_source) + strlen(subdiv_lib_code) + 1,
+ "subdiv patch evaluation library code"));
+ library_code[0] = '\0';
+ strcat(library_code, patch_basis_source);
+ strcat(library_code, subdiv_lib_code);
+
+ g_subdiv_shaders[shader_type] = GPU_shader_create_compute(
+ compute_code, library_code, defines, get_shader_name(shader_type));
+
+ MEM_freeN(library_code);
+ }
+
+ return g_subdiv_shaders[shader_type];
+}
+
+static GPUShader *get_subdiv_shader(int shader_type, const char *defines)
+{
+ if (ELEM(shader_type,
+ SHADER_PATCH_EVALUATION,
+ SHADER_PATCH_EVALUATION_LIMIT_NORMALS,
+ SHADER_PATCH_EVALUATION_FVAR,
+ SHADER_PATCH_EVALUATION_FACE_DOTS)) {
+ return get_patch_evaluation_shader(shader_type);
+ }
+ if (g_subdiv_shaders[shader_type] == nullptr) {
+ const char *compute_code = get_shader_code(shader_type);
+ g_subdiv_shaders[shader_type] = GPU_shader_create_compute(
+ compute_code, datatoc_common_subdiv_lib_glsl, defines, get_shader_name(shader_type));
+ }
+ return g_subdiv_shaders[shader_type];
+}
+
+/* -------------------------------------------------------------------- */
+/** Vertex formats used for data transfer from OpenSubdiv, and for data processing on our side.
+ * \{ */
+
+static GPUVertFormat *get_uvs_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+/* Vertex format for `OpenSubdiv::Osd::PatchArray`. */
+static GPUVertFormat *get_patch_array_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "regDesc", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "desc", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "numPatches", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "indexBase", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "stride", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "primitiveIdBase", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format used for the `PatchTable::PatchHandle`. */
+static GPUVertFormat *get_patch_handle_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "vertex_index", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "array_index", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "patch_index", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format used for the quad-tree nodes of the PatchMap. */
+static GPUVertFormat *get_quadtree_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "child", GPU_COMP_U32, 4, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format for `OpenSubdiv::Osd::PatchParam`, not really used, it is only for making sure
+ * that the #GPUVertBuf used to wrap the OpenSubdiv patch param buffer is valid. */
+static GPUVertFormat *get_patch_param_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+/* Vertex format for the patches' vertices index buffer. */
+static GPUVertFormat *get_patch_index_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format for the OpenSubdiv vertex buffer. */
+static GPUVertFormat *get_subdiv_vertex_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* We use 4 components for the vectors to account for padding in the compute shaders, where
+ * vec3 is promoted to vec4. */
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+struct CompressedPatchCoord {
+ int ptex_face_index;
+ /* UV coordinate encoded as u << 16 | v, where u and v are quantized on 16-bits. */
+ unsigned int encoded_uv;
+};
+
+MINLINE CompressedPatchCoord make_patch_coord(int ptex_face_index, float u, float v)
+{
+ CompressedPatchCoord patch_coord = {
+ ptex_face_index,
+ (static_cast<unsigned int>(u * 65535.0f) << 16) | static_cast<unsigned int>(v * 65535.0f),
+ };
+ return patch_coord;
+}
+
+/* Vertex format used for the #CompressedPatchCoord. */
+static GPUVertFormat *get_blender_patch_coords_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* WARNING! Adjust #CompressedPatchCoord accordingly. */
+ GPU_vertformat_attr_add(&format, "ptex_face_index", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "uv", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+static GPUVertFormat *get_origindex_format()
+{
+ static GPUVertFormat format;
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities to initialize a OpenSubdiv_Buffer for a GPUVertBuf.
+ * \{ */
+
+static void vertbuf_bind_gpu(const OpenSubdiv_Buffer *buffer)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(buffer->data);
+ GPU_vertbuf_use(verts);
+}
+
+static void *vertbuf_alloc(const OpenSubdiv_Buffer *interface, const uint len)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ GPU_vertbuf_data_alloc(verts, len);
+ return GPU_vertbuf_get_data(verts);
+}
+
+static void vertbuf_device_alloc(const OpenSubdiv_Buffer *interface, const uint len)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ /* This assumes that GPU_USAGE_DEVICE_ONLY was used, which won't allocate host memory. */
+ // BLI_assert(GPU_vertbuf_get_usage(verts) == GPU_USAGE_DEVICE_ONLY);
+ GPU_vertbuf_data_alloc(verts, len);
+}
+
+static void vertbuf_wrap_device_handle(const OpenSubdiv_Buffer *interface, uint64_t handle)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ GPU_vertbuf_wrap_handle(verts, handle);
+}
+
+static void vertbuf_update_data(const OpenSubdiv_Buffer *interface,
+ uint start,
+ uint len,
+ const void *data)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ GPU_vertbuf_update_sub(verts, start, len, data);
+}
+
+static void opensubdiv_gpu_buffer_init(OpenSubdiv_Buffer *buffer_interface, GPUVertBuf *vertbuf)
+{
+ buffer_interface->data = vertbuf;
+ buffer_interface->bind_gpu = vertbuf_bind_gpu;
+ buffer_interface->buffer_offset = 0;
+ buffer_interface->wrap_device_handle = vertbuf_wrap_device_handle;
+ buffer_interface->alloc = vertbuf_alloc;
+ buffer_interface->device_alloc = vertbuf_device_alloc;
+ buffer_interface->device_update = vertbuf_update_data;
+}
+
+static GPUVertBuf *create_buffer_and_interface(OpenSubdiv_Buffer *interface, GPUVertFormat *format)
+{
+ GPUVertBuf *buffer = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(buffer, format, GPU_USAGE_DEVICE_ONLY);
+ opensubdiv_gpu_buffer_init(interface, buffer);
+ return buffer;
+}
+
+/** \} */
+
+// --------------------------------------------------------
+
+static uint tris_count_from_number_of_loops(const uint number_of_loops)
+{
+ const uint32_t number_of_quads = number_of_loops / 4;
+ return number_of_quads * 2;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities to build a GPUVertBuf from an origindex buffer.
+ * \{ */
+
+void draw_subdiv_init_origindex_buffer(GPUVertBuf *buffer,
+ int *vert_origindex,
+ uint num_loops,
+ uint loose_len)
+{
+ GPU_vertbuf_init_with_format_ex(buffer, get_origindex_format(), GPU_USAGE_STATIC);
+ GPU_vertbuf_data_alloc(buffer, num_loops + loose_len);
+
+ int *vbo_data = (int *)GPU_vertbuf_get_data(buffer);
+ memcpy(vbo_data, vert_origindex, num_loops * sizeof(int));
+}
+
+GPUVertBuf *draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_loops)
+{
+ GPUVertBuf *buffer = GPU_vertbuf_calloc();
+ draw_subdiv_init_origindex_buffer(buffer, vert_origindex, num_loops, 0);
+ return buffer;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities for DRWPatchMap.
+ * \{ */
+
+static void draw_patch_map_build(DRWPatchMap *gpu_patch_map, Subdiv *subdiv)
+{
+ GPUVertBuf *patch_map_handles = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(patch_map_handles, get_patch_handle_format(), GPU_USAGE_STATIC);
+
+ GPUVertBuf *patch_map_quadtree = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(patch_map_quadtree, get_quadtree_format(), GPU_USAGE_STATIC);
+
+ OpenSubdiv_Buffer patch_map_handles_interface;
+ opensubdiv_gpu_buffer_init(&patch_map_handles_interface, patch_map_handles);
+
+ OpenSubdiv_Buffer patch_map_quad_tree_interface;
+ opensubdiv_gpu_buffer_init(&patch_map_quad_tree_interface, patch_map_quadtree);
+
+ int min_patch_face = 0;
+ int max_patch_face = 0;
+ int max_depth = 0;
+ int patches_are_triangular = 0;
+
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+ evaluator->getPatchMap(evaluator,
+ &patch_map_handles_interface,
+ &patch_map_quad_tree_interface,
+ &min_patch_face,
+ &max_patch_face,
+ &max_depth,
+ &patches_are_triangular);
+
+ gpu_patch_map->patch_map_handles = patch_map_handles;
+ gpu_patch_map->patch_map_quadtree = patch_map_quadtree;
+ gpu_patch_map->min_patch_face = min_patch_face;
+ gpu_patch_map->max_patch_face = max_patch_face;
+ gpu_patch_map->max_depth = max_depth;
+ gpu_patch_map->patches_are_triangular = patches_are_triangular;
+}
+
+static void draw_patch_map_free(DRWPatchMap *gpu_patch_map)
+{
+ GPU_VERTBUF_DISCARD_SAFE(gpu_patch_map->patch_map_handles);
+ GPU_VERTBUF_DISCARD_SAFE(gpu_patch_map->patch_map_quadtree);
+ gpu_patch_map->min_patch_face = 0;
+ gpu_patch_map->max_patch_face = 0;
+ gpu_patch_map->max_depth = 0;
+ gpu_patch_map->patches_are_triangular = 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DRWSubdivCache
+ * \{ */
+
+static void draw_subdiv_cache_free_material_data(DRWSubdivCache *cache)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache->polygon_mat_offset);
+ MEM_SAFE_FREE(cache->mat_start);
+ MEM_SAFE_FREE(cache->mat_end);
+}
+
+static void draw_subdiv_free_edit_mode_cache(DRWSubdivCache *cache)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache->verts_orig_index);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edges_orig_index);
+ GPU_VERTBUF_DISCARD_SAFE(cache->fdots_patch_coords);
+}
+
+void draw_subdiv_cache_free(DRWSubdivCache *cache)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache->patch_coords);
+ GPU_VERTBUF_DISCARD_SAFE(cache->face_ptex_offset_buffer);
+ GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_polygon_offset_buffer);
+ GPU_VERTBUF_DISCARD_SAFE(cache->extra_coarse_face_data);
+ MEM_SAFE_FREE(cache->subdiv_loop_subdiv_vert_index);
+ MEM_SAFE_FREE(cache->subdiv_loop_poly_index);
+ MEM_SAFE_FREE(cache->point_indices);
+ MEM_SAFE_FREE(cache->subdiv_polygon_offset);
+ GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_vertex_face_adjacency_offsets);
+ GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_vertex_face_adjacency);
+ cache->resolution = 0;
+ cache->num_subdiv_loops = 0;
+ cache->num_subdiv_edges = 0;
+ cache->num_subdiv_verts = 0;
+ cache->num_subdiv_triangles = 0;
+ cache->num_coarse_poly = 0;
+ cache->num_subdiv_quads = 0;
+ draw_subdiv_free_edit_mode_cache(cache);
+ draw_subdiv_cache_free_material_data(cache);
+ draw_patch_map_free(&cache->gpu_patch_map);
+ if (cache->ubo) {
+ GPU_uniformbuf_free(cache->ubo);
+ cache->ubo = nullptr;
+ }
+}
+
+/* Flags used in #DRWSubdivCache.extra_coarse_face_data. The flags are packed in the upper bits of
+ * each uint (one per coarse face), #SUBDIV_COARSE_FACE_FLAG_OFFSET tells where they are in the
+ * packed bits. */
+#define SUBDIV_COARSE_FACE_FLAG_SMOOTH 1u
+#define SUBDIV_COARSE_FACE_FLAG_SELECT 2u
+#define SUBDIV_COARSE_FACE_FLAG_ACTIVE 4u
+
+#define SUBDIV_COARSE_FACE_FLAG_OFFSET 29u
+
+#define SUBDIV_COARSE_FACE_FLAG_SMOOTH_MASK \
+ (SUBDIV_COARSE_FACE_FLAG_SMOOTH << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+#define SUBDIV_COARSE_FACE_FLAG_SELECT_MASK \
+ (SUBDIV_COARSE_FACE_FLAG_SELECT << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+#define SUBDIV_COARSE_FACE_FLAG_ACTIVE_MASK \
+ (SUBDIV_COARSE_FACE_FLAG_ACTIVE << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+
+#define SUBDIV_COARSE_FACE_LOOP_START_MASK \
+ ~((SUBDIV_COARSE_FACE_FLAG_SMOOTH | SUBDIV_COARSE_FACE_FLAG_SELECT | \
+ SUBDIV_COARSE_FACE_FLAG_ACTIVE) \
+ << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+
+static void draw_subdiv_cache_update_extra_coarse_face_data(DRWSubdivCache *cache, Mesh *mesh)
+{
+ if (cache->extra_coarse_face_data == nullptr) {
+ cache->extra_coarse_face_data = GPU_vertbuf_calloc();
+ static GPUVertFormat format;
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ GPU_vertbuf_init_with_format_ex(cache->extra_coarse_face_data, &format, GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->extra_coarse_face_data, mesh->totpoly);
+ }
+
+ uint32_t *flags_data = (uint32_t *)(GPU_vertbuf_get_data(cache->extra_coarse_face_data));
+
+ if (cache->bm) {
+ BMesh *bm = cache->bm;
+ BMFace *f;
+ BMIter iter;
+
+ /* Ensure all current elements follow new customdata layout. */
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ const int index = BM_elem_index_get(f);
+ uint32_t flag = 0;
+ if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH;
+ }
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_SELECT;
+ }
+ if (f == bm->act_face) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_ACTIVE;
+ }
+ const int loopstart = BM_elem_index_get(f->l_first);
+ flags_data[index] = (uint)(loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totpoly; i++) {
+ uint32_t flag = 0;
+ if ((mesh->mpoly[i].flag & ME_SMOOTH) != 0) {
+ flag = SUBDIV_COARSE_FACE_FLAG_SMOOTH;
+ }
+ flags_data[i] = (uint)(mesh->mpoly[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
+ }
+ }
+
+ /* Make sure updated data is re-uploaded. */
+ GPU_vertbuf_tag_dirty(cache->extra_coarse_face_data);
+}
+
+static DRWSubdivCache *mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache *mbc)
+{
+ DRWSubdivCache *subdiv_cache = mbc->subdiv_cache;
+ if (subdiv_cache == nullptr) {
+ subdiv_cache = static_cast<DRWSubdivCache *>(
+ MEM_callocN(sizeof(DRWSubdivCache), "DRWSubdivCache"));
+ }
+ mbc->subdiv_cache = subdiv_cache;
+ return subdiv_cache;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Subdivision grid traversal.
+ *
+ * Traverse the uniform subdivision grid over coarse faces and gather useful information for
+ * building the draw buffers on the GPU. We primarily gather the patch coordinates for all
+ * subdivision faces, as well as the original coarse indices for each subdivision element (vertex,
+ * face, or edge) which directly maps to its coarse counterpart (note that all subdivision faces
+ * map to a coarse face). This information will then be cached in #DRWSubdivCache for subsequent
+ * reevaluations, as long as the topology does not change.
+ * \{ */
+
+struct DRWCacheBuildingContext {
+ const Mesh *coarse_mesh;
+ const SubdivToMeshSettings *settings;
+
+ DRWSubdivCache *cache;
+
+ /* Pointers into DRWSubdivCache buffers for easier access during traversal. */
+ CompressedPatchCoord *patch_coords;
+ int *subdiv_loop_vert_index;
+ int *subdiv_loop_subdiv_vert_index;
+ int *subdiv_loop_edge_index;
+ int *subdiv_loop_poly_index;
+ int *point_indices;
+
+ /* Temporary buffers used during traversal. */
+ int *vert_origindex_map;
+ int *edge_origindex_map;
+
+ /* Origindex layers from the mesh to directly look up during traversal the origindex from the
+ * base mesh for edit data so that we do not have to handle yet another GPU buffer and do this in
+ * the shaders. */
+ int *v_origindex;
+ int *e_origindex;
+};
+
+static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_context,
+ const int num_vertices,
+ const int num_edges,
+ const int num_loops,
+ const int num_polygons,
+ const int *subdiv_polygon_offset)
+{
+ if (num_loops == 0) {
+ return false;
+ }
+
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+ DRWSubdivCache *cache = ctx->cache;
+
+ /* Set topology information. */
+ cache->num_subdiv_edges = (uint)num_edges;
+ cache->num_subdiv_loops = (uint)num_loops;
+ cache->num_subdiv_verts = (uint)num_vertices;
+ cache->num_subdiv_quads = (uint)num_polygons;
+ cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset));
+
+ /* Initialize cache buffers, prefer dynamic usage so we can reuse memory on the host even after
+ * it was sent to the device, since we may use the data while building other buffers on the CPU
+ * side. */
+ cache->patch_coords = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(
+ cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->patch_coords, cache->num_subdiv_loops);
+
+ cache->verts_orig_index = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(
+ cache->verts_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->verts_orig_index, cache->num_subdiv_loops);
+
+ cache->edges_orig_index = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(
+ cache->edges_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->edges_orig_index, cache->num_subdiv_loops);
+
+ cache->subdiv_loop_subdiv_vert_index = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_subdiv_vert_index"));
+
+ cache->subdiv_loop_poly_index = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_poly_index"));
+
+ const int num_coarse_vertices = ctx->coarse_mesh->totvert;
+ cache->point_indices = static_cast<int *>(
+ MEM_mallocN(num_coarse_vertices * sizeof(int), "point_indices"));
+ for (int i = 0; i < num_coarse_vertices; i++) {
+ cache->point_indices[i] = -1;
+ }
+
+ /* Initialize context pointers and temporary buffers. */
+ ctx->patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data(cache->patch_coords);
+ ctx->subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(cache->verts_orig_index);
+ ctx->subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(cache->edges_orig_index);
+ ctx->subdiv_loop_subdiv_vert_index = cache->subdiv_loop_subdiv_vert_index;
+ ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index;
+ ctx->point_indices = cache->point_indices;
+
+ ctx->v_origindex = static_cast<int *>(
+ CustomData_get_layer(&ctx->coarse_mesh->vdata, CD_ORIGINDEX));
+
+ ctx->e_origindex = static_cast<int *>(
+ CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX));
+
+ ctx->vert_origindex_map = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map"));
+ for (int i = 0; i < num_vertices; i++) {
+ ctx->vert_origindex_map[i] = -1;
+ }
+
+ ctx->edge_origindex_map = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map"));
+ for (int i = 0; i < num_edges; i++) {
+ ctx->edge_origindex_map[i] = -1;
+ }
+
+ return true;
+}
+
+static void draw_subdiv_vertex_corner_cb(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int UNUSED(ptex_face_index),
+ const float UNUSED(u),
+ const float UNUSED(v),
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
+{
+ BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+ ctx->vert_origindex_map[subdiv_vertex_index] = coarse_vertex_index;
+}
+
+static void draw_subdiv_vertex_edge_cb(const SubdivForeachContext *UNUSED(foreach_context),
+ void *UNUSED(tls_v),
+ const int UNUSED(ptex_face_index),
+ const float UNUSED(u),
+ const float UNUSED(v),
+ const int UNUSED(coarse_edge_index),
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int UNUSED(subdiv_vertex_index))
+{
+ /* Required if SubdivForeachContext.vertex_corner is also set. */
+}
+
+static void draw_subdiv_edge_cb(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_edge_index,
+ const int subdiv_edge_index,
+ const int UNUSED(subdiv_v1),
+ const int UNUSED(subdiv_v2))
+{
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+
+ int coarse_index = coarse_edge_index;
+
+ if (coarse_index != -1) {
+ if (ctx->e_origindex) {
+ coarse_index = ctx->e_origindex[coarse_index];
+ }
+ }
+
+ ctx->edge_origindex_map[subdiv_edge_index] = coarse_index;
+}
+
+static void draw_subdiv_loop_cb(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int UNUSED(coarse_loop_index),
+ const int coarse_poly_index,
+ const int UNUSED(coarse_corner),
+ const int subdiv_loop_index,
+ const int subdiv_vertex_index,
+ const int subdiv_edge_index)
+{
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+ ctx->patch_coords[subdiv_loop_index] = make_patch_coord(ptex_face_index, u, v);
+
+ int coarse_vertex_index = ctx->vert_origindex_map[subdiv_vertex_index];
+
+ if (coarse_vertex_index != -1) {
+ if (ctx->v_origindex) {
+ coarse_vertex_index = ctx->v_origindex[coarse_vertex_index];
+ }
+
+ /* Double check as vorigindex may have modified the index. */
+ if (coarse_vertex_index != -1) {
+ ctx->point_indices[coarse_vertex_index] = subdiv_loop_index;
+ }
+ }
+
+ ctx->subdiv_loop_subdiv_vert_index[subdiv_loop_index] = subdiv_vertex_index;
+ /* For now index the subdiv_edge_index, it will be replaced by the actual coarse edge index
+ * at the end of the traversal as some edges are only then traversed. */
+ ctx->subdiv_loop_edge_index[subdiv_loop_index] = subdiv_edge_index;
+ ctx->subdiv_loop_poly_index[subdiv_loop_index] = coarse_poly_index;
+ ctx->subdiv_loop_vert_index[subdiv_loop_index] = coarse_vertex_index;
+}
+
+static void draw_subdiv_foreach_callbacks(SubdivForeachContext *foreach_context)
+{
+ memset(foreach_context, 0, sizeof(*foreach_context));
+ foreach_context->topology_info = draw_subdiv_topology_info_cb;
+ foreach_context->loop = draw_subdiv_loop_cb;
+ foreach_context->edge = draw_subdiv_edge_cb;
+ foreach_context->vertex_corner = draw_subdiv_vertex_corner_cb;
+ foreach_context->vertex_edge = draw_subdiv_vertex_edge_cb;
+}
+
+static void do_subdiv_traversal(DRWCacheBuildingContext *cache_building_context, Subdiv *subdiv)
+{
+ SubdivForeachContext foreach_context;
+ draw_subdiv_foreach_callbacks(&foreach_context);
+ foreach_context.user_data = cache_building_context;
+
+ BKE_subdiv_foreach_subdiv_geometry(subdiv,
+ &foreach_context,
+ cache_building_context->settings,
+ cache_building_context->coarse_mesh);
+
+ /* Now that traversal is done, we can set up the right original indices for the loop-to-edge map.
+ */
+ for (int i = 0; i < cache_building_context->cache->num_subdiv_loops; i++) {
+ cache_building_context->subdiv_loop_edge_index[i] =
+ cache_building_context
+ ->edge_origindex_map[cache_building_context->subdiv_loop_edge_index[i]];
+ }
+}
+
+static GPUVertBuf *gpu_vertbuf_create_from_format(GPUVertFormat *format, uint len)
+{
+ GPUVertBuf *verts = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(verts, format);
+ GPU_vertbuf_data_alloc(verts, len);
+ return verts;
+}
+
+/* Build maps to hold enough information to tell which face is adjacent to which vertex; those will
+ * be used for computing normals if limit surfaces are unavailable. */
+static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache)
+{
+ /* +1 so that we do not require a special case for the last vertex, this extra offset will
+ * contain the total number of adjacent faces. */
+ cache->subdiv_vertex_face_adjacency_offsets = gpu_vertbuf_create_from_format(
+ get_origindex_format(), cache->num_subdiv_verts + 1);
+
+ int *vertex_offsets = (int *)GPU_vertbuf_get_data(cache->subdiv_vertex_face_adjacency_offsets);
+ memset(vertex_offsets, 0, sizeof(int) * cache->num_subdiv_verts + 1);
+
+ for (int i = 0; i < cache->num_subdiv_loops; i++) {
+ vertex_offsets[cache->subdiv_loop_subdiv_vert_index[i]]++;
+ }
+
+ int ofs = vertex_offsets[0];
+ vertex_offsets[0] = 0;
+ for (uint i = 1; i < cache->num_subdiv_verts + 1; i++) {
+ int tmp = vertex_offsets[i];
+ vertex_offsets[i] = ofs;
+ ofs += tmp;
+ }
+
+ cache->subdiv_vertex_face_adjacency = gpu_vertbuf_create_from_format(get_origindex_format(),
+ cache->num_subdiv_loops);
+ int *adjacent_faces = (int *)GPU_vertbuf_get_data(cache->subdiv_vertex_face_adjacency);
+ int *tmp_set_faces = static_cast<int *>(
+ MEM_callocN(sizeof(int) * cache->num_subdiv_verts, "tmp subdiv vertex offset"));
+
+ for (int i = 0; i < cache->num_subdiv_loops / 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ const int subdiv_vertex = cache->subdiv_loop_subdiv_vert_index[i * 4 + j];
+ int first_face_offset = vertex_offsets[subdiv_vertex] + tmp_set_faces[subdiv_vertex];
+ adjacent_faces[first_face_offset] = i;
+ tmp_set_faces[subdiv_vertex] += 1;
+ }
+ }
+
+ MEM_freeN(tmp_set_faces);
+}
+
+static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
+ Subdiv *subdiv,
+ Mesh *mesh_eval,
+ const Scene *scene,
+ const SubsurfModifierData *smd,
+ const bool is_final_render)
+{
+ const int requested_levels = (is_final_render) ? smd->renderLevels : smd->levels;
+ const int level = get_render_subsurf_level(&scene->r, requested_levels, is_final_render);
+ SubdivToMeshSettings to_mesh_settings;
+ to_mesh_settings.resolution = (1 << level) + 1;
+ to_mesh_settings.use_optimal_display = false;
+
+ if (cache->resolution != to_mesh_settings.resolution) {
+ /* Resolution changed, we need to rebuild, free any existing cached data. */
+ draw_subdiv_cache_free(cache);
+ }
+
+ /* If the resolution between the cache and the settings match for some reason, check if the patch
+ * coordinates were not already generated. Those coordinates are specific to the resolution, so
+ * they should be null either after initialization, or after freeing if the resolution (or some
+ * other subdivision setting) changed.
+ */
+ if (cache->patch_coords != nullptr) {
+ return true;
+ }
+
+ DRWCacheBuildingContext cache_building_context;
+ memset(&cache_building_context, 0, sizeof(DRWCacheBuildingContext));
+ cache_building_context.coarse_mesh = mesh_eval;
+ cache_building_context.settings = &to_mesh_settings;
+ cache_building_context.cache = cache;
+
+ do_subdiv_traversal(&cache_building_context, subdiv);
+ if (cache->num_subdiv_loops == 0) {
+ /* Either the traversal failed, or we have an empty mesh, either way we cannot go any further.
+ * The subdiv_polygon_offset cannot then be reliably stored in the cache, so free it directly.
+ */
+ MEM_SAFE_FREE(cache->subdiv_polygon_offset);
+ return false;
+ }
+
+ /* Build buffers for the PatchMap. */
+ draw_patch_map_build(&cache->gpu_patch_map, subdiv);
+
+ cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+
+ // Build patch coordinates for all the face dots
+ cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(),
+ mesh_eval->totpoly);
+ CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data(
+ cache->fdots_patch_coords);
+ for (int i = 0; i < mesh_eval->totpoly; i++) {
+ const int ptex_face_index = cache->face_ptex_offset[i];
+ if (mesh_eval->mpoly[i].totloop == 4) {
+ /* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */
+ blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f);
+ }
+ else {
+ /* For N-gons, since they are split into quads from the center, and since the center is
+ * chosen to be the top right corner of each quad, the center coordinate of the coarse face
+ * is any one of those top right corners with `u = v = 1.0`. */
+ blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f);
+ }
+ }
+
+ cache->resolution = to_mesh_settings.resolution;
+
+ cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer(
+ cache->subdiv_polygon_offset, mesh_eval->totpoly);
+
+ cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset,
+ mesh_eval->totpoly + 1);
+ cache->num_coarse_poly = mesh_eval->totpoly;
+ cache->point_indices = cache_building_context.point_indices;
+
+ build_vertex_face_adjacency_maps(cache);
+
+ /* Cleanup. */
+ MEM_freeN(cache_building_context.vert_origindex_map);
+ MEM_freeN(cache_building_context.edge_origindex_map);
+
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DRWSubdivUboStorage.
+ *
+ * Common uniforms for the various shaders.
+ * \{ */
+
+struct DRWSubdivUboStorage {
+ /* Offsets in the buffers data where the source and destination data start. */
+ int src_offset;
+ int dst_offset;
+
+ /* Parameters for the DRWPatchMap. */
+ int min_patch_face;
+ int max_patch_face;
+ int max_depth;
+ int patches_are_triangular;
+
+ /* Coarse topology information. */
+ int coarse_poly_count;
+ uint edge_loose_offset;
+
+ /* Refined topology information. */
+ uint num_subdiv_loops;
+
+ /* Subdivision settings, is int in C but bool in the GLSL code, as there, bools have the same
+ * size as ints, so we should use int in C to ensure that the size of the structure is what GLSL
+ * expects. */
+ int optimal_display;
+
+ /* The sculpt mask data layer may be null. */
+ int has_sculpt_mask;
+
+ /* Masks for the extra coarse face data. */
+ uint coarse_face_select_mask;
+ uint coarse_face_smooth_mask;
+ uint coarse_face_active_mask;
+ uint coarse_face_loopstart_mask;
+
+ /* Number of elements to process in the compute shader (can be the coarse quad count, or the
+ * final vertex count, depending on which compute pass we do). This is used to early out in case
+ * of out of bond accesses as compute dispatch are of fixed size. */
+ uint total_dispatch_size;
+};
+
+static_assert((sizeof(DRWSubdivUboStorage) % 16) == 0,
+ "DRWSubdivUboStorage is not padded to a multiple of the size of vec4");
+
+static void draw_subdiv_init_ubo_storage(const DRWSubdivCache *cache,
+ DRWSubdivUboStorage *ubo,
+ const int src_offset,
+ const int dst_offset,
+ const uint total_dispatch_size,
+ const bool has_sculpt_mask)
+{
+ ubo->src_offset = src_offset;
+ ubo->dst_offset = dst_offset;
+ ubo->min_patch_face = cache->gpu_patch_map.min_patch_face;
+ ubo->max_patch_face = cache->gpu_patch_map.max_patch_face;
+ ubo->max_depth = cache->gpu_patch_map.max_depth;
+ ubo->patches_are_triangular = cache->gpu_patch_map.patches_are_triangular;
+ ubo->coarse_poly_count = cache->num_coarse_poly;
+ ubo->optimal_display = cache->optimal_display;
+ ubo->num_subdiv_loops = cache->num_subdiv_loops;
+ ubo->edge_loose_offset = cache->num_subdiv_loops * 2;
+ ubo->has_sculpt_mask = has_sculpt_mask;
+ ubo->coarse_face_smooth_mask = SUBDIV_COARSE_FACE_FLAG_SMOOTH_MASK;
+ ubo->coarse_face_select_mask = SUBDIV_COARSE_FACE_FLAG_SELECT_MASK;
+ ubo->coarse_face_active_mask = SUBDIV_COARSE_FACE_FLAG_ACTIVE_MASK;
+ ubo->coarse_face_loopstart_mask = SUBDIV_COARSE_FACE_LOOP_START_MASK;
+ ubo->total_dispatch_size = total_dispatch_size;
+}
+
+static void draw_subdiv_ubo_update_and_bind(const DRWSubdivCache *cache,
+ GPUShader *shader,
+ const int src_offset,
+ const int dst_offset,
+ const uint total_dispatch_size,
+ const bool has_sculpt_mask = false)
+{
+ DRWSubdivUboStorage storage;
+ draw_subdiv_init_ubo_storage(
+ cache, &storage, src_offset, dst_offset, total_dispatch_size, has_sculpt_mask);
+
+ if (!cache->ubo) {
+ const_cast<DRWSubdivCache *>(cache)->ubo = GPU_uniformbuf_create_ex(
+ sizeof(DRWSubdivUboStorage), &storage, "DRWSubdivUboStorage");
+ }
+
+ GPU_uniformbuf_update(cache->ubo, &storage);
+
+ const int location = GPU_shader_get_uniform_block(shader, "shader_data");
+ GPU_uniformbuf_bind(cache->ubo, location);
+}
+
+/** \} */
+
+// --------------------------------------------------------
+
+#define SUBDIV_LOCAL_WORK_GROUP_SIZE 64
+static uint get_dispatch_size(uint elements)
+{
+ return divide_ceil_u(elements, SUBDIV_LOCAL_WORK_GROUP_SIZE);
+}
+
+/**
+ * Helper to ensure that the UBO is always initialized before dispatching computes and that the
+ * same number of elements that need to be processed is used for the UBO and the dispatch size.
+ * Use this instead of a raw call to #GPU_compute_dispatch.
+ */
+static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache,
+ GPUShader *shader,
+ const int src_offset,
+ const int dst_offset,
+ uint total_dispatch_size,
+ const bool has_sculpt_mask = false)
+{
+ const uint max_res_x = static_cast<uint>(GPU_max_work_group_count(0));
+
+ const uint dispatch_size = get_dispatch_size(total_dispatch_size);
+ uint dispatch_rx = dispatch_size;
+ uint dispatch_ry = 1u;
+ if (dispatch_rx > max_res_x) {
+ /* Since there are some limitations with regards to the maximum work group size (could be as
+ * low as 64k elements per call), we split the number elements into a "2d" number, with the
+ * final index being computed as `res_x + res_y * max_work_group_size`. Even with a maximum
+ * work group size of 64k, that still leaves us with roughly `64k * 64k = 4` billion elements
+ * total, which should be enough. If not, we could also use the 3rd dimension. */
+ /* TODO(fclem): We could dispatch fewer groups if we compute the prime factorization and
+ * get the smallest rect fitting the requirements. */
+ dispatch_rx = dispatch_ry = ceilf(sqrtf(dispatch_size));
+ /* Avoid a completely empty dispatch line caused by rounding. */
+ if ((dispatch_rx * (dispatch_ry - 1)) >= dispatch_size) {
+ dispatch_ry -= 1;
+ }
+ }
+
+ /* X and Y dimensions may have different limits so the above computation may not be right, but
+ * even with the standard 64k minimum on all dimensions we still have a lot of room. Therefore,
+ * we presume it all fits. */
+ BLI_assert(dispatch_ry < static_cast<uint>(GPU_max_work_group_count(1)));
+
+ draw_subdiv_ubo_update_and_bind(
+ cache, shader, src_offset, dst_offset, total_dispatch_size, has_sculpt_mask);
+
+ GPU_compute_dispatch(shader, dispatch_rx, dispatch_ry, 1);
+}
+
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ const bool do_limit_normals)
+{
+ Subdiv *subdiv = cache->subdiv;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+
+ OpenSubdiv_Buffer src_buffer_interface;
+ GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface,
+ get_subdiv_vertex_format());
+ evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface);
+
+ OpenSubdiv_Buffer patch_arrays_buffer_interface;
+ GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
+ get_patch_array_format());
+ evaluator->fillPatchArraysBuffer(evaluator, &patch_arrays_buffer_interface);
+
+ OpenSubdiv_Buffer patch_index_buffer_interface;
+ GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface,
+ get_patch_index_format());
+ evaluator->wrapPatchIndexBuffer(evaluator, &patch_index_buffer_interface);
+
+ OpenSubdiv_Buffer patch_param_buffer_interface;
+ GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface,
+ get_patch_param_format());
+ evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
+
+ GPUShader *shader = get_patch_evaluation_shader(
+ do_limit_normals ? SHADER_PATCH_EVALUATION_LIMIT_NORMALS : SHADER_PATCH_EVALUATION);
+ GPU_shader_bind(shader);
+
+ GPU_vertbuf_bind_as_ssbo(src_buffer, 0);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2);
+ GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4);
+ GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5);
+ GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6);
+ GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7);
+ GPU_vertbuf_bind_as_ssbo(pos_nor, 8);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array.
+ * We also need it for subsequent compute shaders, so a barrier on the shader storage is also
+ * needed. */
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+
+ GPU_vertbuf_discard(patch_index_buffer);
+ GPU_vertbuf_discard(patch_param_buffer);
+ GPU_vertbuf_discard(patch_arrays_buffer);
+ GPU_vertbuf_discard(src_buffer);
+}
+
+void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
+ GPUVertBuf *uvs,
+ const int face_varying_channel,
+ const int dst_offset)
+{
+ Subdiv *subdiv = cache->subdiv;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+
+ OpenSubdiv_Buffer src_buffer_interface;
+ GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, get_uvs_format());
+ evaluator->wrapFVarSrcBuffer(evaluator, face_varying_channel, &src_buffer_interface);
+
+ OpenSubdiv_Buffer patch_arrays_buffer_interface;
+ GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
+ get_patch_array_format());
+ evaluator->fillFVarPatchArraysBuffer(
+ evaluator, face_varying_channel, &patch_arrays_buffer_interface);
+
+ OpenSubdiv_Buffer patch_index_buffer_interface;
+ GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface,
+ get_patch_index_format());
+ evaluator->wrapFVarPatchIndexBuffer(
+ evaluator, face_varying_channel, &patch_index_buffer_interface);
+
+ OpenSubdiv_Buffer patch_param_buffer_interface;
+ GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface,
+ get_patch_param_format());
+ evaluator->wrapFVarPatchParamBuffer(
+ evaluator, face_varying_channel, &patch_param_buffer_interface);
+
+ GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION_FVAR);
+ GPU_shader_bind(shader);
+
+ GPU_vertbuf_bind_as_ssbo(src_buffer, 0);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2);
+ GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4);
+ GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5);
+ GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6);
+ GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7);
+ GPU_vertbuf_bind_as_ssbo(uvs, 8);
+
+ /* The buffer offset has the stride baked in (which is 2 as we have UVs) so remove the stride by
+ * dividing by 2 */
+ const int src_offset = src_buffer_interface.buffer_offset / 2;
+ drw_subdiv_compute_dispatch(cache, shader, src_offset, dst_offset, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array.
+ * Since it may also be used for computing UV stretches, we also need a barrier on the shader
+ * storage. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY | GPU_BARRIER_SHADER_STORAGE);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+
+ GPU_vertbuf_discard(patch_index_buffer);
+ GPU_vertbuf_discard(patch_param_buffer);
+ GPU_vertbuf_discard(patch_arrays_buffer);
+ GPU_vertbuf_discard(src_buffer);
+}
+
+void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
+ GPUVertBuf *src_data,
+ GPUVertBuf *dst_data,
+ int dimensions,
+ int dst_offset)
+{
+ GPUShader *shader = nullptr;
+
+ if (dimensions == 1) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_1D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 1\n");
+ }
+ else if (dimensions == 2) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_2D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 2\n");
+ }
+ else if (dimensions == 3) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_3D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 3\n");
+ }
+ else if (dimensions == 4) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_4D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 4\n"
+ "#define GPU_FETCH_U16_TO_FLOAT\n");
+ }
+ else {
+ /* Crash if dimensions are not supported. */
+ }
+
+ GPU_shader_bind(shader);
+
+ /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
+ GPU_vertbuf_bind_as_ssbo(src_data, 1);
+ GPU_vertbuf_bind_as_ssbo(cache->face_ptex_offset_buffer, 2);
+ GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 4);
+ GPU_vertbuf_bind_as_ssbo(dst_data, 5);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, dst_offset, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_sculpt_data_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *mask_vbo,
+ GPUVertBuf *face_set_vbo,
+ GPUVertBuf *sculpt_data)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_SCULPT_DATA, nullptr);
+ GPU_shader_bind(shader);
+
+ if (mask_vbo) {
+ GPU_vertbuf_bind_as_ssbo(mask_vbo, 0);
+ }
+
+ GPU_vertbuf_bind_as_ssbo(face_set_vbo, 1);
+ GPU_vertbuf_bind_as_ssbo(sculpt_data, 2);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads, mask_vbo != nullptr);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *face_adjacency_offsets,
+ GPUVertBuf *face_adjacency_lists,
+ GPUVertBuf *vertex_normals)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_ACCUMULATE, nullptr);
+ GPU_shader_bind(shader);
+
+ int binding_point = 0;
+
+ GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(face_adjacency_offsets, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(face_adjacency_lists, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(vertex_normals, binding_point++);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_verts);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array.
+ * We also need it for subsequent compute shaders, so a barrier on the shader storage is also
+ * needed. */
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_finalize_normals(const DRWSubdivCache *cache,
+ GPUVertBuf *vertex_normals,
+ GPUVertBuf *subdiv_loop_subdiv_vert_index,
+ GPUVertBuf *pos_nor)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_FINALIZE, nullptr);
+ GPU_shader_bind(shader);
+
+ int binding_point = 0;
+ GPU_vertbuf_bind_as_ssbo(vertex_normals, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(subdiv_loop_subdiv_vert_index, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array.
+ * We also need it for subsequent compute shaders, so a barrier on the shader storage is also
+ * needed. */
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
+ GPUIndexBuf *subdiv_tris,
+ const int material_count)
+{
+ const bool do_single_material = material_count <= 1;
+
+ const char *defines = "#define SUBDIV_POLYGON_OFFSET\n";
+ if (do_single_material) {
+ defines =
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define SINGLE_MATERIAL\n";
+ }
+
+ GPUShader *shader = get_subdiv_shader(
+ do_single_material ? SHADER_BUFFER_TRIS : SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS, defines);
+ GPU_shader_bind(shader);
+
+ /* Outputs */
+ GPU_indexbuf_bind_as_ssbo(subdiv_tris, 1);
+
+ if (!do_single_material) {
+ GPU_vertbuf_bind_as_ssbo(cache->polygon_mat_offset, 2);
+ /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
+ }
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates an index buffer, so we need to put a barrier on the element array. */
+ GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
+ GPUVertBuf *fdots_pos,
+ GPUVertBuf *fdots_nor,
+ GPUIndexBuf *fdots_indices)
+{
+ Subdiv *subdiv = cache->subdiv;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+
+ OpenSubdiv_Buffer src_buffer_interface;
+ GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface,
+ get_subdiv_vertex_format());
+ evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface);
+
+ OpenSubdiv_Buffer patch_arrays_buffer_interface;
+ GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
+ get_patch_array_format());
+ opensubdiv_gpu_buffer_init(&patch_arrays_buffer_interface, patch_arrays_buffer);
+ evaluator->fillPatchArraysBuffer(evaluator, &patch_arrays_buffer_interface);
+
+ OpenSubdiv_Buffer patch_index_buffer_interface;
+ GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface,
+ get_patch_index_format());
+ evaluator->wrapPatchIndexBuffer(evaluator, &patch_index_buffer_interface);
+
+ OpenSubdiv_Buffer patch_param_buffer_interface;
+ GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface,
+ get_patch_param_format());
+ evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
+
+ GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION_FACE_DOTS);
+ GPU_shader_bind(shader);
+
+ GPU_vertbuf_bind_as_ssbo(src_buffer, 0);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2);
+ GPU_vertbuf_bind_as_ssbo(cache->fdots_patch_coords, 3);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4);
+ GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5);
+ GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6);
+ GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7);
+ GPU_vertbuf_bind_as_ssbo(fdots_pos, 8);
+ GPU_vertbuf_bind_as_ssbo(fdots_nor, 9);
+ GPU_indexbuf_bind_as_ssbo(fdots_indices, 10);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 11);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_coarse_poly);
+
+ /* This generates two vertex buffers and an index buffer, so we need to put a barrier on the
+ * vertex attributes and element arrays. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY | GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+
+ GPU_vertbuf_discard(patch_index_buffer);
+ GPU_vertbuf_discard(patch_param_buffer);
+ GPU_vertbuf_discard(patch_arrays_buffer);
+ GPU_vertbuf_discard(src_buffer);
+}
+
+void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache, GPUIndexBuf *lines_indices)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES, nullptr);
+ GPU_shader_bind(shader);
+
+ GPU_vertbuf_bind_as_ssbo(cache->edges_orig_index, 0);
+ GPU_indexbuf_bind_as_ssbo(lines_indices, 1);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates an index buffer, so we need to put a barrier on the element array. */
+ GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
+ GPUIndexBuf *lines_indices,
+ uint num_loose_edges)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES_LOOSE, "#define LINES_LOOSE\n");
+ GPU_shader_bind(shader);
+
+ GPU_indexbuf_bind_as_ssbo(lines_indices, 1);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, num_loose_edges);
+
+ /* This generates an index buffer, so we need to put a barrier on the element array. */
+ GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *edge_idx,
+ GPUVertBuf *edge_fac)
+{
+ /* No separate shader for the AMD driver case as we assume that the GPU will not change during
+ * the execution of the program. */
+ const char *defines = GPU_crappy_amd_driver() ? "#define GPU_AMD_DRIVER_BYTE_BUG\n" : nullptr;
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_EDGE_FAC, defines);
+ GPU_shader_bind(shader);
+
+ GPU_vertbuf_bind_as_ssbo(pos_nor, 0);
+ GPU_vertbuf_bind_as_ssbo(edge_idx, 1);
+ GPU_vertbuf_bind_as_ssbo(edge_fac, 2);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *lnor)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LNOR, "#define SUBDIV_POLYGON_OFFSET\n");
+ GPU_shader_bind(shader);
+
+ /* Inputs */
+ GPU_vertbuf_bind_as_ssbo(pos_nor, 1);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 2);
+ /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
+
+ /* Outputs */
+ GPU_vertbuf_bind_as_ssbo(lnor, 3);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_edituv_stretch_area_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *coarse_data,
+ GPUVertBuf *subdiv_data)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_UV_STRETCH_AREA,
+ "#define SUBDIV_POLYGON_OFFSET\n");
+ GPU_shader_bind(shader);
+
+ /* Inputs */
+ GPU_vertbuf_bind_as_ssbo(coarse_data, 1);
+ /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
+
+ /* Outputs */
+ GPU_vertbuf_bind_as_ssbo(subdiv_data, 2);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *uvs,
+ int uvs_offset,
+ GPUVertBuf *stretch_angles)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_UV_STRETCH_ANGLE, nullptr);
+ GPU_shader_bind(shader);
+
+ /* Inputs */
+ GPU_vertbuf_bind_as_ssbo(pos_nor, 0);
+ GPU_vertbuf_bind_as_ssbo(uvs, 1);
+
+ /* Outputs */
+ GPU_vertbuf_bind_as_ssbo(stretch_angles, 2);
+
+ drw_subdiv_compute_dispatch(cache, shader, uvs_offset, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+/* -------------------------------------------------------------------- */
+
+void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache,
+ MeshRenderData *mr,
+ const ToolSettings *toolsettings)
+{
+ Mesh *mesh = cache->mesh;
+
+ /* Setup required data for loose geometry. */
+ mr->me = mesh;
+ mr->medge = mesh->medge;
+ mr->mvert = mesh->mvert;
+ mr->mpoly = mesh->mpoly;
+ mr->mloop = mesh->mloop;
+ mr->vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+ mr->vert_len = mesh->totvert;
+ mr->edge_len = mesh->totedge;
+ mr->poly_len = mesh->totpoly;
+ mr->loop_len = mesh->totloop;
+ mr->extract_type = MR_EXTRACT_MESH;
+ mr->toolsettings = toolsettings;
+ mr->v_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
+
+ /* MeshRenderData is only used for generating edit mode data here. */
+ if (!cache->bm) {
+ return;
+ }
+
+ BMesh *bm = cache->bm;
+ BM_mesh_elem_table_ensure(bm, BM_EDGE | BM_FACE | BM_VERT);
+
+ mr->bm = bm;
+ mr->eed_act = BM_mesh_active_edge_get(bm);
+ mr->efa_act = BM_mesh_active_face_get(bm, false, true);
+ mr->eve_act = BM_mesh_active_vert_get(bm);
+ mr->edge_crease_ofs = CustomData_get_offset(&bm->edata, CD_CREASE);
+ mr->vert_crease_ofs = CustomData_get_offset(&bm->vdata, CD_CREASE);
+ mr->bweight_ofs = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
+#ifdef WITH_FREESTYLE
+ mr->freestyle_edge_ofs = CustomData_get_offset(&bm->edata, CD_FREESTYLE_EDGE);
+ mr->freestyle_face_ofs = CustomData_get_offset(&bm->pdata, CD_FREESTYLE_FACE);
+#endif
+}
+
+/**
+ * For material assignments we want indices for triangles that share a common material to be laid
+ * out contiguously in memory. To achieve this, we sort the indices based on which material the
+ * coarse polygon was assigned. The sort is performed by offsetting the loops indices so that they
+ * are directly assigned to the right sorted indices.
+ *
+ * \code{.unparsed}
+ * Here is a visual representation, considering four quads:
+ * +---------+---------+---------+---------+
+ * | 3 2 | 7 6 | 11 10 | 15 14 |
+ * | | | | |
+ * | 0 1 | 4 5 | 8 9 | 12 13 |
+ * +---------+---------+---------+---------+
+ *
+ * If the first and third quads have the same material, we should have:
+ * +---------+---------+---------+---------+
+ * | 3 2 | 11 10 | 7 6 | 15 14 |
+ * | | | | |
+ * | 0 1 | 8 9 | 4 5 | 12 13 |
+ * +---------+---------+---------+---------+
+ *
+ * So the offsets would be:
+ * +---------+---------+---------+---------+
+ * | 0 0 | 4 4 | -4 -4 | 0 0 |
+ * | | | | |
+ * | 0 0 | 4 4 | -4 -4 | 0 0 |
+ * +---------+---------+---------+---------+
+ * \endcode
+ *
+ * The offsets are computed not based on the loops indices, but on the number of subdivided
+ * polygons for each coarse polygon. We then only store a single offset for each coarse polygon,
+ * since all sub-faces are contiguous, they all share the same offset.
+ */
+static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache,
+ Mesh *mesh_eval,
+ uint mat_len)
+{
+ draw_subdiv_cache_free_material_data(cache);
+
+ const int number_of_quads = cache->num_subdiv_loops / 4;
+
+ if (mat_len == 1) {
+ cache->mat_start = static_cast<int *>(MEM_callocN(sizeof(int), "subdiv mat_end"));
+ cache->mat_end = static_cast<int *>(MEM_callocN(sizeof(int), "subdiv mat_end"));
+ cache->mat_start[0] = 0;
+ cache->mat_end[0] = number_of_quads;
+ return;
+ }
+
+ /* Count number of subdivided polygons for each material. */
+ int *mat_start = static_cast<int *>(MEM_callocN(sizeof(int) * mat_len, "subdiv mat_start"));
+ int *subdiv_polygon_offset = cache->subdiv_polygon_offset;
+
+ // TODO: parallel_reduce?
+ for (int i = 0; i < mesh_eval->totpoly; i++) {
+ const MPoly *mpoly = &mesh_eval->mpoly[i];
+ const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads :
+ subdiv_polygon_offset[i + 1];
+ const int quad_count = next_offset - subdiv_polygon_offset[i];
+ const int mat_index = mpoly->mat_nr;
+ mat_start[mat_index] += quad_count;
+ }
+
+ /* Accumulate offsets. */
+ int ofs = mat_start[0];
+ mat_start[0] = 0;
+ for (uint i = 1; i < mat_len; i++) {
+ int tmp = mat_start[i];
+ mat_start[i] = ofs;
+ ofs += tmp;
+ }
+
+ /* Compute per polygon offsets. */
+ int *mat_end = static_cast<int *>(MEM_dupallocN(mat_start));
+ int *per_polygon_mat_offset = static_cast<int *>(
+ MEM_mallocN(sizeof(int) * mesh_eval->totpoly, "per_polygon_mat_offset"));
+
+ for (int i = 0; i < mesh_eval->totpoly; i++) {
+ const MPoly *mpoly = &mesh_eval->mpoly[i];
+ const int mat_index = mpoly->mat_nr;
+ const int single_material_index = subdiv_polygon_offset[i];
+ const int material_offset = mat_end[mat_index];
+ const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads :
+ subdiv_polygon_offset[i + 1];
+ const int quad_count = next_offset - subdiv_polygon_offset[i];
+ mat_end[mat_index] += quad_count;
+
+ per_polygon_mat_offset[i] = material_offset - single_material_index;
+ }
+
+ cache->polygon_mat_offset = draw_subdiv_build_origindex_buffer(per_polygon_mat_offset,
+ mesh_eval->totpoly);
+ cache->mat_start = mat_start;
+ cache->mat_end = mat_end;
+
+ MEM_freeN(per_polygon_mat_offset);
+}
+
+static bool draw_subdiv_create_requested_buffers(const Scene *scene,
+ Object *ob,
+ Mesh *mesh,
+ struct MeshBatchCache *batch_cache,
+ MeshBufferCache *mbc,
+ const ToolSettings *toolsettings,
+ OpenSubdiv_EvaluatorCache *evaluator_cache)
+{
+ SubsurfModifierData *smd = BKE_object_get_last_subsurf_modifier(ob);
+ BLI_assert(smd);
+
+ const bool is_final_render = DRW_state_is_scene_render();
+
+ SubdivSettings settings;
+ BKE_subsurf_modifier_subdiv_settings_init(&settings, smd, is_final_render);
+
+ if (settings.level == 0) {
+ return false;
+ }
+
+ Mesh *mesh_eval = mesh;
+ BMesh *bm = nullptr;
+ if (mesh->edit_mesh) {
+ mesh_eval = BKE_object_get_editmesh_eval_final(ob);
+ bm = mesh->edit_mesh->bm;
+ }
+
+ BKE_subsurf_modifier_ensure_runtime(smd);
+
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true);
+ if (!subdiv) {
+ return false;
+ }
+
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) {
+ return false;
+ }
+
+ DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache);
+ if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, scene, smd, is_final_render)) {
+ return false;
+ }
+
+ const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges);
+
+ draw_cache->bm = bm;
+ draw_cache->mesh = mesh_eval;
+ draw_cache->subdiv = subdiv;
+ draw_cache->optimal_display = optimal_display;
+ draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops);
+ /* We can only evaluate limit normals if the patches are adaptive. */
+ draw_cache->do_limit_normals = settings.is_adaptive;
+
+ if (DRW_ibo_requested(mbc->buff.ibo.tris)) {
+ draw_subdiv_cache_ensure_mat_offsets(draw_cache, mesh_eval, batch_cache->mat_len);
+ }
+
+ draw_subdiv_cache_update_extra_coarse_face_data(draw_cache, mesh_eval);
+
+ mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, toolsettings);
+
+ return true;
+}
+
+static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr;
+
+void DRW_create_subdivision(const Scene *scene,
+ Object *ob,
+ Mesh *mesh,
+ struct MeshBatchCache *batch_cache,
+ MeshBufferCache *mbc,
+ const ToolSettings *toolsettings)
+{
+ if (g_evaluator_cache == nullptr) {
+ g_evaluator_cache = openSubdiv_createEvaluatorCache(OPENSUBDIV_EVALUATOR_GLSL_COMPUTE);
+ }
+
+#undef TIME_SUBDIV
+
+#ifdef TIME_SUBDIV
+ const double begin_time = PIL_check_seconds_timer();
+#endif
+
+ if (!draw_subdiv_create_requested_buffers(
+ scene, ob, mesh, batch_cache, mbc, toolsettings, g_evaluator_cache)) {
+ return;
+ }
+
+#ifdef TIME_SUBDIV
+ const double end_time = PIL_check_seconds_timer();
+ fprintf(stderr, "Time to update subdivision: %f\n", end_time - begin_time);
+ fprintf(stderr, "Maximum FPS: %f\n", 1.0 / (end_time - begin_time));
+#endif
+}
+
+void DRW_subdiv_free()
+{
+ for (int i = 0; i < NUM_SHADERS; ++i) {
+ GPU_shader_free(g_subdiv_shaders[i]);
+ }
+
+ DRW_cache_free_old_subdiv();
+
+ if (g_evaluator_cache) {
+ openSubdiv_deleteEvaluatorCache(g_evaluator_cache);
+ g_evaluator_cache = nullptr;
+ }
+}
+
+static LinkNode *gpu_subdiv_free_queue = nullptr;
+static ThreadMutex gpu_subdiv_queue_mutex = BLI_MUTEX_INITIALIZER;
+
+void DRW_subdiv_cache_free(Subdiv *subdiv)
+{
+ BLI_mutex_lock(&gpu_subdiv_queue_mutex);
+ BLI_linklist_prepend(&gpu_subdiv_free_queue, subdiv);
+ BLI_mutex_unlock(&gpu_subdiv_queue_mutex);
+}
+
+void DRW_cache_free_old_subdiv()
+{
+ if (gpu_subdiv_free_queue == nullptr) {
+ return;
+ }
+
+ BLI_mutex_lock(&gpu_subdiv_queue_mutex);
+
+ while (gpu_subdiv_free_queue != nullptr) {
+ Subdiv *subdiv = static_cast<Subdiv *>(BLI_linklist_pop(&gpu_subdiv_free_queue));
+ /* Set the type to CPU so that we do actually free the cache. */
+ subdiv->evaluator->type = OPENSUBDIV_EVALUATOR_CPU;
+ BKE_subdiv_free(subdiv);
+ }
+
+ BLI_mutex_unlock(&gpu_subdiv_queue_mutex);
+}
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index 6c3e0773a15..fdb7cfba580 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -24,12 +24,12 @@
struct DRWShadingGroup;
struct FluidModifierData;
+struct GPUMaterial;
struct ModifierData;
struct Object;
struct ParticleSystem;
struct RegionView3D;
struct ViewLayer;
-struct GPUMaterial;
#define UBO_FIRST_COLOR colorWire
#define UBO_LAST_COLOR colorUVShadow
diff --git a/source/blender/draw/intern/draw_debug.h b/source/blender/draw/intern/draw_debug.h
index 2f1a082af96..2616bc0af97 100644
--- a/source/blender/draw/intern/draw_debug.h
+++ b/source/blender/draw/intern/draw_debug.h
@@ -28,11 +28,11 @@ void DRW_debug_modelmat_reset(void);
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]);
+void DRW_debug_polygon_v3(const float (*v)[3], 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_m4_as_bbox(const float m[4][4], const float color[4], bool invert);
void DRW_debug_bbox(const BoundBox *bbox, const float color[4]);
-void DRW_debug_sphere(const float center[3], const float radius, const float color[4]);
+void DRW_debug_sphere(const float center[3], float radius, const float color[4]);
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 0abb00a71a9..e9010d7a81a 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -54,7 +54,7 @@
BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get(void)
{
#ifdef USE_COMPUTE_SHADERS
- if (GPU_compute_shader_support()) {
+ if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support()) {
return PART_REFINE_SHADER_COMPUTE;
}
#endif
@@ -130,7 +130,7 @@ static void drw_hair_particle_cache_update_compute(ParticleHairCache *cache, con
GPUShader *shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass);
drw_hair_particle_cache_shgrp_attach_resources(shgrp, cache, subdiv);
- DRW_shgroup_vertex_buffer(shgrp, "hairPointOutputBuffer", cache->final[subdiv].proc_buf);
+ DRW_shgroup_vertex_buffer(shgrp, "posTime", cache->final[subdiv].proc_buf);
const int max_strands_per_call = GPU_max_work_group_count(0);
int strands_start = 0;
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 930fb6eabef..45e4c2a575e 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -52,6 +52,7 @@
#include "BKE_pointcache.h"
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
+#include "BKE_subdiv_modifier.h"
#include "BKE_volume.h"
#include "DNA_camera_types.h"
@@ -69,6 +70,7 @@
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
#include "GPU_uniform_buffer.h"
#include "GPU_viewport.h"
@@ -90,6 +92,7 @@
#include "draw_manager_testing.h"
#include "draw_manager_text.h"
#include "draw_shader.h"
+#include "draw_subdivision.h"
#include "draw_texture_pool.h"
/* only for callbacks */
@@ -209,21 +212,7 @@ bool DRW_object_is_in_edit_mode(const Object *ob)
if (BKE_object_is_in_editmode(ob)) {
if (ob->type == OB_MESH) {
if ((ob->mode & OB_MODE_EDIT) == 0) {
- Mesh *me = (Mesh *)ob->data;
- BMEditMesh *embm = me->edit_mesh;
- /* Sanity check when rendering in multiple windows. */
- if (embm && embm->mesh_eval_final == NULL) {
- return false;
- }
- /* Do not draw ob with edit overlay when edit data is present and is modified. */
- if (embm && embm->mesh_eval_cage && (embm->mesh_eval_cage != embm->mesh_eval_final)) {
- return false;
- }
- /* Check if the object that we are drawing is modified. */
- if (!DEG_is_original_id(&me->id)) {
- return false;
- }
- return true;
+ return false;
}
}
return true;
@@ -755,8 +744,11 @@ static void duplidata_key_free(void *key)
}
else {
Object temp_object = *dupli_key->ob;
+ /* Do not modify the original bound-box. */
+ temp_object.runtime.bb = NULL;
BKE_object_replace_data_on_shallow_copy(&temp_object, dupli_key->ob_data);
drw_batch_cache_generate_requested(&temp_object);
+ MEM_SAFE_FREE(temp_object.runtime.bb);
}
MEM_freeN(key);
}
@@ -1794,12 +1786,12 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
DRW_draw_render_loop_ex(depsgraph, engine_type, region, v3d, render_viewport, NULL);
if (draw_background) {
- /* HACK(fclem): In this case we need to make sure the final alpha is 1.
+ /* HACK(@fclem): In this case we need to make sure the final alpha is 1.
* We use the blend mode to ensure that. A better way to fix that would
* be to do that in the color-management shader. */
GPU_offscreen_bind(ofs, false);
GPU_clear_color(0.0f, 0.0f, 0.0f, 1.0f);
- /* Premult Alpha over black background. */
+ /* Pre-multiply alpha over black background. */
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
}
@@ -2530,16 +2522,17 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
ARegion *region,
View3D *v3d,
GPUViewport *viewport,
- const bool use_opengl_context)
+ const bool use_gpencil,
+ const bool use_basic,
+ const bool use_overlay)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
RegionView3D *rv3d = region->regiondata;
- if (use_opengl_context) {
- DRW_opengl_context_enable();
- }
+ /* Reset before using it. */
+ drw_state_prepare_clean_for_draw(&DST);
DST.options.is_depth = true;
@@ -2555,6 +2548,18 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
.depsgraph = depsgraph,
};
drw_context_state_init();
+ drw_manager_init(&DST, viewport, NULL);
+
+ if (use_gpencil) {
+ use_drw_engine(&draw_engine_gpencil_type);
+ }
+ if (use_basic) {
+ drw_engines_enable_basic();
+ }
+ if (use_overlay) {
+ drw_engines_enable_overlays();
+ }
+
drw_task_graph_init();
/* Setup frame-buffer. */
@@ -2622,11 +2627,6 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph,
drw_engines_disable();
drw_manager_exit(&DST);
-
- /* Changing context. */
- if (use_opengl_context) {
- DRW_opengl_context_disable();
- }
}
void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
@@ -2634,26 +2634,8 @@ void DRW_draw_depth_loop(struct Depsgraph *depsgraph,
View3D *v3d,
GPUViewport *viewport)
{
- /* Reset before using it. */
- drw_state_prepare_clean_for_draw(&DST);
-
- /* Required by `drw_manager_init()` */
- DST.draw_ctx.region = region;
- DST.draw_ctx.rv3d = region->regiondata;
- drw_manager_init(&DST, viewport, NULL);
-
- /* Get list of enabled engines */
- {
- /* Required by `DRW_state_draw_support()` */
- DST.draw_ctx.v3d = v3d;
-
- drw_engines_enable_basic();
- if (DRW_state_draw_support()) {
- drw_engines_enable_overlays();
- }
- }
-
- drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, false);
+ drw_draw_depth_loop_impl(
+ depsgraph, region, v3d, viewport, false, true, DRW_state_draw_support());
}
void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
@@ -2661,17 +2643,7 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
View3D *v3d,
GPUViewport *viewport)
{
- /* Reset before using it. */
- drw_state_prepare_clean_for_draw(&DST);
-
- /* Required by `drw_manager_init()` */
- DST.draw_ctx.region = region;
- DST.draw_ctx.rv3d = region->regiondata;
- drw_manager_init(&DST, viewport, NULL);
-
- use_drw_engine(&draw_engine_gpencil_type);
-
- drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, false);
+ drw_draw_depth_loop_impl(depsgraph, region, v3d, viewport, true, false, false);
}
void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, const rcti *rect)
@@ -2771,11 +2743,15 @@ void DRW_draw_depth_object(
GPU_framebuffer_clear_depth(depth_fb, 1.0f);
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
- const float(*world_clip_planes)[4] = NULL;
- if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
+ struct GPUClipPlanes planes;
+ const bool use_clipping_planes = RV3D_CLIPPING_ENABLED(v3d, rv3d);
+ if (use_clipping_planes) {
GPU_clip_distances(6);
ED_view3d_clipping_local(rv3d, object->obmat);
- world_clip_planes = rv3d->clip_local;
+ for (int i = 0; i < 6; i++) {
+ copy_v4_v4(planes.world[i], rv3d->clip_local[i]);
+ }
+ copy_m4_m4(planes.ModelMatrix, object->obmat);
}
drw_batch_cache_validate(object);
@@ -2797,14 +2773,19 @@ void DRW_draw_depth_object(
BLI_task_graph_work_and_wait(task_graph);
BLI_task_graph_free(task_graph);
- const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED :
- GPU_SHADER_CFG_DEFAULT;
+ const eGPUShaderConfig sh_cfg = use_clipping_planes ? GPU_SHADER_CFG_CLIPPED :
+ GPU_SHADER_CFG_DEFAULT;
GPU_batch_program_set_builtin_with_config(batch, GPU_SHADER_3D_DEPTH_ONLY, sh_cfg);
- if (world_clip_planes != NULL) {
- GPU_batch_uniform_4fv_array(batch, "WorldClipPlanes", 6, world_clip_planes);
+
+ GPUUniformBuf *ubo = NULL;
+ if (use_clipping_planes) {
+ ubo = GPU_uniformbuf_create_ex(sizeof(struct GPUClipPlanes), &planes, __func__);
+ GPU_batch_uniformbuf_bind(batch, "clipPlanes", ubo);
}
GPU_batch_draw(batch);
+ GPU_uniformbuf_free(ubo);
+
} break;
case OB_CURVE:
case OB_SURF:
@@ -2975,6 +2956,8 @@ void DRW_engines_register(void)
BKE_volume_batch_cache_dirty_tag_cb = DRW_volume_batch_cache_dirty_tag;
BKE_volume_batch_cache_free_cb = DRW_volume_batch_cache_free;
+
+ BKE_subsurf_modifier_free_gpu_cache_cb = DRW_subdiv_cache_free;
}
}
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index a4924711384..d27eb8be9e0 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -570,7 +570,7 @@ typedef struct DRWManager {
struct Object *dupli_origin;
/** Object-data referenced by the current dupli object. */
struct ID *dupli_origin_data;
- /** Ghash: #DupliKey -> void pointer for each enabled engine. */
+ /** Hash-map: #DupliKey -> void pointer for each enabled engine. */
struct GHash *dupli_ghash;
/** TODO(fclem): try to remove usage of this. */
DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE];
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index e71a1298812..ab570667a77 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -1248,6 +1248,17 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK);
int resourceid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_ID);
+ /* TODO(fclem) Will take the place of the above after the GPUShaderCreateInfo port. */
+ if (view_ubo_location == -1) {
+ view_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_DRW_VIEW);
+ }
+ if (model_ubo_location == -1) {
+ model_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_DRW_MODEL);
+ }
+ if (info_ubo_location == -1) {
+ info_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_DRW_INFOS);
+ }
+
if (chunkid_location != -1) {
drw_shgroup_uniform_create_ex(
shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 0, 1);
@@ -1364,14 +1375,15 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial
if (tex->ima) {
/* Image */
GPUTexture *gputex;
+ ImageUser *iuser = tex->iuser_available ? &tex->iuser : NULL;
if (tex->tiled_mapping_name[0]) {
- gputex = BKE_image_get_gpu_tiles(tex->ima, tex->iuser, NULL);
+ gputex = BKE_image_get_gpu_tiles(tex->ima, iuser, NULL);
drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
- gputex = BKE_image_get_gpu_tilemap(tex->ima, tex->iuser, NULL);
+ gputex = BKE_image_get_gpu_tilemap(tex->ima, iuser, NULL);
drw_shgroup_material_texture(grp, gputex, tex->tiled_mapping_name, tex->sampler_state);
}
else {
- gputex = BKE_image_get_gpu_texture(tex->ima, tex->iuser, NULL);
+ gputex = BKE_image_get_gpu_texture(tex->ima, iuser, NULL);
drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
}
}
diff --git a/source/blender/draw/intern/draw_manager_text.h b/source/blender/draw/intern/draw_manager_text.h
index 000a6ab5e6f..098b636cc98 100644
--- a/source/blender/draw/intern/draw_manager_text.h
+++ b/source/blender/draw/intern/draw_manager_text.h
@@ -38,7 +38,7 @@ void DRW_text_cache_destroy(struct DRWTextStore *dt);
void DRW_text_cache_add(struct DRWTextStore *dt,
const float co[3],
const char *str,
- const int str_len,
+ int str_len,
short xoffs,
short yoffs,
short flag,
diff --git a/source/blender/draw/intern/draw_shader.c b/source/blender/draw/intern/draw_shader.c
index 121a0acd059..28ac76ccd7f 100644
--- a/source/blender/draw/intern/draw_shader.c
+++ b/source/blender/draw/intern/draw_shader.c
@@ -47,12 +47,7 @@ static struct {
static GPUShader *hair_refine_shader_compute_create(ParticleRefineShader UNUSED(refinement))
{
- GPUShader *sh = NULL;
- sh = GPU_shader_create_compute(datatoc_common_hair_refine_comp_glsl,
- datatoc_common_hair_lib_glsl,
- "#define HAIR_PHASE_SUBDIV\n",
- __func__);
- return sh;
+ return GPU_shader_create_from_info_name("draw_hair_refine_compute");
}
static GPUShader *hair_refine_shader_transform_feedback_create(
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
new file mode 100644
index 00000000000..35350417ca8
--- /dev/null
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -0,0 +1,52 @@
+
+#ifndef GPU_SHADER
+# include "gpu_shader_shared_utils.h"
+#endif
+
+#define DRW_SHADER_SHARED_H
+
+#define DRW_RESOURCE_CHUNK_LEN 512
+
+struct ViewInfos {
+ /* View matrices */
+ float4x4 persmat;
+ float4x4 persinv;
+ float4x4 viewmat;
+ float4x4 viewinv;
+ float4x4 winmat;
+ float4x4 wininv;
+
+ float4 clip_planes[6];
+ float4 viewvecs[2];
+ /* Should not be here. Not view dependent (only main view). */
+ float4 viewcamtexcofac;
+};
+BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16)
+
+/* TODO(fclem) Mass rename. */
+#define ViewProjectionMatrix drw_view.persmat
+#define ViewProjectionMatrixInverse drw_view.persinv
+#define ViewMatrix drw_view.viewmat
+#define ViewMatrixInverse drw_view.viewinv
+#define ProjectionMatrix drw_view.winmat
+#define ProjectionMatrixInverse drw_view.wininv
+#define clipPlanes drw_view.clip_planes
+#define ViewVecs drw_view.viewvecs
+#define CameraTexCoFactors drw_view.viewcamtexcofac
+
+struct ObjectMatrices {
+ float4x4 drw_modelMatrix;
+ float4x4 drw_modelMatrixInverse;
+};
+BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16)
+
+struct ObjectInfos {
+ float4 drw_OrcoTexCoFactors[2];
+ float4 drw_ObjectColor;
+ float4 drw_Infos;
+};
+BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16)
+
+#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
+#define ObjectInfo (drw_infos[resource_id].drw_Infos)
+#define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
new file mode 100644
index 00000000000..eeef2156e35
--- /dev/null
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -0,0 +1,231 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_sys_types.h"
+
+struct BMesh;
+struct GPUIndexBuf;
+struct GPUUniformBuf;
+struct GPUVertBuf;
+struct Mesh;
+struct MeshBatchCache;
+struct MeshBufferCache;
+struct MeshRenderData;
+struct Object;
+struct Scene;
+struct Subdiv;
+struct ToolSettings;
+
+/* -------------------------------------------------------------------- */
+/** \name DRWPatchMap
+ *
+ * This is a GPU version of the OpenSubDiv PatchMap. The quad tree and the patch handles are copied
+ * to GPU buffers in order to lookup the right patch for a given set of patch coordinates.
+ * \{ */
+
+typedef struct DRWPatchMap {
+ struct GPUVertBuf *patch_map_handles;
+ struct GPUVertBuf *patch_map_quadtree;
+ int min_patch_face;
+ int max_patch_face;
+ int max_depth;
+ int patches_are_triangular;
+} DRWPatchMap;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DRWSubdivCache
+ *
+ * This holds the various buffers used to evaluate and render subdivision through OpenGL.
+ * \{ */
+
+typedef struct DRWSubdivCache {
+ struct Mesh *mesh;
+ struct BMesh *bm;
+ struct Subdiv *subdiv;
+ bool optimal_display;
+ bool do_limit_normals;
+
+ /* Coordinates used to evaluate patches for UVs, positions, and normals. */
+ struct GPUVertBuf *patch_coords;
+ /* Coordinates used to evaluate patches for the face centers (or face dots) in edit-mode. */
+ struct GPUVertBuf *fdots_patch_coords;
+
+ /* Resolution used to generate the patch coordinates. */
+ int resolution;
+
+ /* Number of subdivided loops, also the number of patch coordinates since we have one coordinate
+ * but quad corner/vertex. */
+ uint num_subdiv_loops;
+ uint num_subdiv_edges;
+ uint num_subdiv_triangles;
+ uint num_subdiv_verts;
+ uint num_subdiv_quads;
+
+ /* Number of polygons in the coarse mesh, notably used to compute a coarse polygon index given a
+ * subdivision loop index. */
+ int num_coarse_poly;
+
+ /* Maps subdivision loop to subdivided vertex index. */
+ int *subdiv_loop_subdiv_vert_index;
+ /* Maps subdivision loop to original coarse poly index. */
+ int *subdiv_loop_poly_index;
+
+ /* Indices of faces adjacent to the vertices, ordered by vertex index, with no particular
+ * winding. */
+ struct GPUVertBuf *subdiv_vertex_face_adjacency;
+ /* The difference between value (i + 1) and (i) gives the number of faces adjacent to vertex (i).
+ */
+ struct GPUVertBuf *subdiv_vertex_face_adjacency_offsets;
+
+ /* Maps subdivision loop to original coarse vertex index, only really useful for edit mode. */
+ struct GPUVertBuf *verts_orig_index;
+ /* Maps subdivision loop to original coarse edge index, only really useful for edit mode. */
+ struct GPUVertBuf *edges_orig_index;
+
+ /* Owned by #Subdiv. Indexed by coarse polygon index, difference between value (i + 1) and (i)
+ * gives the number of ptex faces for coarse polygon (i). */
+ int *face_ptex_offset;
+ /* Vertex buffer for face_ptex_offset. */
+ struct GPUVertBuf *face_ptex_offset_buffer;
+
+ int *subdiv_polygon_offset;
+ struct GPUVertBuf *subdiv_polygon_offset_buffer;
+
+ /* Contains the start loop index and the smooth flag for each coarse polygon. */
+ struct GPUVertBuf *extra_coarse_face_data;
+
+ /* Computed for ibo.points, one value per subdivided vertex, mapping coarse vertices ->
+ * subdivided loop */
+ int *point_indices;
+
+ /* Material offsets. */
+ int *mat_start;
+ int *mat_end;
+ struct GPUVertBuf *polygon_mat_offset;
+
+ DRWPatchMap gpu_patch_map;
+
+ /* UBO to store settings for the various compute shaders. */
+ struct GPUUniformBuf *ubo;
+} DRWSubdivCache;
+
+/* Only frees the data of the cache, caller is responsible to free the cache itself if necessary.
+ */
+void draw_subdiv_cache_free(DRWSubdivCache *cache);
+
+/** \} */
+
+void DRW_create_subdivision(const struct Scene *scene,
+ struct Object *ob,
+ struct Mesh *mesh,
+ struct MeshBatchCache *batch_cache,
+ struct MeshBufferCache *mbc,
+ const struct ToolSettings *toolsettings);
+
+void DRW_subdiv_cache_free(struct Subdiv *subdiv);
+
+void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache,
+ struct MeshRenderData *mr,
+ const struct ToolSettings *toolsettings);
+
+void draw_subdiv_init_origindex_buffer(struct GPUVertBuf *buffer,
+ int *vert_origindex,
+ uint num_loops,
+ uint loose_len);
+
+struct GPUVertBuf *draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_loops);
+
+/* Compute shader functions. */
+
+void draw_subdiv_build_sculpt_data_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *mask_vbo,
+ struct GPUVertBuf *face_set_vbo,
+ struct GPUVertBuf *sculpt_data);
+
+void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *face_adjacency_offsets,
+ struct GPUVertBuf *face_adjacency_lists,
+ struct GPUVertBuf *vertex_normals);
+
+void draw_subdiv_finalize_normals(const DRWSubdivCache *cache,
+ struct GPUVertBuf *vertex_normals,
+ struct GPUVertBuf *subdiv_loop_subdiv_vert_index,
+ struct GPUVertBuf *pos_nor);
+
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ bool do_limit_normals);
+
+void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
+ struct GPUVertBuf *src_data,
+ struct GPUVertBuf *dst_data,
+ int dimensions,
+ int dst_offset);
+
+void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
+ struct GPUVertBuf *uvs,
+ int face_varying_channel,
+ int dst_offset);
+
+void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *edge_idx,
+ struct GPUVertBuf *edge_fac);
+
+void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
+ struct GPUIndexBuf *subdiv_tris,
+ int material_count);
+
+void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache,
+ struct GPUIndexBuf *lines_indices);
+
+void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
+ struct GPUIndexBuf *lines_indices,
+ uint num_loose_edges);
+
+void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
+ struct GPUVertBuf *fdots_pos,
+ struct GPUVertBuf *fdots_nor,
+ struct GPUIndexBuf *fdots_indices);
+
+void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *lnor);
+
+void draw_subdiv_build_edituv_stretch_area_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *coarse_data,
+ struct GPUVertBuf *subdiv_data);
+
+void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *uvs,
+ int uvs_offset,
+ struct GPUVertBuf *stretch_angles);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/intern/draw_view_data.h b/source/blender/draw/intern/draw_view_data.h
index 494c28cc067..b37e48c11e8 100644
--- a/source/blender/draw/intern/draw_view_data.h
+++ b/source/blender/draw/intern/draw_view_data.h
@@ -31,9 +31,9 @@
extern "C" {
#endif
-struct GPUViewport;
-struct DrawEngineType;
struct DRWRegisteredDrawEngine;
+struct DrawEngineType;
+struct GPUViewport;
/* NOTE these structs are only here for reading the actual lists from the engine.
* The actual length of them is stored in a ViewportEngineData_Info.
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
index 7d21804c08f..37eb4f80442 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
@@ -39,6 +39,8 @@
extern "C" {
#endif
+struct DRWSubdivCache;
+
#define MIN_RANGE_LEN 1024
/* ---------------------------------------------------------------------- */
@@ -82,7 +84,8 @@ typedef struct MeshRenderData {
const float (*bm_poly_centers)[3];
int *v_origindex, *e_origindex, *p_origindex;
- int crease_ofs;
+ int edge_crease_ofs;
+ int vert_crease_ofs;
int bweight_ofs;
int freestyle_edge_ofs;
int freestyle_face_ofs;
@@ -98,8 +101,9 @@ typedef struct MeshRenderData {
BMFace *efa_act_uv;
/* Data created on-demand (usually not for #BMesh based data). */
MLoopTri *mlooptri;
+ const float (*vert_normals)[3];
+ const float (*poly_normals)[3];
float (*loop_normals)[3];
- float (*poly_normals)[3];
int *lverts, *ledges;
struct {
@@ -171,38 +175,40 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e
/* TODO(jbakker): move parameters inside a struct. */
-typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
- BMLoop **elt,
- const int elt_index,
- void *data);
+typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data);
typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
const MLoopTri *mlt,
- const int elt_index,
+ int elt_index,
void *data);
typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
const BMFace *f,
- const int f_index,
+ int f_index,
void *data);
typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
const MPoly *mp,
- const int mp_index,
+ int mp_index,
void *data);
typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
const BMEdge *eed,
- const int ledge_index,
+ int ledge_index,
void *data);
typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
const MEdge *med,
- const int ledge_index,
+ int ledge_index,
void *data);
typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
const BMVert *eve,
- const int lvert_index,
+ int lvert_index,
void *data);
typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
const MVert *mv,
- const int lvert_index,
+ int lvert_index,
void *data);
+typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *data);
typedef void(ExtractInitFn)(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buffer,
@@ -213,6 +219,27 @@ typedef void(ExtractFinishFn)(const MeshRenderData *mr,
void *data);
typedef void(ExtractTaskReduceFn)(void *userdata, void *task_userdata);
+typedef void(ExtractInitSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *data);
+typedef void(ExtractIterSubdivBMeshFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_quad);
+typedef void(ExtractIterSubdivMeshFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad);
+typedef void(ExtractFinishSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *data);
+
typedef struct MeshExtract {
/** Executed on main thread and return user data for iteration functions. */
ExtractInitFn *init;
@@ -225,9 +252,15 @@ typedef struct MeshExtract {
ExtractLEdgeMeshFn *iter_ledge_mesh;
ExtractLVertBMeshFn *iter_lvert_bm;
ExtractLVertMeshFn *iter_lvert_mesh;
+ ExtractLooseGeomSubdivFn *iter_loose_geom_subdiv;
/** Executed on one worker thread after all elements iterations. */
ExtractTaskReduceFn *task_reduce;
ExtractFinishFn *finish;
+ /** Executed on main thread for subdivision evaluation. */
+ ExtractInitSubdivFn *init_subdiv;
+ ExtractIterSubdivBMeshFn *iter_subdiv_bm;
+ ExtractIterSubdivMeshFn *iter_subdiv_mesh;
+ ExtractFinishSubdivFn *finish_subdiv;
/** Used to request common data. */
eMRDataType data_type;
size_t data_size;
@@ -248,34 +281,37 @@ typedef struct MeshExtract {
* \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,
- const bool is_mode_active,
+MeshRenderData *mesh_render_data_create(Object *object,
+ Mesh *me,
+ bool is_editmode,
+ bool is_paint_mode,
+ bool is_mode_active,
const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
+ bool do_final,
+ bool do_uvedit,
const ToolSettings *ts);
void mesh_render_data_free(MeshRenderData *mr);
-void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag);
+void mesh_render_data_update_normals(MeshRenderData *mr, eMRDataType data_flag);
void mesh_render_data_update_loose_geom(MeshRenderData *mr,
MeshBufferCache *cache,
- const eMRIterType iter_type,
- const eMRDataType data_flag);
+ eMRIterType iter_type,
+ eMRDataType data_flag);
void mesh_render_data_update_polys_sorted(MeshRenderData *mr,
MeshBufferCache *cache,
- const eMRDataType data_flag);
+ 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);
+ eMRIterType iter_type,
+ eMRDataType data_flag);
/* draw_cache_extract_mesh_extractors.c */
typedef struct EditLoopData {
uchar v_flag;
uchar e_flag;
+ /* This is used for both vertex and edge creases. The edge crease value is stored in the bottom 4
+ * bits, while the vertex crease is stored in the upper 4 bits. */
uchar crease;
uchar bweight;
} EditLoopData;
@@ -283,19 +319,19 @@ typedef struct EditLoopData {
void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist);
eMRIterType mesh_extract_iter_type(const MeshExtract *ext);
const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor,
- const bool do_hq_normals,
- const bool do_single_mat);
+ bool do_hq_normals,
+ bool do_single_mat);
void mesh_render_data_face_flag(const MeshRenderData *mr,
const BMFace *efa,
- const int cd_ofs,
+ int cd_ofs,
EditLoopData *eattr);
void mesh_render_data_loop_flag(const MeshRenderData *mr,
BMLoop *l,
- const int cd_ofs,
+ int cd_ofs,
EditLoopData *eattr);
void mesh_render_data_loop_edge_flag(const MeshRenderData *mr,
BMLoop *l,
- const int cd_ofs,
+ int cd_ofs,
EditLoopData *eattr);
extern const MeshExtract extract_tris;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
index 4cc9a875f79..cd71beb1f02 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc
@@ -27,6 +27,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Edit UV Triangles Indices
@@ -94,6 +96,79 @@ static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(&data->elb, ibo);
}
+static void extract_edituv_tris_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
+ GPU_indexbuf_init(&data->elb,
+ GPU_PRIM_TRIS,
+ subdiv_cache->num_subdiv_triangles,
+ subdiv_cache->num_subdiv_loops);
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+}
+
+static void extract_edituv_tris_iter_subdiv_bm(const DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_quad)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ const uint loop_idx = subdiv_quad_index * 4;
+
+ edituv_tri_add(data,
+ BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN) != 0,
+ BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0,
+ loop_idx,
+ loop_idx + 1,
+ loop_idx + 2);
+
+ edituv_tri_add(data,
+ BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN) != 0,
+ BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0,
+ loop_idx,
+ loop_idx + 2,
+ loop_idx + 3);
+}
+
+static void extract_edituv_tris_iter_subdiv_mesh(const DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ const uint loop_idx = subdiv_quad_index * 4;
+
+ edituv_tri_add(data,
+ (coarse_quad->flag & ME_HIDE) != 0,
+ (coarse_quad->flag & ME_FACE_SEL) != 0,
+ loop_idx,
+ loop_idx + 1,
+ loop_idx + 2);
+
+ edituv_tri_add(data,
+ (coarse_quad->flag & ME_HIDE) != 0,
+ (coarse_quad->flag & ME_FACE_SEL) != 0,
+ loop_idx,
+ loop_idx + 2,
+ loop_idx + 3);
+}
+
+static void extract_edituv_tris_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+}
+
constexpr MeshExtract create_extractor_edituv_tris()
{
MeshExtract extractor = {nullptr};
@@ -101,6 +176,10 @@ constexpr MeshExtract create_extractor_edituv_tris()
extractor.iter_looptri_bm = extract_edituv_tris_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh;
extractor.finish = extract_edituv_tris_finish;
+ extractor.init_subdiv = extract_edituv_tris_init_subdiv;
+ extractor.iter_subdiv_bm = extract_edituv_tris_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_edituv_tris_iter_subdiv_mesh;
+ extractor.finish_subdiv = extract_edituv_tris_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
@@ -184,6 +263,77 @@ static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(&data->elb, ibo);
}
+static void extract_edituv_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
+ GPU_indexbuf_init(
+ &data->elb, GPU_PRIM_LINES, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops);
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+}
+
+static void extract_edituv_lines_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_poly)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint loop_idx = start_loop_idx; loop_idx < end_loop_idx; loop_idx++) {
+ const int edge_origindex = subdiv_loop_edge_index[loop_idx];
+ const bool real_edge = (edge_origindex != -1 &&
+ (mr->e_origindex == nullptr ||
+ mr->e_origindex[edge_origindex] != ORIGINDEX_NONE));
+ edituv_edge_add(data,
+ BM_elem_flag_test_bool(coarse_poly, BM_ELEM_HIDDEN) != 0 || !real_edge,
+ BM_elem_flag_test_bool(coarse_poly, BM_ELEM_SELECT) != 0,
+ loop_idx,
+ (loop_idx + 1 == end_loop_idx) ? start_loop_idx : (loop_idx + 1));
+ }
+}
+
+static void extract_edituv_lines_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_poly)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint loop_idx = start_loop_idx; loop_idx < end_loop_idx; loop_idx++) {
+ const int edge_origindex = subdiv_loop_edge_index[loop_idx];
+ const bool real_edge = (edge_origindex != -1 &&
+ (mr->e_origindex == nullptr ||
+ mr->e_origindex[edge_origindex] != ORIGINDEX_NONE));
+ edituv_edge_add(data,
+ (coarse_poly->flag & ME_HIDE) != 0 || !real_edge,
+ (coarse_poly->flag & ME_FACE_SEL) != 0,
+ loop_idx,
+ (loop_idx + 1 == end_loop_idx) ? start_loop_idx : (loop_idx + 1));
+ }
+}
+
+static void extract_edituv_lines_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+}
+
constexpr MeshExtract create_extractor_edituv_lines()
{
MeshExtract extractor = {nullptr};
@@ -191,6 +341,10 @@ constexpr MeshExtract create_extractor_edituv_lines()
extractor.iter_poly_bm = extract_edituv_lines_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_lines_iter_poly_mesh;
extractor.finish = extract_edituv_lines_finish;
+ extractor.init_subdiv = extract_edituv_lines_init_subdiv;
+ extractor.iter_subdiv_bm = extract_edituv_lines_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_edituv_lines_iter_subdiv_mesh;
+ extractor.finish_subdiv = extract_edituv_lines_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
@@ -268,6 +422,75 @@ static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(&data->elb, ibo);
}
+static void extract_edituv_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
+ GPU_indexbuf_init(
+ &data->elb, GPU_PRIM_POINTS, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops);
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+}
+
+static void extract_edituv_points_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_quad)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint i = start_loop_idx; i < end_loop_idx; i++) {
+ const int vert_origindex = subdiv_loop_vert_index[i];
+ const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
+ vert_origindex != -1 &&
+ mr->v_origindex[vert_origindex] != ORIGINDEX_NONE);
+ edituv_point_add(data,
+ (BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN)) || !real_vert,
+ BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0,
+ i);
+ }
+}
+
+static void extract_edituv_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint i = start_loop_idx; i < end_loop_idx; i++) {
+ const int vert_origindex = subdiv_loop_vert_index[i];
+ const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
+ vert_origindex != -1 &&
+ mr->v_origindex[vert_origindex] != ORIGINDEX_NONE);
+ edituv_point_add(data,
+ ((coarse_quad->flag & ME_HIDE) != 0) || !real_vert,
+ (coarse_quad->flag & ME_FACE_SEL) != 0,
+ i);
+ }
+}
+
+static void extract_edituv_points_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+}
+
constexpr MeshExtract create_extractor_edituv_points()
{
MeshExtract extractor = {nullptr};
@@ -275,6 +498,10 @@ constexpr MeshExtract create_extractor_edituv_points()
extractor.iter_poly_bm = extract_edituv_points_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_points_iter_poly_mesh;
extractor.finish = extract_edituv_points_finish;
+ extractor.init_subdiv = extract_edituv_points_init_subdiv;
+ extractor.iter_subdiv_bm = extract_edituv_points_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_edituv_points_iter_subdiv_mesh;
+ extractor.finish_subdiv = extract_edituv_points_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
index 54f5611106f..3d9729dea56 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
@@ -25,6 +25,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -155,6 +157,33 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(elb, ibo);
}
+static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
+ GPU_indexbuf_init_build_on_device(ibo,
+ subdiv_cache->num_subdiv_loops * 2 + mr->edge_loose_len * 2);
+
+ draw_subdiv_build_lines_buffer(subdiv_cache, ibo);
+}
+
+static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ if (loose_geom->edge_len == 0) {
+ return;
+ }
+
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
+ draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom->edge_len));
+}
+
constexpr MeshExtract create_extractor_lines()
{
MeshExtract extractor = {nullptr};
@@ -163,6 +192,8 @@ constexpr MeshExtract create_extractor_lines()
extractor.iter_poly_mesh = extract_lines_iter_poly_mesh;
extractor.iter_ledge_bm = extract_lines_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh;
+ extractor.init_subdiv = extract_lines_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_lines_loose_geom_subdiv;
extractor.task_reduce = extract_lines_task_reduce;
extractor.finish = extract_lines_finish;
extractor.data_type = MR_DATA_NONE;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
index e7dabfa9ee2..2b01b6801c2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -44,6 +45,18 @@ struct MeshExtract_LineAdjacency_Data {
uint *vert_to_loop;
};
+static void line_adjacency_data_init(MeshExtract_LineAdjacency_Data *data,
+ uint vert_len,
+ uint loop_len,
+ uint tess_edge_len)
+{
+ data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * vert_len, __func__));
+
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, loop_len);
+ data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
+ data->is_manifold = true;
+}
+
static void extract_lines_adjacency_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
@@ -55,11 +68,7 @@ static void extract_lines_adjacency_init(const MeshRenderData *mr,
uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len;
MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(tls_data);
- data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * mr->vert_len, __func__));
-
- GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len);
- data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
- data->is_manifold = true;
+ line_adjacency_data_init(data, mr->vert_len, mr->loop_len, tess_edge_len);
}
BLI_INLINE void lines_adjacency_triangle(
@@ -171,6 +180,71 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data->vert_to_loop);
}
+static void extract_lines_adjacency_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *_data)
+{
+ MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data);
+
+ /* For each polygon there is (loop + triangle - 1) edges. Since we only have quads, and a quad
+ * is split into 2 triangles, we have (loop + 2 - 1) = (loop + 1) edges for each quad, or in
+ * total: (number_of_loops + number_of_quads). */
+ const uint tess_len = subdiv_cache->num_subdiv_loops + subdiv_cache->num_subdiv_quads;
+ line_adjacency_data_init(
+ data, subdiv_cache->num_subdiv_verts, subdiv_cache->num_subdiv_loops, tess_len);
+}
+
+static void extract_lines_adjacency_iter_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ void *_data,
+ uint subdiv_quad_index)
+{
+ MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data);
+
+ const uint loop_index = subdiv_quad_index * 4;
+ const uint l0 = loop_index + 0;
+ const uint l1 = loop_index + 1;
+ const uint l2 = loop_index + 2;
+ const uint l3 = loop_index + 3;
+
+ const uint v0 = subdiv_cache->subdiv_loop_subdiv_vert_index[l0];
+ const uint v1 = subdiv_cache->subdiv_loop_subdiv_vert_index[l1];
+ const uint v2 = subdiv_cache->subdiv_loop_subdiv_vert_index[l2];
+ const uint v3 = subdiv_cache->subdiv_loop_subdiv_vert_index[l3];
+
+ lines_adjacency_triangle(v0, v1, v2, l0, l1, l2, data);
+ lines_adjacency_triangle(v0, v2, v3, l0, l2, l3, data);
+}
+
+static void extract_lines_adjacency_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *UNUSED(coarse_quad))
+{
+ extract_lines_adjacency_iter_subdiv(subdiv_cache, mr, _data, subdiv_quad_index);
+}
+
+static void extract_lines_adjacency_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *UNUSED(coarse_quad))
+{
+ extract_lines_adjacency_iter_subdiv(subdiv_cache, mr, _data, subdiv_quad_index);
+}
+
+static void extract_lines_adjacency_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *_data)
+{
+ extract_lines_adjacency_finish(mr, cache, buf, _data);
+}
+
#undef NO_EDGE
constexpr MeshExtract create_extractor_lines_adjacency()
@@ -180,6 +254,10 @@ constexpr MeshExtract create_extractor_lines_adjacency()
extractor.iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh;
extractor.finish = extract_lines_adjacency_finish;
+ extractor.init_subdiv = extract_lines_adjacency_init_subdiv;
+ extractor.iter_subdiv_bm = extract_lines_adjacency_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_lines_adjacency_iter_subdiv_mesh;
+ extractor.finish_subdiv = extract_lines_adjacency_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_LineAdjacency_Data);
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
index 01e14a004ed..c3f89ab96ee 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -155,6 +156,69 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(elb, ibo);
}
+static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buffer),
+ void *data)
+{
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
+ /* Copy the points as the data upload will free them. */
+ elb->data = (uint *)MEM_dupallocN(subdiv_cache->point_indices);
+ elb->index_len = mr->vert_len;
+ elb->index_min = 0;
+ elb->index_max = subdiv_cache->num_subdiv_loops + mr->loop_loose_len;
+ elb->prim_type = GPU_PRIM_POINTS;
+}
+
+static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *UNUSED(buffer),
+ void *data)
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
+
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
+ const MEdge *coarse_edges = coarse_mesh->medge;
+
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
+ if (elb->data[loose_edge->v1] == -1u) {
+ GPU_indexbuf_set_point_vert(elb, loose_edge->v1, offset);
+ }
+ if (elb->data[loose_edge->v2] == -1u) {
+ GPU_indexbuf_set_point_vert(elb, loose_edge->v2, offset + 1);
+ }
+ offset += 2;
+ }
+
+ for (int i = 0; i < loose_geom->vert_len; i++) {
+ if (elb->data[loose_geom->verts[i]] == -1u) {
+ GPU_indexbuf_set_point_vert(elb, loose_geom->verts[i], offset);
+ }
+ offset += 1;
+ }
+}
+
+static void extract_points_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *_userdata)
+{
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(elb, ibo);
+}
+
constexpr MeshExtract create_extractor_points()
{
MeshExtract extractor = {nullptr};
@@ -167,6 +231,9 @@ constexpr MeshExtract create_extractor_points()
extractor.iter_lvert_mesh = extract_points_iter_lvert_mesh;
extractor.task_reduce = extract_points_task_reduce;
extractor.finish = extract_points_finish;
+ extractor.init_subdiv = extract_points_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_points_loose_geom_subdiv;
+ extractor.finish_subdiv = extract_points_finish_subdiv;
extractor.use_threading = true;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(GPUIndexBufBuilder);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
index 54e733d3d86..b1ace8bc6c9 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
@@ -25,6 +25,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_from)
@@ -123,10 +125,37 @@ static void extract_tris_finish(const MeshRenderData *mr,
}
}
+static void extract_tris_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
+ /* Initialize the index buffer, it was already allocated, it will be filled on the device. */
+ GPU_indexbuf_init_build_on_device(ibo, subdiv_cache->num_subdiv_triangles * 3);
+
+ if (cache->tris_per_mat) {
+ for (int i = 0; i < cache->mat_len; i++) {
+ if (cache->tris_per_mat[i] == nullptr) {
+ cache->tris_per_mat[i] = GPU_indexbuf_calloc();
+ }
+
+ /* Multiply by 6 since we have 2 triangles per quad. */
+ const int start = subdiv_cache->mat_start[i] * 6;
+ const int len = (subdiv_cache->mat_end[i] - subdiv_cache->mat_start[i]) * 6;
+ GPU_indexbuf_create_subrange_in_place(cache->tris_per_mat[i], ibo, start, len);
+ }
+ }
+
+ draw_subdiv_build_tris_buffer(subdiv_cache, ibo, cache->mat_len);
+}
+
constexpr MeshExtract create_extractor_tris()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_tris_init;
+ extractor.init_subdiv = extract_tris_init_subdiv;
extractor.iter_poly_bm = extract_tris_iter_poly_bm;
extractor.iter_poly_mesh = extract_tris_iter_poly_mesh;
extractor.task_reduce = extract_tris_mat_task_reduce;
@@ -214,6 +243,7 @@ constexpr MeshExtract create_extractor_tris_single_mat()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_tris_single_mat_init;
+ extractor.init_subdiv = extract_tris_init_subdiv;
extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh;
extractor.task_reduce = extract_tris_mat_task_reduce;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
index 8a5a8134ca7..b846da3f016 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -25,13 +25,12 @@
#include <functional>
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
-#include "BLI_float4.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
#include "BKE_attribute.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -153,7 +152,9 @@ static GPUVertCompType get_comp_type_for_type(CustomDataType type)
static void init_vbo_for_attribute(const MeshRenderData *mr,
GPUVertBuf *vbo,
- const DRW_AttributeRequest &request)
+ const DRW_AttributeRequest &request,
+ bool build_on_device,
+ uint32_t len)
{
GPUVertCompType comp_type = get_comp_type_for_type(request.cd_type);
GPUVertFetchMode fetch_mode = get_fetch_mode_for_type(request.cd_type);
@@ -184,8 +185,13 @@ static void init_vbo_for_attribute(const MeshRenderData *mr,
}
}
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, static_cast<uint32_t>(mr->loop_len));
+ if (build_on_device) {
+ GPU_vertbuf_init_build_on_device(vbo, &format, len);
+ }
+ else {
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, len);
+ }
}
template<typename AttributeType, typename VBOType>
@@ -309,7 +315,7 @@ static void extract_attr_init(const MeshRenderData *mr,
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- init_vbo_for_attribute(mr, vbo, request);
+ init_vbo_for_attribute(mr, vbo, request, false, static_cast<uint32_t>(mr->loop_len));
/* TODO(kevindietrich) : float3 is used for scalar attributes as the implicit conversion done by
* OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following the
@@ -346,6 +352,68 @@ static void extract_attr_init(const MeshRenderData *mr,
}
}
+static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(tls_data),
+ int index)
+{
+ const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_AttributeRequest &request = attrs_used->requests[index];
+
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+
+ const uint32_t dimensions = gpu_component_size_for_attribute_type(request.cd_type);
+
+ /* Prepare VBO for coarse data. The compute shader only expects floats. */
+ GPUVertBuf *src_data = GPU_vertbuf_calloc();
+ static GPUVertFormat coarse_format = {0};
+ GPU_vertformat_attr_add(&coarse_format, "data", GPU_COMP_F32, dimensions, GPU_FETCH_FLOAT);
+ GPU_vertbuf_init_with_format_ex(src_data, &coarse_format, GPU_USAGE_STATIC);
+ GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop));
+
+ switch (request.cd_type) {
+ case CD_PROP_BOOL: {
+ extract_attr_generic<bool, float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_INT32: {
+ extract_attr_generic<int32_t, float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_FLOAT: {
+ extract_attr_generic<float, float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_FLOAT2: {
+ extract_attr_generic<float2>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ extract_attr_generic<float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_COLOR: {
+ extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request);
+ break;
+ }
+ default: {
+ BLI_assert(false);
+ }
+ }
+
+ GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
+ init_vbo_for_attribute(mr, dst_buffer, request, true, subdiv_cache->num_subdiv_loops);
+
+ /* Ensure data is uploaded properly. */
+ GPU_vertbuf_tag_dirty(src_data);
+ draw_subdiv_interp_custom_data(
+ subdiv_cache, src_data, dst_buffer, static_cast<int>(dimensions), 0);
+
+ GPU_vertbuf_discard(src_data);
+}
+
/* Wrappers around extract_attr_init so we can pass the index of the attribute that we want to
* extract. The overall API does not allow us to pass this in a convenient way. */
#define EXTRACT_INIT_WRAPPER(index) \
@@ -353,6 +421,14 @@ static void extract_attr_init(const MeshRenderData *mr,
const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *tls_data) \
{ \
extract_attr_init(mr, cache, buf, tls_data, index); \
+ } \
+ static void extract_attr_init_subdiv##index(const DRWSubdivCache *subdiv_cache, \
+ const MeshRenderData *mr, \
+ struct MeshBatchCache *cache, \
+ void *buf, \
+ void *tls_data) \
+ { \
+ extract_attr_init_subdiv(subdiv_cache, mr, cache, buf, tls_data, index); \
}
EXTRACT_INIT_WRAPPER(0)
@@ -371,10 +447,12 @@ EXTRACT_INIT_WRAPPER(12)
EXTRACT_INIT_WRAPPER(13)
EXTRACT_INIT_WRAPPER(14)
-template<int index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn)
+template<int index>
+constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn)
{
MeshExtract extractor = {nullptr};
extractor.init = fn;
+ extractor.init_subdiv = subdiv_fn;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
@@ -388,7 +466,8 @@ template<int index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn
extern "C" {
#define CREATE_EXTRACTOR_ATTR(index) \
- blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index)
+ blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index, \
+ blender::draw::extract_attr_init_subdiv##index)
const MeshExtract extract_attr[GPU_MAX_ATTR] = {
CREATE_EXTRACTOR_ATTR(0),
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
index 2e2444a8e3d..8470a71059f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
@@ -25,6 +25,7 @@
#include "GPU_capabilities.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -148,9 +149,8 @@ static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr,
const MLoop *ml_next = &mr->mloop[ml_index_other];
const MVert *v1 = &mr->mvert[ml->v];
const MVert *v2 = &mr->mvert[ml_next->v];
- float vnor_f[3];
- normal_short_to_float_v3(vnor_f, v1->no);
- float ratio = loop_edge_factor_get(mr->poly_normals[mp_index], v1->co, vnor_f, v2->co);
+ float ratio = loop_edge_factor_get(
+ mr->poly_normals[mp_index], v1->co, mr->vert_normals[ml->v], v2->co);
data->vbo_data[ml_index] = ratio * 253 + 1;
}
else {
@@ -216,6 +216,86 @@ static void extract_edge_fac_finish(const MeshRenderData *mr,
MEM_SAFE_FREE(data->edge_loop_count);
}
+/* Different function than the one used for the non-subdivision case, as we directly take care of
+ * the buggy AMD driver case. */
+static GPUVertFormat *get_subdiv_edge_fac_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ if (GPU_crappy_amd_driver()) {
+ GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ else {
+ GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ }
+ return &format;
+}
+
+static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *edge_idx = cache->final.buff.vbo.edge_idx;
+ GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ GPU_vertbuf_init_build_on_device(
+ vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+
+ /* Create a temporary buffer for the edge original indices if it was not requested. */
+ const bool has_edge_idx = edge_idx != nullptr;
+ GPUVertBuf *loop_edge_idx = nullptr;
+ if (has_edge_idx) {
+ loop_edge_idx = edge_idx;
+ }
+ else {
+ loop_edge_idx = GPU_vertbuf_calloc();
+ draw_subdiv_init_origindex_buffer(
+ loop_edge_idx,
+ static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)),
+ subdiv_cache->num_subdiv_loops,
+ 0);
+ }
+
+ draw_subdiv_build_edge_fac_buffer(subdiv_cache, pos_nor, loop_edge_idx, vbo);
+
+ if (!has_edge_idx) {
+ GPU_vertbuf_discard(loop_edge_idx);
+ }
+}
+
+static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ if (loose_geom->edge_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+
+ /* Make sure buffer is active for sending loose data. */
+ GPU_vertbuf_use(vbo);
+
+ uint offset = subdiv_cache->num_subdiv_loops;
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ if (GPU_crappy_amd_driver()) {
+ float loose_edge_fac[2] = {1.0f, 1.0f};
+ GPU_vertbuf_update_sub(vbo, offset * sizeof(float), sizeof(loose_edge_fac), loose_edge_fac);
+ }
+ else {
+ char loose_edge_fac[2] = {255, 255};
+ GPU_vertbuf_update_sub(vbo, offset * sizeof(char), sizeof(loose_edge_fac), loose_edge_fac);
+ }
+
+ offset += 2;
+ }
+}
+
constexpr MeshExtract create_extractor_edge_fac()
{
MeshExtract extractor = {nullptr};
@@ -224,6 +304,8 @@ constexpr MeshExtract create_extractor_edge_fac()
extractor.iter_poly_mesh = extract_edge_fac_iter_poly_mesh;
extractor.iter_ledge_bm = extract_edge_fac_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh;
+ extractor.init_subdiv = extract_edge_fac_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_edge_fac_loose_geom_subdiv;
extractor.finish = extract_edge_fac_finish;
extractor.data_type = MR_DATA_POLY_NOR;
extractor.data_size = sizeof(MeshExtract_EdgeFac_Data);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
index 5232346e51e..0002b95c867 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
@@ -25,6 +25,8 @@
#include "draw_cache_impl.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -70,11 +72,11 @@ static void mesh_render_data_edge_flag(const MeshRenderData *mr,
}
}
- /* Use a byte for value range */
- if (mr->crease_ofs != -1) {
- float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->crease_ofs);
+ /* Use half a byte for value range */
+ if (mr->edge_crease_ofs != -1) {
+ float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->edge_crease_ofs);
if (crease > 0) {
- eattr->crease = (uchar)(crease * 255.0f);
+ eattr->crease = (uchar)ceil(crease * 15.0f);
}
}
/* Use a byte for value range */
@@ -105,21 +107,34 @@ static void mesh_render_data_vert_flag(const MeshRenderData *mr,
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
eattr->e_flag |= VFLAG_VERT_SELECTED;
}
+ /* Use half a byte for value range */
+ if (mr->vert_crease_ofs != -1) {
+ float crease = BM_ELEM_CD_GET_FLOAT(eve, mr->vert_crease_ofs);
+ if (crease > 0) {
+ eattr->crease |= (uchar)ceil(crease * 15.0f) << 4;
+ }
+ }
}
-static void extract_edit_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf,
- void *tls_data)
+static GPUVertFormat *get_edit_data_format()
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING: Adjust #EditLoopData struct accordingly. */
GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
GPU_vertformat_alias_add(&format, "flag");
}
- GPU_vertbuf_init_with_format(vbo, &format);
+ return &format;
+}
+
+static void extract_edit_data_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat *format = get_edit_data_format();
+ GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
*(EditLoopData **)tls_data = vbo_data;
@@ -240,6 +255,92 @@ static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr,
}
}
+static void extract_edit_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPU_vertbuf_init_with_format(vbo, get_edit_data_format());
+ GPU_vertbuf_data_alloc(vbo, subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+ EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
+ *(EditLoopData **)data = vbo_data;
+}
+
+static void extract_edit_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_quad)
+{
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
+ int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
+ int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint i = start_loop_idx; i < end_loop_idx; i++) {
+ const int vert_origindex = subdiv_loop_vert_index[i];
+ const int edge_origindex = subdiv_loop_edge_index[i];
+
+ EditLoopData *edit_loop_data = &vbo_data[i];
+ memset(edit_loop_data, 0, sizeof(EditLoopData));
+
+ if (vert_origindex != -1) {
+ const BMVert *eve = bm_original_vert_get(mr, vert_origindex);
+ if (eve) {
+ mesh_render_data_vert_flag(mr, eve, edit_loop_data);
+ }
+ }
+
+ if (edge_origindex != -1) {
+ const BMEdge *eed = bm_original_edge_get(mr, edge_origindex);
+ if (eed) {
+ mesh_render_data_edge_flag(mr, eed, edit_loop_data);
+ }
+ }
+
+ /* The -1 parameter is for edit_uvs, which we don't do here. */
+ mesh_render_data_face_flag(mr, coarse_quad, -1, edit_loop_data);
+ }
+}
+
+static void extract_edit_data_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad)
+{
+ const int coarse_quad_index = static_cast<int>(coarse_quad - mr->mpoly);
+ BMFace *coarse_quad_bm = bm_original_face_get(mr, coarse_quad_index);
+ extract_edit_data_iter_subdiv_bm(subdiv_cache, mr, _data, subdiv_quad_index, coarse_quad_bm);
+}
+
+static void extract_edit_data_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ const MeshExtractLooseGeom *loose_geom,
+ void *UNUSED(buffer),
+ void *_data)
+{
+ if (loose_geom->edge_len == 0) {
+ return;
+ }
+
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
+
+ for (int ledge_index = 0; ledge_index < loose_geom->edge_len; ledge_index++) {
+ const int offset = subdiv_cache->num_subdiv_loops + ledge_index * 2;
+ EditLoopData *data = &vbo_data[offset];
+ memset(data, 0, sizeof(EditLoopData));
+ BMEdge *eed = bm_original_edge_get(mr, loose_geom->edges[ledge_index]);
+ mesh_render_data_edge_flag(mr, eed, &data[0]);
+ data[1] = data[0];
+ mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
+ mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
+ }
+}
+
constexpr MeshExtract create_extractor_edit_data()
{
MeshExtract extractor = {nullptr};
@@ -250,6 +351,10 @@ constexpr MeshExtract create_extractor_edit_data()
extractor.iter_ledge_mesh = extract_edit_data_iter_ledge_mesh;
extractor.iter_lvert_bm = extract_edit_data_iter_lvert_bm;
extractor.iter_lvert_mesh = extract_edit_data_iter_lvert_mesh;
+ extractor.init_subdiv = extract_edit_data_init_subdiv;
+ extractor.iter_subdiv_bm = extract_edit_data_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_edit_data_iter_subdiv_mesh;
+ extractor.iter_loose_geom_subdiv = extract_edit_data_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(EditLoopData *);
extractor.use_threading = true;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
index b8494428eed..b25e40690c9 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
@@ -25,6 +25,8 @@
#include "draw_cache_impl.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -36,12 +38,11 @@ struct MeshExtract_EditUVData_Data {
int cd_ofs;
};
-static void extract_edituv_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf,
- void *tls_data)
+static void extract_edituv_data_init_common(const MeshRenderData *mr,
+ GPUVertBuf *vbo,
+ MeshExtract_EditUVData_Data *data,
+ uint loop_len)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING: Adjust #EditLoopData struct accordingly. */
@@ -50,15 +51,23 @@ static void extract_edituv_data_init(const MeshRenderData *mr,
}
GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+ GPU_vertbuf_data_alloc(vbo, loop_len);
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
-
- MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data);
data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
}
+static void extract_edituv_data_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data);
+ extract_edituv_data_init_common(mr, vbo, data, mr->loop_len);
+}
+
static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr,
const BMFace *f,
const int UNUSED(f_index),
@@ -119,12 +128,66 @@ static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static void extract_edituv_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data);
+ extract_edituv_data_init_common(mr, vbo, data, subdiv_cache->num_subdiv_loops);
+}
+
+static void extract_edituv_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const BMFace *coarse_quad)
+{
+ MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(_data);
+ int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
+ int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index);
+
+ uint start_loop_idx = subdiv_quad_index * 4;
+ uint end_loop_idx = (subdiv_quad_index + 1) * 4;
+ for (uint i = start_loop_idx; i < end_loop_idx; i++) {
+ const int vert_origindex = subdiv_loop_vert_index[i];
+ const int edge_origindex = subdiv_loop_edge_index[i];
+
+ EditLoopData *edit_loop_data = &data->vbo_data[i];
+ memset(edit_loop_data, 0, sizeof(EditLoopData));
+
+ if (vert_origindex != -1 && edge_origindex != -1) {
+ BMEdge *eed = bm_original_edge_get(mr, edge_origindex);
+ /* Loop on an edge endpoint. */
+ BMLoop *l = BM_face_edge_share_loop(const_cast<BMFace *>(coarse_quad), eed);
+ mesh_render_data_loop_flag(mr, l, data->cd_ofs, edit_loop_data);
+ mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, edit_loop_data);
+ }
+ }
+}
+
+static void extract_edituv_data_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad)
+{
+ const int coarse_quad_index = static_cast<int>(coarse_quad - mr->mpoly);
+ BMFace *coarse_quad_bm = bm_original_face_get(mr, coarse_quad_index);
+ extract_edituv_data_iter_subdiv_bm(subdiv_cache, mr, _data, subdiv_quad_index, coarse_quad_bm);
+}
+
constexpr MeshExtract create_extractor_edituv_data()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_data_init;
extractor.iter_poly_bm = extract_edituv_data_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_data_iter_poly_mesh;
+ extractor.init_subdiv = extract_edituv_data_init_subdiv;
+ extractor.iter_subdiv_bm = extract_edituv_data_iter_subdiv_bm;
+ extractor.iter_subdiv_mesh = extract_edituv_data_iter_subdiv_mesh;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUVData_Data);
extractor.use_threading = true;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
index a947d98f955..49b23ff1efe 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
@@ -27,6 +27,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -213,12 +215,69 @@ static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr
}
}
+static GPUVertFormat *get_edituv_stretch_angle_format_subdiv()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* Waning: adjust #UVStretchAngle struct accordingly. */
+ GPU_vertformat_attr_add(&format, "angle", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(tls_data))
+{
+ GPUVertBuf *refined_vbo = static_cast<GPUVertBuf *>(buffer);
+
+ GPU_vertbuf_init_build_on_device(
+ refined_vbo, get_edituv_stretch_angle_format_subdiv(), subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
+ GPUVertBuf *uvs = cache->final.buff.vbo.uv;
+
+ /* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active
+ * UV layer. */
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_MESH) ? &mr->me->ldata : &mr->bm->ldata;
+
+ uint32_t uv_layers = cache->cd_used.uv;
+ /* HACK to fix T68857 */
+ if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
+ int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
+ if (layer != -1) {
+ uv_layers |= (1 << layer);
+ }
+ }
+
+ int uvs_offset = 0;
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (uv_layers & (1 << i)) {
+ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
+ break;
+ }
+
+ uvs_offset += 1;
+ }
+ }
+
+ /* The data is at `offset * num loops`, and we have 2 values per index. */
+ uvs_offset *= subdiv_cache->num_subdiv_loops * 2;
+
+ draw_subdiv_build_edituv_stretch_angle_buffer(
+ subdiv_cache, pos_nor, uvs, uvs_offset, refined_vbo);
+}
+
constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_stretch_angle_init;
extractor.iter_poly_bm = extract_edituv_stretch_angle_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_stretch_angle_iter_poly_mesh;
+ extractor.init_subdiv = extract_edituv_stretch_angle_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_StretchAngle_Data);
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
index 3db8cd79af5..c116fa5ba07 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
@@ -27,6 +27,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -63,14 +65,12 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_t
return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
}
-static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(data))
+static void compute_area_ratio(const MeshRenderData *mr,
+ float *r_area_ratio,
+ float &r_tot_area,
+ float &r_tot_uv_area)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
float tot_area = 0.0f, tot_uv_area = 0.0f;
- float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__));
if (mr->extract_type == MR_EXTRACT_BMESH) {
CustomData *cd_ldata = &mr->bm->ldata;
@@ -84,7 +84,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
float uvarea = BM_face_calc_area_uv(efa, uv_ofs);
tot_area += area;
tot_uv_area += uvarea;
- area_ratio[f] = area_ratio_get(area, uvarea);
+ r_area_ratio[f] = area_ratio_get(area, uvarea);
}
}
else {
@@ -96,12 +96,22 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
float uvarea = BKE_mesh_calc_poly_uv_area(mp, uv_data);
tot_area += area;
tot_uv_area += uvarea;
- area_ratio[mp_index] = area_ratio_get(area, uvarea);
+ r_area_ratio[mp_index] = area_ratio_get(area, uvarea);
}
}
- cache->tot_area = tot_area;
- cache->tot_uv_area = tot_uv_area;
+ r_tot_area = tot_area;
+ r_tot_uv_area = tot_uv_area;
+}
+
+static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__));
+ compute_area_ratio(mr, area_ratio, cache->tot_area, cache->tot_uv_area);
/* Convert in place to avoid an extra allocation */
uint16_t *poly_stretch = (uint16_t *)area_ratio;
@@ -135,11 +145,46 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
MEM_freeN(area_ratio);
}
+static void extract_edituv_stretch_area_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+
+ /* Initialize final buffer. */
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+
+ GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops);
+
+ /* Initialize coarse data buffer. */
+
+ GPUVertBuf *coarse_data = GPU_vertbuf_calloc();
+
+ /* We use the same format as we just copy data around. */
+ GPU_vertbuf_init_with_format(coarse_data, &format);
+ GPU_vertbuf_data_alloc(coarse_data, mr->loop_len);
+
+ compute_area_ratio(mr,
+ static_cast<float *>(GPU_vertbuf_get_data(coarse_data)),
+ cache->tot_area,
+ cache->tot_uv_area);
+
+ draw_subdiv_build_edituv_stretch_area_buffer(subdiv_cache, coarse_data, vbo);
+
+ GPU_vertbuf_discard(coarse_data);
+}
+
constexpr MeshExtract create_extractor_edituv_stretch_area()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_stretch_area_init;
extractor.finish = extract_edituv_stretch_area_finish;
+ extractor.init_subdiv = extract_edituv_stretch_area_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
index 33f9180e122..f65159f9b95 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
@@ -23,24 +23,40 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots positions
* \{ */
-static void extract_fdots_pos_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf,
- void *tls_data)
+static GPUVertFormat *get_fdots_pos_format()
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
}
+ return &format;
+}
+
+static GPUVertFormat *get_fdots_nor_format_subdiv()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
- GPU_vertbuf_init_with_format(vbo, &format);
+static void extract_fdots_pos_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat *format = get_fdots_pos_format();
+ GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
void *vbo_data = GPU_vertbuf_get_data(vbo);
*(float(**)[3])tls_data = static_cast<float(*)[3]>(vbo_data);
@@ -97,10 +113,30 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static void extract_fdots_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ /* We "extract" positions, normals, and indices at once. */
+ GPUVertBuf *fdots_pos_vbo = static_cast<GPUVertBuf *>(buffer);
+ GPUVertBuf *fdots_nor_vbo = cache->final.buff.vbo.fdots_nor;
+ GPUIndexBuf *fdots_pos_ibo = cache->final.buff.ibo.fdots;
+
+ GPU_vertbuf_init_build_on_device(
+ fdots_nor_vbo, get_fdots_nor_format_subdiv(), subdiv_cache->num_coarse_poly);
+ GPU_vertbuf_init_build_on_device(
+ fdots_pos_vbo, get_fdots_pos_format(), subdiv_cache->num_coarse_poly);
+ GPU_indexbuf_init_build_on_device(fdots_pos_ibo, subdiv_cache->num_coarse_poly);
+ draw_subdiv_build_fdots_buffers(subdiv_cache, fdots_pos_vbo, fdots_nor_vbo, fdots_pos_ibo);
+}
+
constexpr MeshExtract create_extractor_fdots_pos()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_fdots_pos_init;
+ extractor.init_subdiv = extract_fdots_init_subdiv;
extractor.iter_poly_bm = extract_fdots_pos_iter_poly_bm;
extractor.iter_poly_mesh = extract_fdots_pos_iter_poly_mesh;
extractor.data_type = MR_DATA_NONE;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
index 3c3ac7a7a0a..93b94b210b2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
@@ -23,6 +23,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -85,7 +87,7 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
*lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]);
}
else if (mp->flag & ME_SMOOTH) {
- *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[ml->v].no);
+ *lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]);
}
else {
*lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]);
@@ -107,10 +109,34 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static GPUVertFormat *get_subdiv_lnor_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "lnor");
+ }
+ return &format;
+}
+
+static void extract_lnor_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
+ BLI_assert(pos_nor);
+ GPU_vertbuf_init_build_on_device(vbo, get_subdiv_lnor_format(), subdiv_cache->num_subdiv_loops);
+ draw_subdiv_build_lnor_buffer(subdiv_cache, pos_nor, vbo);
+}
+
constexpr MeshExtract create_extractor_lnor()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_lnor_init;
+ extractor.init_subdiv = extract_lnor_init_subdiv;
extractor.iter_poly_bm = extract_lnor_iter_poly_bm;
extractor.iter_poly_mesh = extract_lnor_iter_poly_mesh;
extractor.data_type = MR_DATA_LOOP_NOR;
@@ -184,7 +210,7 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr,
normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]);
}
else if (mp->flag & ME_SMOOTH) {
- copy_v3_v3_short(&lnor_data->x, mr->mvert[ml->v].no);
+ normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]);
}
else {
normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]);
@@ -210,6 +236,7 @@ constexpr MeshExtract create_extractor_lnor_hq()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_lnor_hq_init;
+ extractor.init_subdiv = extract_lnor_init_subdiv;
extractor.iter_poly_bm = extract_lnor_hq_iter_poly_bm;
extractor.iter_poly_mesh = extract_lnor_hq_iter_poly_mesh;
extractor.data_type = MR_DATA_LOOP_NOR;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
index 33a33c81bc2..706c6ad5403 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
@@ -460,7 +460,7 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort)
float fac = -1.0f;
if (mp->totloop > 3) {
- float *f_no = mr->poly_normals[mp_index];
+ const float *f_no = mr->poly_normals[mp_index];
fac = 0.0f;
for (int i = 1; i <= mp->totloop; i++) {
@@ -555,7 +555,7 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp)
void **pval;
bool value_is_init = BLI_edgehash_ensure_p(eh, l_curr->v, l_next->v, &pval);
if (!value_is_init) {
- *pval = mr->poly_normals[mp_index];
+ *pval = (void *)mr->poly_normals[mp_index];
/* non-manifold edge, yet... */
continue;
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
index eb9a138590c..5d2ea923658 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
@@ -25,6 +25,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -72,9 +74,8 @@ static void extract_pos_nor_init(const MeshRenderData *mr,
}
}
else {
- const MVert *mv = mr->mvert;
- for (int v = 0; v < mr->vert_len; v++, mv++) {
- data->normals[v].low = GPU_normal_convert_i10_s3(mv->no);
+ for (int v = 0; v < mr->vert_len; v++) {
+ data->normals[v].low = GPU_normal_convert_i10_v3(mr->vert_normals[v]);
}
}
}
@@ -194,6 +195,123 @@ static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data->normals);
}
+static GPUVertFormat *get_pos_nor_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "vnor");
+ }
+ return &format;
+}
+
+static GPUVertFormat *get_normals_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "lnor");
+ }
+ return &format;
+}
+
+static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ const bool do_limit_normals = subdiv_cache->do_limit_normals;
+
+ /* Initialize the vertex buffer, it was already allocated. */
+ GPU_vertbuf_init_build_on_device(
+ vbo, get_pos_nor_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+
+ draw_subdiv_extract_pos_nor(subdiv_cache, vbo, do_limit_normals);
+
+ if (!do_limit_normals) {
+ /* We cannot evaluate vertex normals using the limit surface, so compute them manually. */
+ GPUVertBuf *subdiv_loop_subdiv_vert_index = draw_subdiv_build_origindex_buffer(
+ subdiv_cache->subdiv_loop_subdiv_vert_index, subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *vertex_normals = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_build_on_device(
+ vertex_normals, get_normals_format(), subdiv_cache->num_subdiv_verts);
+
+ draw_subdiv_accumulate_normals(subdiv_cache,
+ vbo,
+ subdiv_cache->subdiv_vertex_face_adjacency_offsets,
+ subdiv_cache->subdiv_vertex_face_adjacency,
+ vertex_normals);
+
+ draw_subdiv_finalize_normals(subdiv_cache, vertex_normals, subdiv_loop_subdiv_vert_index, vbo);
+
+ GPU_vertbuf_discard(vertex_normals);
+ GPU_vertbuf_discard(subdiv_loop_subdiv_vert_index);
+ }
+}
+
+static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
+ const MEdge *coarse_edges = coarse_mesh->medge;
+ const MVert *coarse_verts = coarse_mesh->mvert;
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ /* TODO(kevindietrich) : replace this when compressed normals are supported. */
+ struct SubdivPosNorLoop {
+ float pos[3];
+ float nor[3];
+ float flag;
+ };
+
+ SubdivPosNorLoop edge_data[2];
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
+ const MVert *loose_vert1 = &coarse_verts[loose_edge->v1];
+ const MVert *loose_vert2 = &coarse_verts[loose_edge->v2];
+
+ copy_v3_v3(edge_data[0].pos, loose_vert1->co);
+ copy_v3_v3(edge_data[0].nor, mr->vert_normals[loose_edge->v1]);
+ edge_data[0].flag = 0.0f;
+
+ copy_v3_v3(edge_data[1].pos, loose_vert2->co);
+ copy_v3_v3(edge_data[1].nor, mr->vert_normals[loose_edge->v2]);
+ edge_data[1].flag = 0.0f;
+
+ GPU_vertbuf_update_sub(
+ vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data);
+
+ offset += 2;
+ }
+
+ SubdivPosNorLoop vert_data;
+ vert_data.flag = 0.0f;
+ for (int i = 0; i < loose_geom->vert_len; i++) {
+ const MVert *loose_vertex = &coarse_verts[loose_geom->verts[i]];
+
+ copy_v3_v3(vert_data.pos, loose_vertex->co);
+ copy_v3_v3(vert_data.nor, mr->vert_normals[loose_geom->verts[i]]);
+
+ GPU_vertbuf_update_sub(
+ vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data);
+
+ offset += 1;
+ }
+}
+
constexpr MeshExtract create_extractor_pos_nor()
{
MeshExtract extractor = {nullptr};
@@ -205,6 +323,8 @@ constexpr MeshExtract create_extractor_pos_nor()
extractor.iter_lvert_bm = extract_pos_nor_iter_lvert_bm;
extractor.iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh;
extractor.finish = extract_pos_nor_finish;
+ extractor.init_subdiv = extract_pos_nor_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_pos_nor_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_PosNor_Data);
extractor.use_threading = true;
@@ -259,9 +379,8 @@ static void extract_pos_nor_hq_init(const MeshRenderData *mr,
}
}
else {
- const MVert *mv = mr->mvert;
- for (int v = 0; v < mr->vert_len; v++, mv++) {
- copy_v3_v3_short(data->normals[v].high, mv->no);
+ for (int v = 0; v < mr->vert_len; v++) {
+ normal_float_to_short_v3(data->normals[v].high, mr->vert_normals[v]);
}
}
}
@@ -391,6 +510,7 @@ constexpr MeshExtract create_extractor_pos_nor_hq()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_pos_nor_hq_init;
+ extractor.init_subdiv = extract_pos_nor_init_subdiv;
extractor.iter_poly_bm = extract_pos_nor_hq_iter_poly_bm;
extractor.iter_poly_mesh = extract_pos_nor_hq_iter_poly_mesh;
extractor.iter_ledge_bm = extract_pos_nor_hq_iter_ledge_bm;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
index fd91bc5258f..753fbe7e0e2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
@@ -27,6 +27,7 @@
#include "BKE_paint.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -35,13 +36,23 @@ namespace blender::draw {
/** \name Extract Sculpt Data
* \{ */
+static GPUVertFormat *get_sculpt_data_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
static void extract_sculpt_data_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- GPUVertFormat format = {0};
+ GPUVertFormat *format = get_sculpt_data_format();
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
@@ -50,12 +61,7 @@ static void extract_sculpt_data_init(const MeshRenderData *mr,
float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
- if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- }
-
- GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
struct gpuSculptData {
@@ -121,10 +127,99 @@ static void extract_sculpt_data_init(const MeshRenderData *mr,
}
}
+static void extract_sculpt_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+
+ Mesh *coarse_mesh = mr->me;
+ CustomData *cd_vdata = &coarse_mesh->vdata;
+ CustomData *cd_pdata = &coarse_mesh->pdata;
+
+ /* First, interpolate mask if available. */
+ GPUVertBuf *mask_vbo = nullptr;
+ GPUVertBuf *subdiv_mask_vbo = nullptr;
+ float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
+
+ if (cd_mask) {
+ GPUVertFormat mask_format = {0};
+ GPU_vertformat_attr_add(&mask_format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+
+ mask_vbo = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(mask_vbo, &mask_format);
+ GPU_vertbuf_data_alloc(mask_vbo, coarse_mesh->totloop);
+ float *v_mask = static_cast<float *>(GPU_vertbuf_get_data(mask_vbo));
+
+ for (int i = 0; i < coarse_mesh->totpoly; i++) {
+ const MPoly *mpoly = &coarse_mesh->mpoly[i];
+
+ for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop;
+ loop_index++) {
+ const MLoop *ml = &coarse_mesh->mloop[loop_index];
+ *v_mask++ = cd_mask[ml->v];
+ }
+ }
+
+ subdiv_mask_vbo = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_build_on_device(
+ subdiv_mask_vbo, &mask_format, subdiv_cache->num_subdiv_loops);
+
+ draw_subdiv_interp_custom_data(subdiv_cache, mask_vbo, subdiv_mask_vbo, 1, 0);
+ }
+
+ /* Then, gather face sets. */
+ GPUVertFormat face_set_format = {0};
+ GPU_vertformat_attr_add(&face_set_format, "msk", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ GPUVertBuf *face_set_vbo = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(face_set_vbo, &face_set_format);
+ GPU_vertbuf_data_alloc(face_set_vbo, subdiv_cache->num_subdiv_loops);
+
+ struct gpuFaceSet {
+ uint8_t color[4];
+ };
+
+ gpuFaceSet *face_sets = (gpuFaceSet *)GPU_vertbuf_get_data(face_set_vbo);
+ int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
+
+ GPUVertFormat *format = get_sculpt_data_format();
+ GPU_vertbuf_init_build_on_device(vbo, format, subdiv_cache->num_subdiv_loops);
+ int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index;
+
+ for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) {
+ const int mp_index = subdiv_loop_poly_index[i];
+
+ uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
+ if (cd_face_set) {
+ const int face_set_id = cd_face_set[mp_index];
+ /* Skip for the default color Face Set to render it white. */
+ if (face_set_id != coarse_mesh->face_sets_color_default) {
+ BKE_paint_face_set_overlay_color_get(
+ face_set_id, coarse_mesh->face_sets_color_seed, face_set_color);
+ }
+ }
+ copy_v3_v3_uchar(face_sets->color, face_set_color);
+ face_sets++;
+ }
+
+ /* Finally, interleave mask and face sets. */
+ draw_subdiv_build_sculpt_data_buffer(subdiv_cache, subdiv_mask_vbo, face_set_vbo, vbo);
+
+ if (mask_vbo) {
+ GPU_vertbuf_discard(mask_vbo);
+ GPU_vertbuf_discard(subdiv_mask_vbo);
+ }
+ GPU_vertbuf_discard(face_set_vbo);
+}
+
constexpr MeshExtract create_extractor_sculpt_data()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_sculpt_data_init;
+ extractor.init_subdiv = extract_sculpt_data_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
index 5ac30dd3be9..33c27b45627 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
@@ -21,6 +21,7 @@
* \ingroup draw
*/
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -196,12 +197,104 @@ static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr,
(*(uint32_t **)data)[offset + lvert_index] = v_orig;
}
+static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ /* Each element points to an element in the ibo.points. */
+ draw_subdiv_init_origindex_buffer(vbo,
+ subdiv_cache->subdiv_loop_subdiv_vert_index,
+ subdiv_cache->num_subdiv_loops,
+ mr->loop_loose_len);
+}
+
+static void extract_vert_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo);
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
+ const MEdge *coarse_edges = coarse_mesh->medge;
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
+ vert_idx_data[offset] = loose_edge->v1;
+ vert_idx_data[offset + 1] = loose_edge->v2;
+ offset += 2;
+ }
+
+ for (int i = 0; i < loose_geom->vert_len; i++) {
+ vert_idx_data[offset] = loose_geom->verts[i];
+ offset += 1;
+ }
+}
+
+static void extract_edge_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ draw_subdiv_init_origindex_buffer(
+ vbo,
+ static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)),
+ subdiv_cache->num_subdiv_loops,
+ mr->edge_loose_len * 2);
+}
+
+static void extract_edge_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo);
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ vert_idx_data[offset] = loose_geom->edges[i];
+ vert_idx_data[offset + 1] = loose_geom->edges[i];
+ offset += 2;
+ }
+}
+
+static void extract_poly_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ draw_subdiv_init_origindex_buffer(
+ vbo, subdiv_cache->subdiv_loop_poly_index, subdiv_cache->num_subdiv_loops, 0);
+}
+
constexpr MeshExtract create_extractor_poly_idx()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_select_idx_init;
extractor.iter_poly_bm = extract_poly_idx_iter_poly_bm;
extractor.iter_poly_mesh = extract_poly_idx_iter_poly_mesh;
+ extractor.init_subdiv = extract_poly_idx_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(uint32_t *);
extractor.use_threading = true;
@@ -217,6 +310,8 @@ constexpr MeshExtract create_extractor_edge_idx()
extractor.iter_poly_mesh = extract_edge_idx_iter_poly_mesh;
extractor.iter_ledge_bm = extract_edge_idx_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh;
+ extractor.init_subdiv = extract_edge_idx_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_edge_idx_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(uint32_t *);
extractor.use_threading = true;
@@ -234,6 +329,8 @@ constexpr MeshExtract create_extractor_vert_idx()
extractor.iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh;
extractor.iter_lvert_bm = extract_vert_idx_iter_lvert_bm;
extractor.iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh;
+ extractor.init_subdiv = extract_vert_idx_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_vert_idx_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(uint32_t *);
extractor.use_threading = true;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
index 7a3b2cf49ff..03d1b327689 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
@@ -138,6 +138,7 @@ static void extract_tan_ex_init(const MeshRenderData *mr,
calc_active_tangent,
tangent_names,
tan_len,
+ mr->vert_normals,
mr->poly_normals,
mr->loop_normals,
orco,
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
index af279b08a59..6e9d8ef6926 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
@@ -23,6 +23,7 @@
#include "BLI_string.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -31,25 +32,27 @@ namespace blender::draw {
/** \name Extract UV layers
* \{ */
-static void extract_uv_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(tls_data))
+/* Initialize the vertex format to be used for UVs. Return true if any UV layer is
+ * found, false otherwise. */
+static bool mesh_extract_uv_format_init(GPUVertFormat *format,
+ struct MeshBatchCache *cache,
+ CustomData *cd_ldata,
+ eMRExtractType extract_type,
+ uint32_t &r_uv_layers)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- GPUVertFormat format = {0};
- GPU_vertformat_deinterleave(&format);
+ GPU_vertformat_deinterleave(format);
- CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
uint32_t uv_layers = cache->cd_used.uv;
/* HACK to fix T68857 */
- if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
+ if (extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
uv_layers |= (1 << layer);
}
}
+ r_uv_layers = uv_layers;
+
for (int i = 0; i < MAX_MTFACE; i++) {
if (uv_layers & (1 << i)) {
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
@@ -58,30 +61,47 @@ static void extract_uv_init(const MeshRenderData *mr,
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
/* UV layer name. */
BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name);
- GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
/* Auto layer name. */
BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
- GPU_vertformat_alias_add(&format, attr_name);
+ GPU_vertformat_alias_add(format, attr_name);
/* Active render layer name. */
if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
- GPU_vertformat_alias_add(&format, "u");
+ GPU_vertformat_alias_add(format, "u");
}
/* Active display layer name. */
if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
- GPU_vertformat_alias_add(&format, "au");
+ GPU_vertformat_alias_add(format, "au");
/* Alias to `pos` for edit uvs. */
- GPU_vertformat_alias_add(&format, "pos");
+ GPU_vertformat_alias_add(format, "pos");
}
/* Stencil mask uv layer name. */
if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) {
- GPU_vertformat_alias_add(&format, "mu");
+ GPU_vertformat_alias_add(format, "mu");
}
}
}
+ if (format->attr_len == 0) {
+ GPU_vertformat_attr_add(format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ return false;
+ }
+
+ return true;
+}
+
+static void extract_uv_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat format = {0};
+
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
int v_len = mr->loop_len;
- if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint32_t uv_layers = cache->cd_used.uv;
+ if (!mesh_extract_uv_format_init(&format, cache, cd_ldata, mr->extract_type, uv_layers)) {
/* VBO will not be used, only allocate minimum of memory. */
v_len = 1;
}
@@ -116,10 +136,45 @@ static void extract_uv_init(const MeshRenderData *mr,
}
}
+static void extract_uv_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ GPUVertFormat format = {0};
+
+ uint v_len = subdiv_cache->num_subdiv_loops;
+ uint uv_layers;
+ if (!mesh_extract_uv_format_init(
+ &format, cache, &coarse_mesh->ldata, MR_EXTRACT_MESH, uv_layers)) {
+ // TODO(kevindietrich): handle this more gracefully.
+ v_len = 1;
+ }
+
+ GPU_vertbuf_init_build_on_device(vbo, &format, v_len);
+
+ if (uv_layers == 0) {
+ return;
+ }
+
+ /* Index of the UV layer in the compact buffer. Used UV layers are stored in a single buffer. */
+ int pack_layer_index = 0;
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (uv_layers & (1 << i)) {
+ const int offset = (int)subdiv_cache->num_subdiv_loops * pack_layer_index++;
+ draw_subdiv_extract_uvs(subdiv_cache, vbo, i, offset);
+ }
+ }
+}
+
constexpr MeshExtract create_extractor_uv()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_uv_init;
+ extractor.init_subdiv = extract_uv_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
index f8878eb2617..a0307b9b2cd 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
@@ -25,6 +25,7 @@
#include "BLI_string.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -33,17 +34,14 @@ namespace blender::draw {
/** \name Extract VCol
* \{ */
-static void extract_vcol_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(tls_data))
+/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */
+static void init_vcol_format(GPUVertFormat *format,
+ const MeshBatchCache *cache,
+ CustomData *cd_ldata)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- GPUVertFormat format = {0};
- GPU_vertformat_deinterleave(&format);
+ GPU_vertformat_deinterleave(format);
- CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
- uint32_t vcol_layers = cache->cd_used.vcol;
+ const uint32_t vcol_layers = cache->cd_used.vcol;
for (int i = 0; i < MAX_MCOL; i++) {
if (vcol_layers & (1 << i)) {
@@ -52,31 +50,56 @@ static void extract_vcol_init(const MeshRenderData *mr,
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
- GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) {
- GPU_vertformat_alias_add(&format, "c");
+ GPU_vertformat_alias_add(format, "c");
}
if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) {
- GPU_vertformat_alias_add(&format, "ac");
+ GPU_vertformat_alias_add(format, "ac");
}
/* Gather number of auto layers. */
/* We only do `vcols` that are not overridden by `uvs`. */
if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
- GPU_vertformat_alias_add(&format, attr_name);
+ GPU_vertformat_alias_add(format, attr_name);
}
}
}
+}
+
+/* Vertex format for vertex colors, only used during the coarse data upload for the subdivision
+ * case. */
+static GPUVertFormat *get_coarse_vcol_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "cCol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "c");
+ GPU_vertformat_alias_add(&format, "ac");
+ }
+ return &format;
+}
+
+using gpuMeshVcol = struct gpuMeshVcol {
+ ushort r, g, b, a;
+};
+
+static void extract_vcol_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat format = {0};
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ const uint32_t vcol_layers = cache->cd_used.vcol;
+ init_vcol_format(&format, cache, cd_ldata);
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
- using gpuMeshVcol = struct gpuMeshVcol {
- ushort r, g, b, a;
- };
-
gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo);
for (int i = 0; i < MAX_MCOL; i++) {
@@ -111,10 +134,64 @@ static void extract_vcol_init(const MeshRenderData *mr,
}
}
+static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+
+ GPUVertFormat format = {0};
+ init_vcol_format(&format, cache, &coarse_mesh->ldata);
+
+ GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *src_data = GPU_vertbuf_calloc();
+ /* Dynamic as we upload and interpolate layers one at a time. */
+ GPU_vertbuf_init_with_format_ex(src_data, get_coarse_vcol_format(), GPU_USAGE_DYNAMIC);
+
+ GPU_vertbuf_data_alloc(src_data, coarse_mesh->totloop);
+
+ gpuMeshVcol *mesh_vcol = (gpuMeshVcol *)GPU_vertbuf_get_data(src_data);
+
+ const CustomData *cd_ldata = &coarse_mesh->ldata;
+
+ const uint vcol_layers = cache->cd_used.vcol;
+
+ /* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in
+ * a single buffer. */
+ int pack_layer_index = 0;
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (vcol_layers & (1 << i)) {
+ /* Include stride in offset, we use a stride of 2 since colors are packed into 2 uints. */
+ const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++;
+ const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
+
+ gpuMeshVcol *vcol = mesh_vcol;
+
+ for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, mloopcol++) {
+ vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
+ vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
+ vcol->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
+ vcol->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
+ }
+
+ /* Ensure data is uploaded properly. */
+ GPU_vertbuf_tag_dirty(src_data);
+ draw_subdiv_interp_custom_data(subdiv_cache, src_data, dst_buffer, 4, dst_offset);
+ }
+ }
+
+ GPU_vertbuf_discard(src_data);
+}
+
constexpr MeshExtract create_extractor_vcol()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_vcol_init;
+ extractor.init_subdiv = extract_vcol_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
index bdb1410a755..bb8853b8154 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
@@ -25,6 +25,7 @@
#include "BKE_deform.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -167,10 +168,57 @@ static void extract_weights_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static void extract_weights_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *coarse_weights = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(coarse_weights, &format);
+ GPU_vertbuf_data_alloc(coarse_weights, coarse_mesh->totloop);
+ float *coarse_weights_data = static_cast<float *>(GPU_vertbuf_get_data(coarse_weights));
+
+ const DRW_MeshWeightState *wstate = &cache->weight_state;
+ const MDeformVert *dverts = static_cast<const MDeformVert *>(
+ CustomData_get_layer(&coarse_mesh->vdata, CD_MDEFORMVERT));
+
+ for (int i = 0; i < coarse_mesh->totpoly; i++) {
+ const MPoly *mpoly = &coarse_mesh->mpoly[i];
+
+ for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop;
+ loop_index++) {
+ const MLoop *ml = &coarse_mesh->mloop[loop_index];
+
+ if (dverts != nullptr) {
+ const MDeformVert *dvert = &dverts[ml->v];
+ coarse_weights_data[loop_index] = evaluate_vertex_weight(dvert, wstate);
+ }
+ else {
+ coarse_weights_data[loop_index] = evaluate_vertex_weight(nullptr, wstate);
+ }
+ }
+ }
+
+ draw_subdiv_interp_custom_data(subdiv_cache, coarse_weights, vbo, 1, 0);
+
+ GPU_vertbuf_discard(coarse_weights);
+}
+
constexpr MeshExtract create_extractor_weights()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_weights_init;
+ extractor.init_subdiv = extract_weights_init_subdiv;
extractor.iter_poly_bm = extract_weights_iter_poly_bm;
extractor.iter_poly_mesh = extract_weights_iter_poly_mesh;
extractor.data_type = MR_DATA_NONE;
diff --git a/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl
index 8a7fb97d98c..53ec38fea0b 100644
--- a/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl
+++ b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl
@@ -1,5 +1,7 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
out vec4 uvcoordsvar;
+#endif
void main()
{
diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index 6cc7f09a852..ed8b8aeb849 100644
--- a/source/blender/draw/intern/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
@@ -5,6 +5,9 @@
* of data the CPU has to precompute and transfer for each update.
*/
+/* TODO(fclem): Keep documentation but remove the uniform declaration. */
+#ifndef USE_GPU_SHADER_CREATE_INFO
+
/**
* hairStrandsRes: Number of points per hair strand.
* 2 - no subdivision
@@ -33,8 +36,6 @@ uniform int hairStrandOffset = 0;
/* -- Per control points -- */
uniform samplerBuffer hairPointBuffer; /* RGBA32F */
-#define point_position xyz
-#define point_time w /* Position along the hair length */
/* -- Per strands data -- */
uniform usamplerBuffer hairStrandBuffer; /* R32UI */
@@ -43,6 +44,10 @@ uniform usamplerBuffer hairStrandSegBuffer; /* R16UI */
/* Not used, use one buffer per uv layer */
// uniform samplerBuffer hairUVBuffer; /* RG32F */
// uniform samplerBuffer hairColBuffer; /* RGBA16 linear color */
+#endif
+
+#define point_position xyz
+#define point_time w /* Position along the hair length */
/* -- Subdivision stage -- */
/**
diff --git a/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl b/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl
index 4dcde4b0245..6a3a7815cdc 100644
--- a/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl
@@ -1,4 +1,6 @@
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#ifndef USE_GPU_SHADER_CREATE_INFO
/*
* To be compiled with common_hair_lib.glsl.
*/
@@ -9,6 +11,7 @@ layout(std430, binding = 0) writeonly buffer hairPointOutputBuffer
vec4 posTime[];
}
out_vertbuf;
+#endif
void main(void)
{
@@ -20,5 +23,5 @@ void main(void)
vec4 result = hair_interp_data(data0, data1, data2, data3, weights);
uint index = uint(hair_get_id() * hairStrandsRes) + gl_GlobalInvocationID.y;
- out_vertbuf.posTime[index] = result;
+ posTime[index] = result;
}
diff --git a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl
index 74b989441a2..dd725ad327f 100644
--- a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl
@@ -2,6 +2,8 @@
/* NOTE: To be used with UNIFORM_RESOURCE_ID and INSTANCED_ATTR as define. */
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#ifndef DRW_SHADER_SHARED_H
+
in vec4 pos; /* Position and radius. */
/* ---- Instanced attribs ---- */
@@ -9,6 +11,8 @@ in vec4 pos; /* Position and radius. */
in vec3 pos_inst;
in vec3 nor;
+#endif
+
mat3 pointcloud_get_facing_matrix(vec3 p)
{
mat3 facing_mat;
@@ -18,13 +22,22 @@ mat3 pointcloud_get_facing_matrix(vec3 p)
return facing_mat;
}
+/* Returns world center position and radius. */
+void pointcloud_get_pos_and_radius(out vec3 outpos, out float outradius)
+{
+ outpos = point_object_to_world(pos.xyz);
+ outradius = dot(abs(mat3(ModelMatrix) * pos.www), vec3(1.0 / 3.0));
+}
+
/* Return world position and normal. */
void pointcloud_get_pos_and_nor(out vec3 outpos, out vec3 outnor)
{
- vec3 p = point_object_to_world(pos.xyz);
+ vec3 p;
+ float radius;
+ pointcloud_get_pos_and_radius(p, radius);
+
mat3 facing_mat = pointcloud_get_facing_matrix(p);
- float radius = dot(abs(mat3(ModelMatrix) * pos.www), vec3(1.0 / 3.0));
/* TODO(fclem): remove multiplication here. Here only for keeping the size correct for now. */
radius *= 0.01;
outpos = p + (facing_mat * pos_inst) * radius;
diff --git a/source/blender/draw/intern/shaders/common_smaa_lib.glsl b/source/blender/draw/intern/shaders/common_smaa_lib.glsl
index 36ffb4d8b32..73f65fb0799 100644
--- a/source/blender/draw/intern/shaders/common_smaa_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_smaa_lib.glsl
@@ -736,9 +736,11 @@ float2 SMAALumaEdgeDetectionPS(float2 texcoord,
float2 edges = step(threshold, delta.xy);
# ifndef SMAA_NO_DISCARD
+# ifdef GPU_FRAGMENT_SHADER
// Then discard if there is no edge:
if (dot(edges, float2(1.0, 1.0)) == 0.0)
discard;
+# endif
# endif
// Calculate right and bottom deltas:
@@ -804,9 +806,11 @@ float2 SMAAColorEdgeDetectionPS(float2 texcoord,
float2 edges = step(threshold, delta.xy);
# ifndef SMAA_NO_DISCARD
+# ifdef GPU_FRAGMENT_SHADER
// Then discard if there is no edge:
if (dot(edges, float2(1.0, 1.0)) == 0.0)
discard;
+# endif
# endif
// Calculate right and bottom deltas:
@@ -851,8 +855,10 @@ float2 SMAADepthEdgeDetectionPS(float2 texcoord, float4 offset[3], SMAATexture2D
float2 delta = abs(neighbours.xx - float2(neighbours.y, neighbours.z));
float2 edges = step(SMAA_DEPTH_THRESHOLD, delta);
+# ifdef GPU_FRAGMENT_SHADER
if (dot(edges, float2(1.0, 1.0)) == 0.0)
discard;
+# endif
return edges;
}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl
new file mode 100644
index 00000000000..36c3970d9a0
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl
@@ -0,0 +1,230 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 1) readonly restrict buffer sourceBuffer
+{
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint src_data[];
+#else
+ float src_data[];
+#endif
+};
+
+layout(std430, binding = 2) readonly restrict buffer facePTexOffset
+{
+ uint face_ptex_offset[];
+};
+
+layout(std430, binding = 3) readonly restrict buffer patchCoords
+{
+ BlenderPatchCoord patch_coords[];
+};
+
+layout(std430, binding = 4) readonly restrict buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+
+layout(std430, binding = 5) writeonly restrict buffer destBuffer
+{
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint dst_data[];
+#else
+ float dst_data[];
+#endif
+};
+
+struct Vertex {
+ float vertex_data[DIMENSIONS];
+};
+
+void clear(inout Vertex v)
+{
+ for (int i = 0; i < DIMENSIONS; i++) {
+ v.vertex_data[i] = 0.0;
+ }
+}
+
+Vertex read_vertex(uint index)
+{
+ Vertex result;
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint base_index = index * 2;
+ if (DIMENSIONS == 4) {
+ uint xy = src_data[base_index];
+ uint zw = src_data[base_index + 1];
+
+ float x = float((xy >> 16) & 0xffff) / 65535.0;
+ float y = float(xy & 0xffff) / 65535.0;
+ float z = float((zw >> 16) & 0xffff) / 65535.0;
+ float w = float(zw & 0xffff) / 65535.0;
+
+ result.vertex_data[0] = x;
+ result.vertex_data[1] = y;
+ result.vertex_data[2] = z;
+ result.vertex_data[3] = w;
+ }
+ else {
+ /* This case is unsupported for now. */
+ clear(result);
+ }
+#else
+ uint base_index = index * DIMENSIONS;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ result.vertex_data[i] = src_data[base_index + i];
+ }
+#endif
+ return result;
+}
+
+void write_vertex(uint index, Vertex v)
+{
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint base_index = dst_offset + index * 2;
+ if (DIMENSIONS == 4) {
+ uint x = uint(v.vertex_data[0] * 65535.0);
+ uint y = uint(v.vertex_data[1] * 65535.0);
+ uint z = uint(v.vertex_data[2] * 65535.0);
+ uint w = uint(v.vertex_data[3] * 65535.0);
+
+ uint xy = x << 16 | y;
+ uint zw = z << 16 | w;
+
+ dst_data[base_index] = xy;
+ dst_data[base_index + 1] = zw;
+ }
+ else {
+ /* This case is unsupported for now. */
+ dst_data[base_index] = 0;
+ }
+#else
+ uint base_index = dst_offset + index * DIMENSIONS;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ dst_data[base_index + i] = v.vertex_data[i];
+ }
+#endif
+}
+
+Vertex interp_vertex(Vertex v0, Vertex v1, Vertex v2, Vertex v3, vec2 uv)
+{
+ Vertex result;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ float e = mix(v0.vertex_data[i], v1.vertex_data[i], uv.x);
+ float f = mix(v2.vertex_data[i], v3.vertex_data[i], uv.x);
+ result.vertex_data[i] = mix(e, f, uv.y);
+ }
+ return result;
+}
+
+void add_with_weight(inout Vertex v0, Vertex v1, float weight)
+{
+ for (int i = 0; i < DIMENSIONS; i++) {
+ v0.vertex_data[i] += v1.vertex_data[i] * weight;
+ }
+}
+
+Vertex average(Vertex v0, Vertex v1)
+{
+ Vertex result;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ result.vertex_data[i] = (v0.vertex_data[i] + v1.vertex_data[i]) * 0.5;
+ }
+ return result;
+}
+
+uint get_vertex_count(uint coarse_polygon)
+{
+ uint number_of_patches = face_ptex_offset[coarse_polygon + 1] - face_ptex_offset[coarse_polygon];
+ if (number_of_patches == 1) {
+ /* If there is only one patch for the current coarse polygon, then it is a quad. */
+ return 4;
+ }
+ /* Otherwise, the number of patches is the number of vertices. */
+ return number_of_patches;
+}
+
+uint get_polygon_corner_index(uint coarse_polygon, uint patch_index)
+{
+ uint patch_offset = face_ptex_offset[coarse_polygon];
+ return patch_index - patch_offset;
+}
+
+uint get_loop_start(uint coarse_polygon)
+{
+ return extra_coarse_face_data[coarse_polygon] & coarse_face_loopstart_mask;
+}
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ /* Find which coarse polygon we came from. */
+ uint coarse_polygon = coarse_polygon_index_from_subdiv_quad_index(quad_index, coarse_poly_count);
+ uint loop_start = get_loop_start(coarse_polygon);
+
+ /* Find the number of vertices for the coarse polygon. */
+ Vertex v0, v1, v2, v3;
+ clear(v0);
+ clear(v1);
+ clear(v2);
+ clear(v3);
+
+ uint number_of_vertices = get_vertex_count(coarse_polygon);
+ if (number_of_vertices == 4) {
+ /* Interpolate the src data. */
+ v0 = read_vertex(loop_start + 0);
+ v1 = read_vertex(loop_start + 1);
+ v2 = read_vertex(loop_start + 2);
+ v3 = read_vertex(loop_start + 3);
+ }
+ else {
+ /* Interpolate the src data for the center. */
+ uint loop_end = loop_start + number_of_vertices - 1;
+ Vertex center_value;
+ clear(center_value);
+
+ float weight = 1.0 / float(number_of_vertices);
+
+ for (uint l = loop_start; l < loop_end; l++) {
+ add_with_weight(center_value, read_vertex(l), weight);
+ }
+
+ /* Interpolate between the previous and next corner for the middle values for the edges. */
+ uint patch_index = uint(patch_coords[start_loop_index].patch_index);
+ uint current_coarse_corner = get_polygon_corner_index(coarse_polygon, patch_index);
+ uint next_coarse_corner = (current_coarse_corner + 1) % number_of_vertices;
+ uint prev_coarse_corner = (current_coarse_corner + number_of_vertices - 1) %
+ number_of_vertices;
+
+ v0 = read_vertex(loop_start);
+ v1 = average(v0, read_vertex(loop_start + next_coarse_corner));
+ v3 = average(v0, read_vertex(loop_start + prev_coarse_corner));
+
+ /* Interpolate between the current value, and the ones for the center and mid-edges. */
+ v2 = center_value;
+ }
+
+ /* Do a linear interpolation of the data based on the UVs for each loop of this subdivided quad.
+ */
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ BlenderPatchCoord co = patch_coords[loop_index];
+ vec2 uv = decode_uv(co.encoded_uv);
+ /* NOTE: v2 and v3 are reversed to stay consistent with the interpolation weight on the x-axis:
+ *
+ * v3 +-----+ v2
+ * | |
+ * | |
+ * v0 +-----+ v1
+ *
+ * otherwise, weight would be `1.0 - uv.x` for `v2 <-> v3`, but `uv.x` for `v0 <-> v1`.
+ */
+ Vertex result = interp_vertex(v0, v1, v3, v2, uv);
+ write_vertex(loop_index, result);
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
new file mode 100644
index 00000000000..f11c0f6427e
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
@@ -0,0 +1,57 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputEdgeOrigIndex
+{
+ int input_origindex[];
+};
+
+layout(std430, binding = 1) writeonly buffer outputLinesIndices
+{
+ uint output_lines[];
+};
+
+#ifndef LINES_LOOSE
+void emit_line(uint line_offset, uint start_loop_index, uint corner_index)
+{
+ uint vertex_index = start_loop_index + corner_index;
+
+ if (input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display) {
+ output_lines[line_offset + 0] = 0xffffffff;
+ output_lines[line_offset + 1] = 0xffffffff;
+ }
+ else {
+ /* Mod 4 so we loop back at the first vertex on the last loop index (3). */
+ uint next_vertex_index = start_loop_index + (corner_index + 1) % 4;
+
+ output_lines[line_offset + 0] = vertex_index;
+ output_lines[line_offset + 1] = next_vertex_index;
+ }
+}
+#endif
+
+void main()
+{
+ uint index = get_global_invocation_index();
+ if (index >= total_dispatch_size) {
+ return;
+ }
+
+#ifdef LINES_LOOSE
+ /* In the loose lines case, we execute for each line, with two vertices per line. */
+ uint line_offset = edge_loose_offset + index * 2;
+ uint loop_index = num_subdiv_loops + index * 2;
+ output_lines[line_offset] = loop_index;
+ output_lines[line_offset + 1] = loop_index + 1;
+#else
+ /* We execute for each quad, so the start index of the loop is quad_index * 4. */
+ uint start_loop_index = index * 4;
+ /* We execute for each quad, so the start index of the line is quad_index * 8 (with 2 vertices
+ * per line). */
+ uint start_line_index = index * 8;
+
+ for (int i = 0; i < 4; i++) {
+ emit_line(start_line_index + i * 2, start_loop_index, i);
+ }
+#endif
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
new file mode 100644
index 00000000000..3257ebdae17
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
@@ -0,0 +1,43 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+/* Generate triangles from subdivision quads indices. */
+
+layout(std430, binding = 1) writeonly buffer outputTriangles
+{
+ uint output_tris[];
+};
+
+#ifndef SINGLE_MATERIAL
+layout(std430, binding = 2) readonly buffer inputPolygonMatOffset
+{
+ int polygon_mat_offset[];
+};
+#endif
+
+void main()
+{
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint loop_index = quad_index * 4;
+
+#ifdef SINGLE_MATERIAL
+ uint triangle_loop_index = quad_index * 6;
+#else
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+ int mat_offset = polygon_mat_offset[coarse_quad_index];
+
+ int triangle_loop_index = (int(quad_index) + mat_offset) * 6;
+#endif
+
+ output_tris[triangle_loop_index + 0] = loop_index + 0;
+ output_tris[triangle_loop_index + 1] = loop_index + 1;
+ output_tris[triangle_loop_index + 2] = loop_index + 2;
+ output_tris[triangle_loop_index + 3] = loop_index + 0;
+ output_tris[triangle_loop_index + 4] = loop_index + 2;
+ output_tris[triangle_loop_index + 5] = loop_index + 3;
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
new file mode 100644
index 00000000000..9dd86c35ee4
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
@@ -0,0 +1,176 @@
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+/* Uniform block for #DRWSubivUboStorage. */
+layout(std140) uniform shader_data
+{
+ /* Offsets in the buffers data where the source and destination data start. */
+ int src_offset;
+ int dst_offset;
+
+ /* Parameters for the DRWPatchMap. */
+ int min_patch_face;
+ int max_patch_face;
+ int max_depth;
+ int patches_are_triangular;
+
+ /* Coarse topology information. */
+ int coarse_poly_count;
+ uint edge_loose_offset;
+
+ /* Subdiv topology information. */
+ uint num_subdiv_loops;
+
+ /* Subdivision settings. */
+ bool optimal_display;
+
+ /* Sculpt data. */
+ bool has_sculpt_mask;
+
+ /* Masks for the extra coarse face data. */
+ uint coarse_face_select_mask;
+ uint coarse_face_smooth_mask;
+ uint coarse_face_active_mask;
+ uint coarse_face_loopstart_mask;
+
+ /* Total number of elements to process. */
+ uint total_dispatch_size;
+};
+
+uint get_global_invocation_index()
+{
+ uint invocations_per_row = gl_WorkGroupSize.x * gl_NumWorkGroups.x;
+ return gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * invocations_per_row;
+}
+
+/* Structure for #CompressedPatchCoord. */
+struct BlenderPatchCoord {
+ int patch_index;
+ uint encoded_uv;
+};
+
+vec2 decode_uv(uint encoded_uv)
+{
+ float u = float((encoded_uv >> 16) & 0xFFFFu) / 65535.0;
+ float v = float(encoded_uv & 0xFFFFu) / 65535.0;
+ return vec2(u, v);
+}
+
+/* This structure is a carbon copy of OpenSubDiv's PatchTable::PatchHandle. */
+struct PatchHandle {
+ int array_index;
+ int patch_index;
+ int vertex_index;
+};
+
+/* This structure is a carbon copy of OpenSubDiv's PatchCoord. */
+struct PatchCoord {
+ int array_index;
+ int patch_index;
+ int vertex_index;
+ float u;
+ float v;
+};
+
+/* This structure is a carbon copy of OpenSubDiv's PatchCoord.QuadNode.
+ * Each child is a bitfield. */
+struct QuadNode {
+ uvec4 child;
+};
+
+bool is_set(uint i)
+{
+ /* QuadNode.Child.isSet is the first bit of the bitfield. */
+ return (i & 0x1u) != 0;
+}
+
+bool is_leaf(uint i)
+{
+ /* QuadNode.Child.isLeaf is the second bit of the bitfield. */
+ return (i & 0x2u) != 0;
+}
+
+uint get_index(uint i)
+{
+ /* QuadNode.Child.index is made of the remaining bits. */
+ return (i >> 2) & 0x3FFFFFFFu;
+}
+
+/* Duplicate of #PosNorLoop from the mesh extract CPU code.
+ * We do not use a vec3 for the position as it will be padded to a vec4 which is incompatible with
+ * the format. */
+struct PosNorLoop {
+ float x, y, z;
+ /* TODO(kevindietrich) : figure how to compress properly as GLSL does not have char/short types,
+ * bit operations get tricky. */
+ float nx, ny, nz;
+ float flag;
+};
+
+vec3 get_vertex_pos(PosNorLoop vertex_data)
+{
+ return vec3(vertex_data.x, vertex_data.y, vertex_data.z);
+}
+
+vec3 get_vertex_nor(PosNorLoop vertex_data)
+{
+ return vec3(vertex_data.nx, vertex_data.ny, vertex_data.nz);
+}
+
+void set_vertex_pos(inout PosNorLoop vertex_data, vec3 pos)
+{
+ vertex_data.x = pos.x;
+ vertex_data.y = pos.y;
+ vertex_data.z = pos.z;
+}
+
+void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, uint flag)
+{
+ vertex_data.nx = nor.x;
+ vertex_data.ny = nor.y;
+ vertex_data.nz = nor.z;
+ vertex_data.flag = float(flag);
+}
+
+/* Set the vertex normal but preserve the existing flag. This is for when we compute manually the
+ * vertex normals when we cannot use the limit surface, in which case the flag and the normal are
+ * set by two separate compute pass. */
+void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor)
+{
+ set_vertex_nor(vertex_data, nor, 0);
+}
+
+#define ORIGINDEX_NONE -1
+
+#ifdef SUBDIV_POLYGON_OFFSET
+layout(std430, binding = 0) readonly buffer inputSubdivPolygonOffset
+{
+ uint subdiv_polygon_offset[];
+};
+
+/* Given the index of the subdivision quad, return the index of the corresponding coarse polygon.
+ * This uses subdiv_polygon_offset and since it is a growing list of offsets, we can use binary
+ * search to locate the right index. */
+uint coarse_polygon_index_from_subdiv_quad_index(uint subdiv_quad_index, uint coarse_poly_count)
+{
+ uint first = 0;
+ uint last = coarse_poly_count;
+
+ while (first != last) {
+ uint middle = (first + last) / 2;
+
+ if (subdiv_polygon_offset[middle] < subdiv_quad_index) {
+ first = middle + 1;
+ }
+ else {
+ last = middle;
+ }
+ }
+
+ if (subdiv_polygon_offset[first] == subdiv_quad_index) {
+ return first;
+ }
+
+ return first - 1;
+}
+#endif
diff --git a/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl
new file mode 100644
index 00000000000..575090472b1
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl
@@ -0,0 +1,56 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputVertexData
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 1) readonly buffer faceAdjacencyOffsets
+{
+ uint face_adjacency_offsets[];
+};
+
+layout(std430, binding = 2) readonly buffer faceAdjacencyLists
+{
+ uint face_adjacency_lists[];
+};
+
+layout(std430, binding = 3) writeonly buffer vertexNormals
+{
+ vec3 normals[];
+};
+
+void main()
+{
+ uint vertex_index = get_global_invocation_index();
+ if (vertex_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint first_adjacent_face_offset = face_adjacency_offsets[vertex_index];
+ uint number_of_adjacent_faces = face_adjacency_offsets[vertex_index + 1] -
+ first_adjacent_face_offset;
+
+ vec3 accumulated_normal = vec3(0.0);
+
+ /* For each adjacent face. */
+ for (uint i = 0; i < number_of_adjacent_faces; i++) {
+ uint adjacent_face = face_adjacency_lists[first_adjacent_face_offset + i];
+ uint start_loop_index = adjacent_face * 4;
+
+ /* Compute face normal. */
+ vec3 adjacent_verts[3];
+ for (uint j = 0; j < 3; j++) {
+ adjacent_verts[j] = get_vertex_pos(pos_nor[start_loop_index + j]);
+ }
+
+ vec3 face_normal = normalize(
+ cross(adjacent_verts[1] - adjacent_verts[0], adjacent_verts[2] - adjacent_verts[0]));
+ accumulated_normal += face_normal;
+ }
+
+ float weight = 1.0 / float(number_of_adjacent_faces);
+ vec3 normal = normalize(accumulated_normal);
+ normals[vertex_index] = normal;
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl
new file mode 100644
index 00000000000..84cd65d4161
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl
@@ -0,0 +1,34 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputNormals
+{
+ vec3 vertex_normals[];
+};
+
+layout(std430, binding = 1) readonly buffer inputSubdivVertLoopMap
+{
+ uint vert_loop_map[];
+};
+
+layout(std430, binding = 2) buffer outputPosNor
+{
+ PosNorLoop pos_nor[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (int i = 0; i < 4; i++) {
+ uint subdiv_vert_index = vert_loop_map[start_loop_index + i];
+ vec3 nor = vertex_normals[subdiv_vert_index];
+ set_vertex_nor(pos_nor[start_loop_index + i], nor);
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
new file mode 100644
index 00000000000..5dd7decf663
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
@@ -0,0 +1,416 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+/* Source buffer. */
+layout(std430, binding = 0) buffer src_buffer
+{
+ float srcVertexBuffer[];
+};
+
+/* #DRWPatchMap */
+layout(std430, binding = 1) readonly buffer inputPatchHandles
+{
+ PatchHandle input_patch_handles[];
+};
+
+layout(std430, binding = 2) readonly buffer inputQuadNodes
+{
+ QuadNode quad_nodes[];
+};
+
+layout(std430, binding = 3) readonly buffer inputPatchCoords
+{
+ BlenderPatchCoord patch_coords[];
+};
+
+layout(std430, binding = 4) readonly buffer inputVertOrigIndices
+{
+ int input_vert_origindex[];
+};
+
+/* Patch buffers. */
+layout(std430, binding = 5) buffer patchArray_buffer
+{
+ OsdPatchArray patchArrayBuffer[];
+};
+
+layout(std430, binding = 6) buffer patchIndex_buffer
+{
+ int patchIndexBuffer[];
+};
+
+layout(std430, binding = 7) buffer patchParam_buffer
+{
+ OsdPatchParam patchParamBuffer[];
+};
+
+ /* Output buffer(s). */
+
+#if defined(FVAR_EVALUATION)
+layout(std430, binding = 8) writeonly buffer outputFVarData
+{
+ vec2 output_fvar[];
+};
+#elif defined(FDOTS_EVALUATION)
+/* For face dots, we build the position, normals, and index buffers in one go. */
+
+/* vec3 is padded to vec4, but the format used for fdots does not have any padding. */
+struct FDotVert {
+ float x, y, z;
+};
+
+/* Same here, do not use vec3. */
+struct FDotNor {
+ float x, y, z;
+ float flag;
+};
+
+layout(std430, binding = 8) writeonly buffer outputVertices
+{
+ FDotVert output_verts[];
+};
+
+layout(std430, binding = 9) writeonly buffer outputNormals
+{
+ FDotNor output_nors[];
+};
+
+layout(std430, binding = 10) writeonly buffer outputFdotsIndices
+{
+ uint output_indices[];
+};
+
+layout(std430, binding = 11) readonly buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+#else
+layout(std430, binding = 8) writeonly buffer outputVertexData
+{
+ PosNorLoop output_verts[];
+};
+#endif
+
+vec2 read_vec2(int index)
+{
+ vec2 result;
+ result.x = srcVertexBuffer[index * 2];
+ result.y = srcVertexBuffer[index * 2 + 1];
+ return result;
+}
+
+vec3 read_vec3(int index)
+{
+ vec3 result;
+ result.x = srcVertexBuffer[index * 3];
+ result.y = srcVertexBuffer[index * 3 + 1];
+ result.z = srcVertexBuffer[index * 3 + 2];
+ return result;
+}
+
+OsdPatchArray GetPatchArray(int arrayIndex)
+{
+ return patchArrayBuffer[arrayIndex];
+}
+
+OsdPatchParam GetPatchParam(int patchIndex)
+{
+ return patchParamBuffer[patchIndex];
+}
+
+/* ------------------------------------------------------------------------------
+ * Patch Coordinate lookup. Return an OsdPatchCoord for the given patch_index and uvs.
+ * This code is a port of the OpenSubdiv PatchMap lookup code.
+ */
+
+PatchHandle bogus_patch_handle()
+{
+ PatchHandle ret;
+ ret.array_index = -1;
+ ret.vertex_index = -1;
+ ret.patch_index = -1;
+ return ret;
+}
+
+int transformUVToQuadQuadrant(float median, inout float u, inout float v)
+{
+ int uHalf = (u >= median) ? 1 : 0;
+ if (uHalf != 0)
+ u -= median;
+
+ int vHalf = (v >= median) ? 1 : 0;
+ if (vHalf != 0)
+ v -= median;
+
+ return (vHalf << 1) | uHalf;
+}
+
+int transformUVToTriQuadrant(float median, inout float u, inout float v, inout bool rotated)
+{
+
+ if (!rotated) {
+ if (u >= median) {
+ u -= median;
+ return 1;
+ }
+ if (v >= median) {
+ v -= median;
+ return 2;
+ }
+ if ((u + v) >= median) {
+ rotated = true;
+ return 3;
+ }
+ return 0;
+ }
+ else {
+ if (u < median) {
+ v -= median;
+ return 1;
+ }
+ if (v < median) {
+ u -= median;
+ return 2;
+ }
+ u -= median;
+ v -= median;
+ if ((u + v) < median) {
+ rotated = false;
+ return 3;
+ }
+ return 0;
+ }
+}
+
+PatchHandle find_patch(int face_index, float u, float v)
+{
+ if (face_index < min_patch_face || face_index > max_patch_face) {
+ return bogus_patch_handle();
+ }
+
+ QuadNode node = quad_nodes[face_index - min_patch_face];
+
+ if (!is_set(node.child[0])) {
+ return bogus_patch_handle();
+ }
+
+ float median = 0.5;
+ bool tri_rotated = false;
+
+ for (int depth = 0; depth <= max_depth; ++depth, median *= 0.5) {
+ int quadrant = (patches_are_triangular != 0) ?
+ transformUVToTriQuadrant(median, u, v, tri_rotated) :
+ transformUVToQuadQuadrant(median, u, v);
+
+ if (is_leaf(node.child[quadrant])) {
+ return input_patch_handles[get_index(node.child[quadrant])];
+ }
+
+ node = quad_nodes[get_index(node.child[quadrant])];
+ }
+}
+
+OsdPatchCoord bogus_patch_coord(int face_index, float u, float v)
+{
+ OsdPatchCoord coord;
+ coord.arrayIndex = 0;
+ coord.patchIndex = face_index;
+ coord.vertIndex = 0;
+ coord.s = u;
+ coord.t = v;
+ return coord;
+}
+
+OsdPatchCoord GetPatchCoord(int face_index, float u, float v)
+{
+ PatchHandle patch_handle = find_patch(face_index, u, v);
+
+ if (patch_handle.array_index == -1) {
+ return bogus_patch_coord(face_index, u, v);
+ }
+
+ OsdPatchCoord coord;
+ coord.arrayIndex = patch_handle.array_index;
+ coord.patchIndex = patch_handle.patch_index;
+ coord.vertIndex = patch_handle.vertex_index;
+ coord.s = u;
+ coord.t = v;
+ return coord;
+}
+
+/* ------------------------------------------------------------------------------
+ * Patch evaluation. Note that the 1st and 2nd derivatives are always computed, although we
+ * only return and use the 1st derivatives if adaptive patches are used. This could
+ * perhaps be optimized.
+ */
+
+#if defined(FVAR_EVALUATION)
+void evaluate_patches_limits(int patch_index, float u, float v, inout vec2 dst)
+{
+ OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
+ OsdPatchArray array = GetPatchArray(coord.arrayIndex);
+ OsdPatchParam param = GetPatchParam(coord.patchIndex);
+
+ int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
+
+ float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
+ int nPoints = OsdEvaluatePatchBasis(
+ patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
+
+ int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
+
+ for (int cv = 0; cv < nPoints; ++cv) {
+ int index = patchIndexBuffer[indexBase + cv];
+ vec2 src_fvar = read_vec2(src_offset + index);
+ dst += src_fvar * wP[cv];
+ }
+}
+#else
+void evaluate_patches_limits(
+ int patch_index, float u, float v, inout vec3 dst, inout vec3 du, inout vec3 dv)
+{
+ OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
+ OsdPatchArray array = GetPatchArray(coord.arrayIndex);
+ OsdPatchParam param = GetPatchParam(coord.patchIndex);
+
+ int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
+
+ float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
+ int nPoints = OsdEvaluatePatchBasis(
+ patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
+
+ int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
+
+ for (int cv = 0; cv < nPoints; ++cv) {
+ int index = patchIndexBuffer[indexBase + cv];
+ vec3 src_vertex = read_vec3(index);
+
+ dst += src_vertex * wP[cv];
+ du += src_vertex * wDu[cv];
+ dv += src_vertex * wDv[cv];
+ }
+}
+#endif
+
+/* ------------------------------------------------------------------------------
+ * Entry point.
+ */
+
+#if defined(FVAR_EVALUATION)
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ vec2 fvar = vec2(0.0);
+
+ BlenderPatchCoord patch_co = patch_coords[loop_index];
+ vec2 uv = decode_uv(patch_co.encoded_uv);
+
+ evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, fvar);
+ output_fvar[dst_offset + loop_index] = fvar;
+ }
+}
+#elif defined(FDOTS_EVALUATION)
+bool is_face_selected(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_select_mask) != 0;
+}
+
+bool is_face_active(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_active_mask) != 0;
+}
+
+float get_face_flag(uint coarse_quad_index)
+{
+ if (is_face_active(coarse_quad_index)) {
+ return -1.0;
+ }
+
+ if (is_face_selected(coarse_quad_index)) {
+ return 1.0;
+ }
+
+ return 0.0;
+}
+
+void main()
+{
+ /* We execute for each coarse quad. */
+ uint coarse_quad_index = get_global_invocation_index();
+ if (coarse_quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ BlenderPatchCoord patch_co = patch_coords[coarse_quad_index];
+ vec2 uv = decode_uv(patch_co.encoded_uv);
+
+ vec3 pos = vec3(0.0);
+ vec3 du = vec3(0.0);
+ vec3 dv = vec3(0.0);
+ evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv);
+ vec3 nor = normalize(cross(du, dv));
+
+ FDotVert vert;
+ vert.x = pos.x;
+ vert.y = pos.y;
+ vert.z = pos.z;
+
+ FDotNor fnor;
+ fnor.x = nor.x;
+ fnor.y = nor.y;
+ fnor.z = nor.z;
+ fnor.flag = get_face_flag(coarse_quad_index);
+
+ output_verts[coarse_quad_index] = vert;
+ output_nors[coarse_quad_index] = fnor;
+ output_indices[coarse_quad_index] = coarse_quad_index;
+}
+#else
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ vec3 pos = vec3(0.0);
+ vec3 du = vec3(0.0);
+ vec3 dv = vec3(0.0);
+
+ BlenderPatchCoord patch_co = patch_coords[loop_index];
+ vec2 uv = decode_uv(patch_co.encoded_uv);
+
+ evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv);
+
+# if defined(LIMIT_NORMALS)
+ vec3 nor = normalize(cross(du, dv));
+# else
+ /* This will be computed later. */
+ vec3 nor = vec3(0.0);
+# endif
+
+ int origindex = input_vert_origindex[loop_index];
+ uint flag = 0;
+ if (origindex == -1) {
+ flag = -1;
+ }
+
+ PosNorLoop vertex_data;
+ set_vertex_pos(vertex_data, pos);
+ set_vertex_nor(vertex_data, nor, flag);
+ output_verts[loop_index] = vertex_data;
+ }
+}
+#endif
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl
new file mode 100644
index 00000000000..6c76cd41ca4
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl
@@ -0,0 +1,97 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputVertexData
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 1) readonly buffer inputEdgeIndex
+{
+ uint input_edge_index[];
+};
+
+layout(std430, binding = 2) writeonly buffer outputEdgeFactors
+{
+#ifdef GPU_AMD_DRIVER_BYTE_BUG
+ float output_edge_fac[];
+#else
+ uint output_edge_fac[];
+#endif
+};
+
+void write_vec4(uint index, vec4 edge_facs)
+{
+#ifdef GPU_AMD_DRIVER_BYTE_BUG
+ for (uint i = 0; i < 4; i++) {
+ output_edge_fac[index + i] = edge_facs[i];
+ }
+#else
+ /* Use same scaling as in extract_edge_fac_iter_poly_mesh. */
+ uint a = uint(clamp(edge_facs.x * 253.0 + 1.0, 0.0, 255.0));
+ uint b = uint(clamp(edge_facs.y * 253.0 + 1.0, 0.0, 255.0));
+ uint c = uint(clamp(edge_facs.z * 253.0 + 1.0, 0.0, 255.0));
+ uint d = uint(clamp(edge_facs.w * 253.0 + 1.0, 0.0, 255.0));
+ uint packed_edge_fac = a << 24 | b << 16 | c << 8 | d;
+ output_edge_fac[index] = packed_edge_fac;
+#endif
+}
+
+/* From extract_mesh_vbo_edge_fac.cc, keep in sync! */
+float loop_edge_factor_get(vec3 f_no, vec3 v_co, vec3 v_no, vec3 v_next_co)
+{
+ vec3 evec = v_next_co - v_co;
+ vec3 enor = normalize(cross(v_no, evec));
+ float d = abs(dot(enor, f_no));
+ /* Re-scale to the slider range. */
+ d *= (1.0 / 0.065);
+ return clamp(d, 0.0, 1.0);
+}
+
+float compute_line_factor(uint start_loop_index, uint corner_index, vec3 face_normal)
+{
+ uint vertex_index = start_loop_index + corner_index;
+ uint edge_index = input_edge_index[vertex_index];
+
+ if (edge_index == -1 && optimal_display) {
+ return 0.0;
+ }
+
+ /* Mod 4 so we loop back at the first vertex on the last loop index (3), but only the corner
+ * index needs to be wrapped. */
+ uint next_vertex_index = start_loop_index + (corner_index + 1) % 4;
+ vec3 vertex_pos = get_vertex_pos(pos_nor[vertex_index]);
+ vec3 vertex_nor = get_vertex_nor(pos_nor[vertex_index]);
+ vec3 next_vertex_pos = get_vertex_pos(pos_nor[next_vertex_index]);
+ return loop_edge_factor_get(face_normal, vertex_pos, vertex_nor, next_vertex_pos);
+}
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ /* The start index of the loop is quad_index * 4. */
+ uint start_loop_index = quad_index * 4;
+
+ /* First compute the face normal, we need it to compute the bihedral edge angle. */
+ vec3 v0 = get_vertex_pos(pos_nor[start_loop_index + 0]);
+ vec3 v1 = get_vertex_pos(pos_nor[start_loop_index + 1]);
+ vec3 v2 = get_vertex_pos(pos_nor[start_loop_index + 2]);
+ vec3 face_normal = normalize(cross(v1 - v0, v2 - v0));
+
+ vec4 edge_facs = vec4(0.0);
+ for (int i = 0; i < 4; i++) {
+ edge_facs[i] = compute_line_factor(start_loop_index, i, face_normal);
+ }
+
+#ifdef GPU_AMD_DRIVER_BYTE_BUG
+ write_vec4(start_loop_index, edge_facs);
+#else
+ /* When packed into bytes, the index is the same as for the quad. */
+ write_vec4(quad_index, edge_facs);
+#endif
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl
new file mode 100644
index 00000000000..ea73b9482d3
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl
@@ -0,0 +1,80 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputVerts
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 1) readonly buffer inputUVs
+{
+ vec2 uvs[];
+};
+
+/* Mirror of #UVStretchAngle in the C++ code, but using floats until proper data compression
+ * is implemented for all subdivision data. */
+struct UVStretchAngle {
+ float angle;
+ float uv_angle0;
+ float uv_angle1;
+};
+
+layout(std430, binding = 2) writeonly buffer outputStretchAngles
+{
+ UVStretchAngle uv_stretches[];
+};
+
+#define M_PI 3.1415926535897932
+#define M_1_PI 0.31830988618379067154
+
+/* Adapted from BLI_math_vector.h */
+float angle_normalized_v3v3(vec3 v1, vec3 v2)
+{
+ /* this is the same as acos(dot_v3v3(v1, v2)), but more accurate */
+ bool q = (dot(v1, v2) >= 0.0);
+ vec3 v = (q) ? (v1 - v2) : (v1 + v2);
+ float a = 2.0 * asin(length(v) / 2.0);
+ return (q) ? a : M_PI - a;
+}
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint i = 0; i < 4; i++) {
+ uint cur_loop_index = start_loop_index + i;
+ uint next_loop_index = start_loop_index + (i + 1) % 4;
+ uint prev_loop_index = start_loop_index + (i + 3) % 4;
+
+ /* Compute 2d edge vectors from UVs. */
+ vec2 cur_uv = uvs[src_offset + cur_loop_index];
+ vec2 next_uv = uvs[src_offset + next_loop_index];
+ vec2 prev_uv = uvs[src_offset + prev_loop_index];
+
+ vec2 norm_uv_edge0 = normalize(prev_uv - cur_uv);
+ vec2 norm_uv_edge1 = normalize(cur_uv - next_uv);
+
+ /* Compute 3d edge vectors from positions. */
+ vec3 cur_pos = get_vertex_pos(pos_nor[cur_loop_index]);
+ vec3 next_pos = get_vertex_pos(pos_nor[next_loop_index]);
+ vec3 prev_pos = get_vertex_pos(pos_nor[prev_loop_index]);
+
+ vec3 norm_pos_edge0 = normalize(prev_pos - cur_pos);
+ vec3 norm_pos_edge1 = normalize(cur_pos - next_pos);
+
+ /* Compute stretches, this logic is adapted from #edituv_get_edituv_stretch_angle.
+ * Keep in sync! */
+ UVStretchAngle stretch;
+ stretch.uv_angle0 = atan(norm_uv_edge0.y, norm_uv_edge0.x) * M_1_PI;
+ stretch.uv_angle1 = atan(norm_uv_edge1.y, norm_uv_edge1.x) * M_1_PI;
+ stretch.angle = angle_normalized_v3v3(norm_pos_edge0, norm_pos_edge1) * M_1_PI;
+
+ uv_stretches[cur_loop_index] = stretch;
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl
new file mode 100644
index 00000000000..e897fb3f3c0
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl
@@ -0,0 +1,31 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 1) readonly buffer inputCoarseData
+{
+ float coarse_stretch_area[];
+};
+
+layout(std430, binding = 2) writeonly buffer outputSubdivData
+{
+ float subdiv_stretch_area[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ /* The start index of the loop is quad_index * 4. */
+ uint start_loop_index = quad_index * 4;
+
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+
+ for (int i = 0; i < 4; i++) {
+ subdiv_stretch_area[start_loop_index + i] = coarse_stretch_area[coarse_quad_index];
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
new file mode 100644
index 00000000000..41a8df3cf82
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
@@ -0,0 +1,52 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 1) readonly buffer inputVertexData
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 2) readonly buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+
+layout(std430, binding = 3) writeonly buffer outputLoopNormals
+{
+ vec3 output_lnor[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ /* The start index of the loop is quad_index * 4. */
+ uint start_loop_index = quad_index * 4;
+
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+
+ if ((extra_coarse_face_data[coarse_quad_index] & coarse_face_smooth_mask) != 0) {
+ /* Face is smooth, use vertex normals. */
+ for (int i = 0; i < 4; i++) {
+ PosNorLoop pos_nor_loop = pos_nor[start_loop_index + i];
+ output_lnor[start_loop_index + i] = get_vertex_nor(pos_nor_loop);
+ }
+ }
+ else {
+ /* Face is flat shaded, compute flat face normal from an inscribed triangle. */
+ vec3 verts[3];
+ for (int i = 0; i < 3; i++) {
+ verts[i] = get_vertex_pos(pos_nor[start_loop_index + i]);
+ }
+
+ vec3 face_normal = normalize(cross(verts[1] - verts[0], verts[2] - verts[0]));
+ for (int i = 0; i < 4; i++) {
+ output_lnor[start_loop_index + i] = face_normal;
+ }
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
new file mode 100644
index 00000000000..7182ce57ad3
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
@@ -0,0 +1,47 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+struct SculptData {
+ uint face_set_color;
+ float mask;
+};
+
+layout(std430, binding = 0) readonly restrict buffer sculptMask
+{
+ float sculpt_mask[];
+};
+
+layout(std430, binding = 1) readonly restrict buffer faceSetColor
+{
+ uint face_set_color[];
+};
+
+layout(std430, binding = 2) writeonly restrict buffer sculptData
+{
+ SculptData sculpt_data[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ SculptData data;
+ data.face_set_color = face_set_color[loop_index];
+
+ if (has_sculpt_mask) {
+ data.mask = sculpt_mask[loop_index];
+ }
+ else {
+ data.mask = 0.0;
+ }
+
+ sculpt_data[loop_index] = data;
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_view_clipping_lib.glsl b/source/blender/draw/intern/shaders/common_view_clipping_lib.glsl
new file mode 100644
index 00000000000..d55808c42d2
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_view_clipping_lib.glsl
@@ -0,0 +1,33 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
+#if defined(GPU_VERTEX_SHADER) || defined(GPU_GEOMETRY_SHADER)
+
+void view_clipping_distances(vec3 wpos)
+{
+# ifdef USE_WORLD_CLIP_PLANES
+ vec4 pos = vec4(wpos, 1.0);
+ gl_ClipDistance[0] = dot(drw_view.clip_planes[0], pos);
+ gl_ClipDistance[1] = dot(drw_view.clip_planes[1], pos);
+ gl_ClipDistance[2] = dot(drw_view.clip_planes[2], pos);
+ gl_ClipDistance[3] = dot(drw_view.clip_planes[3], pos);
+ gl_ClipDistance[4] = dot(drw_view.clip_planes[4], pos);
+ gl_ClipDistance[5] = dot(drw_view.clip_planes[5], pos);
+# endif
+}
+
+/* Kept as define for compiler compatibility. */
+# ifdef USE_WORLD_CLIP_PLANES
+# define view_clipping_distances_set(c) \
+ gl_ClipDistance[0] = (c).gl_ClipDistance[0]; \
+ gl_ClipDistance[1] = (c).gl_ClipDistance[1]; \
+ gl_ClipDistance[2] = (c).gl_ClipDistance[2]; \
+ gl_ClipDistance[3] = (c).gl_ClipDistance[3]; \
+ gl_ClipDistance[4] = (c).gl_ClipDistance[4]; \
+ gl_ClipDistance[5] = (c).gl_ClipDistance[5];
+
+# else
+# define view_clipping_distances_set(c)
+# endif
+
+#endif
diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index e9912ba7d9a..d4d18b95238 100644
--- a/source/blender/draw/intern/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -1,5 +1,7 @@
-#define COMMON_VIEW_LIB
-#define DRW_RESOURCE_CHUNK_LEN 512
+/* Temporary until we fully make the switch. */
+#ifndef DRW_SHADER_SHARED_H
+
+# define DRW_RESOURCE_CHUNK_LEN 512
/* keep in sync with DRWManager.view_data */
layout(std140) uniform viewBlock
@@ -22,6 +24,8 @@ layout(std140) uniform viewBlock
vec4 CameraTexCoFactors;
};
+#endif /* DRW_SHADER_SHARED_H */
+
#define ViewNear (ViewVecs[0].w)
#define ViewFar (ViewVecs[1].w)
@@ -80,67 +84,96 @@ vec4 pack_line_data(vec2 frag_co, vec2 edge_start, vec2 edge_pos)
}
}
-uniform int resourceChunk;
+/* Temporary until we fully make the switch. */
+#ifndef DRW_SHADER_SHARED_H
+uniform int drw_resourceChunk;
+#endif /* DRW_SHADER_SHARED_H */
#ifdef GPU_VERTEX_SHADER
-# ifdef GPU_ARB_shader_draw_parameters
-# define baseInstance gl_BaseInstanceARB
-# else /* no ARB_shader_draw_parameters */
-uniform int baseInstance;
-# endif
-# if defined(IN_PLACE_INSTANCES) || defined(INSTANCED_ATTR)
-/* When drawing instances of an object at the same position. */
-# define instanceId 0
-# elif defined(GPU_DEPRECATED_AMD_DRIVER)
-/* A driver bug make it so that when using an attribute with GL_INT_2_10_10_10_REV as format,
- * the gl_InstanceID is incremented by the 2 bit component of the attribute.
- * Ignore gl_InstanceID then. */
-# define instanceId 0
-# else
-# define instanceId gl_InstanceID
-# endif
+/* Temporary until we fully make the switch. */
+# ifndef DRW_SHADER_SHARED_H
-# ifdef UNIFORM_RESOURCE_ID
-/* This is in the case we want to do a special instance drawcall but still want to have the
- * right resourceId and all the correct ubo datas. */
-uniform int resourceId;
-# define resource_id resourceId
-# else
-# define resource_id (baseInstance + instanceId)
-# endif
+/* clang-format off */
+# if defined(IN_PLACE_INSTANCES) || defined(INSTANCED_ATTR) || defined(DRW_LEGACY_MODEL_MATRIX) || defined(GPU_DEPRECATED_AMD_DRIVER)
+/* clang-format on */
+/* When drawing instances of an object at the same position. */
+# define instanceId 0
+# else
+# define instanceId gl_InstanceID
+# endif
+
+# if defined(UNIFORM_RESOURCE_ID)
+/* This is in the case we want to do a special instance drawcall for one object but still want to
+ * have the right resourceId and all the correct ubo datas. */
+uniform int drw_ResourceID;
+# define resource_id drw_ResourceID
+# else
+# define resource_id (gpu_BaseInstance + instanceId)
+# endif
/* Use this to declare and pass the value if
* the fragment shader uses the resource_id. */
-# ifdef USE_GEOMETRY_SHADER
-# define RESOURCE_ID_VARYING flat out int resourceIDGeom;
-# define PASS_RESOURCE_ID resourceIDGeom = resource_id;
-# else
-# define RESOURCE_ID_VARYING flat out int resourceIDFrag;
-# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
+# ifdef USE_GEOMETRY_SHADER
+# define RESOURCE_ID_VARYING flat out int resourceIDGeom;
+# define PASS_RESOURCE_ID resourceIDGeom = resource_id;
+# else
+# define RESOURCE_ID_VARYING flat out int resourceIDFrag;
+# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
+# endif
+
+# endif /* DRW_SHADER_SHARED_H */
+
+#endif /* GPU_VERTEX_SHADER */
+
+/* Temporary until we fully make the switch. */
+#ifdef DRW_SHADER_SHARED_H
+/* TODO(fclem): Rename PASS_RESOURCE_ID to DRW_RESOURCE_ID_VARYING_SET */
+# if defined(UNIFORM_RESOURCE_ID)
+# define resource_id drw_ResourceID
+# define PASS_RESOURCE_ID
+
+# elif defined(GPU_VERTEX_SHADER)
+# define resource_id gpu_InstanceIndex
+# define PASS_RESOURCE_ID drw_ResourceID_iface.resource_index = resource_id;
+
+# elif defined(GPU_GEOMETRY_SHADER)
+# define resource_id drw_ResourceID_iface_in[0].index
+# define PASS_RESOURCE_ID drw_ResourceID_iface_out.resource_index = resource_id;
+
+# elif defined(GPU_FRAGMENT_SHADER)
+# define resource_id drw_ResourceID_iface.resource_index
# endif
-#endif
+/* TODO(fclem): Remove. */
+# define RESOURCE_ID_VARYING
+
+#else
/* If used in a fragment / geometry shader, we pass
* resource_id as varying. */
-#ifdef GPU_GEOMETRY_SHADER
-# define RESOURCE_ID_VARYING \
- flat out int resourceIDFrag; \
- flat in int resourceIDGeom[];
+# ifdef GPU_GEOMETRY_SHADER
+# define RESOURCE_ID_VARYING \
+ flat out int resourceIDFrag; \
+ flat in int resourceIDGeom[];
-# define resource_id resourceIDGeom
-# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0];
-#endif
+# define resource_id resourceIDGeom
+# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0];
+# endif
-#ifdef GPU_FRAGMENT_SHADER
+# ifdef GPU_FRAGMENT_SHADER
flat in int resourceIDFrag;
-# define resource_id resourceIDFrag
+# define resource_id resourceIDFrag
+# endif
#endif
/* Breaking this across multiple lines causes issues for some older GLSL compilers. */
/* clang-format off */
-#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTR)
+#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX)
/* clang-format on */
+
+/* Temporary until we fully make the switch. */
+# ifndef DRW_SHADER_SHARED_H
+
struct ObjectMatrices {
mat4 drw_modelMatrix;
mat4 drw_modelMatrixInverse;
@@ -151,19 +184,28 @@ layout(std140) uniform modelBlock
ObjectMatrices drw_matrices[DRW_RESOURCE_CHUNK_LEN];
};
-# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix)
-# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse)
+# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix)
+# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse)
+# endif /* DRW_SHADER_SHARED_H */
#else /* GPU_INTEL */
+
+/* Temporary until we fully make the switch. */
+# ifndef DRW_SHADER_SHARED_H
/* Intel GPU seems to suffer performance impact when the model matrix is in UBO storage.
* So for now we just force using the legacy path. */
/* Note that this is also a workaround of a problem on osx (amd or nvidia)
* and older amd driver on windows. */
uniform mat4 ModelMatrix;
uniform mat4 ModelMatrixInverse;
+# endif /* DRW_SHADER_SHARED_H */
+
#endif
-#define resource_handle (resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)
+/* Temporary until we fully make the switch. */
+#ifndef DRW_SHADER_SHARED_H
+# define resource_handle (drw_resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)
+#endif
/** Transform shortcuts. */
/* Rule of thumb: Try to reuse world positions and normals because converting through viewspace
diff --git a/source/blender/draw/intern/shaders/draw_fullscreen_info.hh b/source/blender/draw/intern/shaders/draw_fullscreen_info.hh
new file mode 100644
index 00000000000..803ad69ffb7
--- /dev/null
+++ b/source/blender/draw/intern/shaders/draw_fullscreen_info.hh
@@ -0,0 +1,8 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(fullscreen_iface, "").smooth(Type::VEC4, "uvcoordsvar");
+
+GPU_SHADER_CREATE_INFO(draw_fullscreen)
+ .vertex_out(fullscreen_iface)
+ .vertex_source("common_fullscreen_vert.glsl");
diff --git a/source/blender/draw/intern/shaders/draw_hair_refine_info.hh b/source/blender/draw/intern/shaders/draw_hair_refine_info.hh
new file mode 100644
index 00000000000..b41be7d8605
--- /dev/null
+++ b/source/blender/draw/intern/shaders/draw_hair_refine_info.hh
@@ -0,0 +1,42 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(draw_hair_refine_compute)
+ .local_group_size(1, 1)
+ .storage_buf(0, Qualifier::WRITE_ONLY, "vec4", "posTime[]")
+ .sampler(0, ImageType::FLOAT_BUFFER, "hairPointBuffer")
+ .sampler(1, ImageType::UINT_BUFFER, "hairStrandBuffer")
+ .sampler(2, ImageType::UINT_BUFFER, "hairStrandSegBuffer")
+ .push_constant(Type::VEC4, "hairDupliMatrix", 4)
+ .push_constant(Type::BOOL, "hairCloseTip")
+ .push_constant(Type::FLOAT, "hairRadShape")
+ .push_constant(Type::FLOAT, "hairRadTip")
+ .push_constant(Type::FLOAT, "hairRadRoot")
+ .push_constant(Type::INT, "hairThicknessRes")
+ .push_constant(Type::INT, "hairStrandsRes")
+ .push_constant(Type::INT, "hairStrandOffset")
+ .compute_source("common_hair_refine_comp.glsl")
+ .define("HAIR_PHASE_SUBDIV")
+ .do_static_compilation(true);
diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
new file mode 100644
index 00000000000..17a32c7d5ed
--- /dev/null
+++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
@@ -0,0 +1,6 @@
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(draw_object_infos)
+ .typedef_source("draw_shader_shared.h")
+ .uniform_buf(1, "ObjectInfos", "drw_infos[DRW_RESOURCE_CHUNK_LEN]", Frequency::BATCH);
diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh
new file mode 100644
index 00000000000..0a25059ffed
--- /dev/null
+++ b/source/blender/draw/intern/shaders/draw_view_info.hh
@@ -0,0 +1,105 @@
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Resource ID
+ *
+ * This is used to fetch per object data in drw_matrices and other object indexed
+ * buffers. There is multiple possibilities depending on how we are drawing the object.
+ *
+ * \{ */
+
+/* Standard way. Use gpu_InstanceIndex to index the object data. */
+GPU_SHADER_CREATE_INFO(draw_resource_id).define("DYNAMIC_RESOURCE_ID");
+
+/**
+ * Used if the resource index needs to be passed to the fragment shader.
+ * IMPORTANT: Vertex and Geometry shaders need to use PASS_RESOURCE_ID in main().
+ */
+GPU_SHADER_INTERFACE_INFO(draw_resource_id_iface, "drw_ResourceID_iface")
+ .flat(Type::INT, "resource_index");
+
+GPU_SHADER_CREATE_INFO(draw_resource_id_varying)
+ .vertex_out(draw_resource_id_iface)
+ .geometry_out(draw_resource_id_iface); /* Used if needed. */
+
+/* Variation used when drawing multiple instances for one object. */
+GPU_SHADER_CREATE_INFO(draw_resource_id_uniform)
+ .define("UNIFORM_RESOURCE_ID")
+ .push_constant(Type::INT, "drw_ResourceID");
+
+/**
+ * Declare a resource handle that identify a unique object.
+ * Requires draw_resource_id[_constant].
+ */
+GPU_SHADER_CREATE_INFO(draw_resource_handle)
+ .define("resource_handle (drw_resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)")
+ .push_constant(Type::INT, "drw_resourceChunk");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw View
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(draw_view)
+ .uniform_buf(0, "ViewInfos", "drw_view", Frequency::PASS)
+ .typedef_source("draw_shader_shared.h");
+
+GPU_SHADER_CREATE_INFO(draw_modelmat)
+ .uniform_buf(8, "ObjectMatrices", "drw_matrices[DRW_RESOURCE_CHUNK_LEN]", Frequency::BATCH)
+ .define("ModelMatrix", "(drw_matrices[resource_id].drw_modelMatrix)")
+ .define("ModelMatrixInverse", "(drw_matrices[resource_id].drw_modelMatrixInverse)")
+ .additional_info("draw_view");
+
+GPU_SHADER_CREATE_INFO(draw_modelmat_legacy)
+ .define("DRW_LEGACY_MODEL_MATRIX")
+ .push_constant(Type::MAT4, "ModelMatrix")
+ .push_constant(Type::MAT4, "ModelMatrixInverse")
+ .additional_info("draw_view");
+
+GPU_SHADER_CREATE_INFO(draw_modelmat_instanced_attr)
+ .push_constant(Type::MAT4, "ModelMatrix")
+ .push_constant(Type::MAT4, "ModelMatrixInverse")
+ .additional_info("draw_view");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Draw View
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(drw_clipped).define("USE_WORLD_CLIP_PLANES");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Type
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(draw_mesh).additional_info("draw_modelmat", "draw_resource_id");
+
+GPU_SHADER_CREATE_INFO(draw_hair)
+ .sampler(15, ImageType::FLOAT_BUFFER, "hairPointBuffer")
+ .sampler(14, ImageType::UINT_BUFFER, "hairStrandBuffer")
+ .sampler(13, ImageType::UINT_BUFFER, "hairStrandSegBuffer")
+ /* TODO(fclem) Pack thoses into one UBO. */
+ .push_constant(Type::INT, "hairStrandsRes")
+ .push_constant(Type::INT, "hairThicknessRes")
+ .push_constant(Type::FLOAT, "hairRadRoot")
+ .push_constant(Type::FLOAT, "hairRadTip")
+ .push_constant(Type::FLOAT, "hairRadShape")
+ .push_constant(Type::BOOL, "hairCloseTip")
+ .push_constant(Type::INT, "hairStrandOffset")
+ .push_constant(Type::VEC4, "hairDupliMatrix", 4)
+ .additional_info("draw_modelmat", "draw_resource_id");
+
+GPU_SHADER_CREATE_INFO(draw_pointcloud)
+ .vertex_in(0, Type::VEC4, "pos")
+ .vertex_in(1, Type::VEC3, "pos_inst")
+ .vertex_in(2, Type::VEC3, "nor")
+ .additional_info("draw_modelmat_instanced_attr", "draw_resource_id_uniform");
+
+GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resource_id_uniform");
+
+/** \} */
diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc
index ef702821a59..6f4dc226c84 100644
--- a/source/blender/draw/tests/shaders_test.cc
+++ b/source/blender/draw/tests/shaders_test.cc
@@ -27,8 +27,6 @@ using namespace blender::draw::image_engine;
static void test_workbench_glsl_shaders()
{
- workbench_shader_library_ensure();
-
const int MAX_WPD = 6;
WORKBENCH_PrivateData wpds[MAX_WPD];
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index f509898f2ee..bdcbac80699 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -879,10 +879,10 @@ EnumPropertyItem prop_driver_create_mapping_types[] = {
};
/* Filtering callback for driver mapping types enum */
-static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C,
- PointerRNA *UNUSED(owner_ptr),
- PropertyRNA *UNUSED(owner_prop),
- bool *r_free)
+static const EnumPropertyItem *driver_mapping_type_itemf(bContext *C,
+ PointerRNA *UNUSED(owner_ptr),
+ PropertyRNA *UNUSED(owner_prop),
+ bool *r_free)
{
EnumPropertyItem *input = prop_driver_create_mapping_types;
EnumPropertyItem *item = NULL;
@@ -961,7 +961,7 @@ static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_typ
}
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
if (path) {
@@ -1039,7 +1039,7 @@ static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot)
0,
"Mapping Type",
"Method used to match target and driven properties");
- RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf);
+ RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemf);
}
/* Add Driver Button Operator ------------------------ */
@@ -1055,7 +1055,7 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
/* 1) Create a new "empty" driver for this property */
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
bool changed = false;
@@ -1115,7 +1115,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op)
}
if (ptr.owner_id && ptr.data && prop) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
changed = ANIM_remove_driver(op->reports, ptr.owner_id, path, index, 0);
@@ -1200,7 +1200,7 @@ static int copy_driver_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
/* only copy the driver for the button that this was involved for */
@@ -1244,7 +1244,7 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
/* only copy the driver for the button that this was involved for */
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 6fba2d9c258..ae8d04f51d3 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -496,7 +496,7 @@ static void ED_keylist_draw_list_elem_prepare_for_drawing(AnimKeylistDrawListEle
}
typedef struct AnimKeylistDrawList {
- ListBase /* AnimKeylistDrawListElem*/ channels;
+ ListBase /* AnimKeylistDrawListElem */ channels;
} AnimKeylistDrawList;
AnimKeylistDrawList *ED_keylist_draw_list_create(void)
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 145d67b7810..dfe6566df67 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -1283,6 +1283,61 @@ static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
+static void handle_flatten(float vec[3][3], const int idx, const float direction[2])
+{
+ BLI_assert_msg(idx == 0 || idx == 2, "handle_flatten() expects a handle index");
+
+ add_v2_v2v2(vec[idx], vec[1], direction);
+}
+
+static void handle_set_length(float vec[3][3], const int idx, const float handle_length)
+{
+ BLI_assert_msg(idx == 0 || idx == 2, "handle_set_length() expects a handle index");
+
+ float handle_direction[2];
+ sub_v2_v2v2(handle_direction, vec[idx], vec[1]);
+ normalize_v2_length(handle_direction, handle_length);
+ add_v2_v2v2(vec[idx], vec[1], handle_direction);
+}
+
+void ANIM_fcurve_equalize_keyframes_loop(FCurve *fcu,
+ const eEditKeyframes_Equalize mode,
+ const float handle_length,
+ const bool flatten)
+{
+ uint i;
+ BezTriple *bezt;
+ const float flat_direction_left[2] = {-handle_length, 0.f};
+ const float flat_direction_right[2] = {handle_length, 0.f};
+
+ /* Loop through an F-Curves keyframes. */
+ for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
+ if ((bezt->f2 & SELECT) == 0) {
+ continue;
+ }
+
+ /* Perform handle equalization if mode is 'Both' or 'Left'. */
+ if (mode & EQUALIZE_HANDLES_LEFT) {
+ if (flatten) {
+ handle_flatten(bezt->vec, 0, flat_direction_left);
+ }
+ else {
+ handle_set_length(bezt->vec, 0, handle_length);
+ }
+ }
+
+ /* Perform handle equalization if mode is 'Both' or 'Right'. */
+ if (mode & EQUALIZE_HANDLES_RIGHT) {
+ if (flatten) {
+ handle_flatten(bezt->vec, 2, flat_direction_right);
+ }
+ else {
+ handle_set_length(bezt->vec, 2, handle_length);
+ }
+ }
+ }
+}
+
KeyframeEditFunc ANIM_editkeyframes_ipo(short mode)
{
switch (mode) {
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index dc5d71b5a1e..92017c02858 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -307,11 +307,13 @@ 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.
+/**
+ * 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.*/
+ * \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,
@@ -345,6 +347,67 @@ static bool find_fcurve_segment(FCurve *fcu,
return in_segment;
}
+ListBase find_fcurve_segments(FCurve *fcu)
+{
+ ListBase segments = {NULL, NULL};
+ int segment_start_idx = 0;
+ int segment_len = 0;
+ int current_index = 0;
+
+ while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) {
+ FCurveSegment *segment;
+ segment = MEM_callocN(sizeof(*segment), "FCurveSegment");
+ segment->start_index = segment_start_idx;
+ segment->length = segment_len;
+ BLI_addtail(&segments, segment);
+ current_index = segment_start_idx + segment_len;
+ }
+ return segments;
+}
+
+static BezTriple fcurve_segment_start_get(FCurve *fcu, int index)
+{
+ BezTriple start_bezt = index - 1 >= 0 ? fcu->bezt[index - 1] : fcu->bezt[index];
+ return start_bezt;
+}
+
+static BezTriple fcurve_segment_end_get(FCurve *fcu, int index)
+{
+ BezTriple end_bezt = index < fcu->totvert ? fcu->bezt[index] : fcu->bezt[index - 1];
+ return end_bezt;
+}
+
+/* ---------------- */
+
+void blend_to_neighbor_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
+{
+ const float blend_factor = fabs(factor * 2 - 1);
+ BezTriple target_bezt;
+ /* Find which key to blend towards. */
+ if (factor < 0.5f) {
+ target_bezt = fcurve_segment_start_get(fcu, segment->start_index);
+ }
+ else {
+ target_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length);
+ }
+ /* Blend each key individually. */
+ for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
+ fcu->bezt[i].vec[1][1] = interpf(target_bezt.vec[1][1], fcu->bezt[i].vec[1][1], blend_factor);
+ }
+}
+
+/* ---------------- */
+
+void breakdown_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
+{
+ BezTriple left_bezt = fcurve_segment_start_get(fcu, segment->start_index);
+ BezTriple right_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length);
+
+ for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
+ fcu->bezt[i].vec[1][1] = interpf(right_bezt.vec[1][1], left_bezt.vec[1][1], factor);
+ }
+}
+
/* ---------------- */
/* Check if the keyframe interpolation type is supported */
@@ -440,15 +503,12 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG;
}
- /* Only decimate the individual selected curve segments. */
- int segment_start_idx = 0;
- int segment_len = 0;
- int current_index = 0;
-
- while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) {
- decimate_fcurve_segment(fcu, segment_start_idx, segment_len, remove_ratio, error_sq_max);
- current_index = segment_start_idx + segment_len;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ decimate_fcurve_segment(
+ fcu, segment->start_index, segment->length, remove_ratio, error_sq_max);
}
+ BLI_freelistN(&segments);
uint old_totvert = fcu->totvert;
fcu->bezt = NULL;
diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc
index 8dae46766fa..aba73ec141b 100644
--- a/source/blender/editors/animation/keyframes_keylist.cc
+++ b/source/blender/editors/animation/keyframes_keylist.cc
@@ -80,7 +80,7 @@ struct AnimKeylist {
ListBase /* ActKeyColumn */ key_columns;
/* Last accessed column in the key_columns list base. Inserting columns are typically done in
* order. The last accessed column is used as starting point to search for a location to add or
- * update the next column.*/
+ * update the next column. */
std::optional<ActKeyColumn *> last_accessed_column = std::nullopt;
struct {
@@ -850,7 +850,6 @@ bool actkeyblock_is_valid(const ActKeyColumn *ac)
return ac != nullptr && ac->next != nullptr && ac->totblock > 0;
}
-/* Checks if ActKeyBlock should exist... */
int actkeyblock_get_valid_hold(const ActKeyColumn *ac)
{
/* check that block is valid */
diff --git a/source/blender/editors/animation/keyframes_keylist_test.cc b/source/blender/editors/animation/keyframes_keylist_test.cc
index 17a21be5ae8..914693842ca 100644
--- a/source/blender/editors/animation/keyframes_keylist_test.cc
+++ b/source/blender/editors/animation/keyframes_keylist_test.cc
@@ -26,12 +26,12 @@ 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;
+ fcurve.bezt[0].vec[1][0] = 10.0f;
+ fcurve.bezt[0].vec[1][1] = 1.0f;
+ fcurve.bezt[1].vec[1][0] = 20.0f;
+ fcurve.bezt[1].vec[1][1] = 2.0f;
+ fcurve.bezt[2].vec[1][0] = 30.0f;
+ fcurve.bezt[2].vec[1][1] = 1.0f;
}
static AnimKeylist *create_test_keylist()
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 25d2f6c510b..0a435a9034a 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -580,7 +580,7 @@ int insert_vert_fcurve(
beztr.ipo = BEZT_IPO_BEZ;
}
else {
- /* for UI usage - defaults should come from the userprefs and/or toolsettings */
+ /* For UI usage - defaults should come from the user-preferences and/or tool-settings. */
beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */
/* use default interpolation mode, with exceptions for int/discrete values */
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 97f8c0cf630..252cf806e34 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -297,7 +297,7 @@ 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_ex(struct bArmature *arm, int flag);
void armature_select_mirrored(struct bArmature *arm);
/** Only works when tagged. */
void armature_tag_unselect(struct bArmature *arm);
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 990e7589d9d..787d7cbaab0 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -1618,8 +1618,7 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
mdb->cagemesh_cache.mpoly = me->mpoly;
mdb->cagemesh_cache.mloop = me->mloop;
mdb->cagemesh_cache.looptri = BKE_mesh_runtime_looptri_ensure(me);
- /* can be NULL */
- mdb->cagemesh_cache.poly_nors = CustomData_get_layer(&me->pdata, CD_NORMAL);
+ mdb->cagemesh_cache.poly_nors = BKE_mesh_poly_normals_ensure(me);
}
/* make bounding box equal size in all directions, add padding, and compute
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 772fe8f3196..8bd6c9f54fd 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -160,7 +160,7 @@ static bool pose_has_protected_selected(Object *ob, short warn)
bArmature *arm = ob->data;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone && (pchan->bone->layer & arm->layer)) {
+ if (pchan->bone && BKE_pose_is_layer_visible(arm, pchan)) {
if (pchan->bone->layer & arm->layer_protected) {
if (pchan->bone->flag & BONE_SELECTED) {
break;
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 646356e7a45..dc96c777be0 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -1070,7 +1070,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld,
else if (pchan->bone) {
/* only ok if bone is visible and selected */
if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->flag & BONE_HIDDEN_P) == 0 &&
- (pchan->bone->layer & arm->layer)) {
+ BKE_pose_is_layer_visible(arm, pchan)) {
ok = 1;
}
}
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 17347aa57fe..0b889149f9d 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -746,7 +746,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
bool changed = false;
- pchan_act = BKE_pose_channel_active(ob);
+ pchan_act = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan_act == NULL) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt
index 2391f4af14d..086fab4ab47 100644
--- a/source/blender/editors/asset/CMakeLists.txt
+++ b/source/blender/editors/asset/CMakeLists.txt
@@ -48,6 +48,7 @@ set(SRC
ED_asset_catalog.hh
ED_asset_filter.h
ED_asset_handle.h
+ ED_asset_indexer.h
ED_asset_library.h
ED_asset_list.h
ED_asset_list.hh
diff --git a/source/blender/editors/asset/ED_asset_catalog.h b/source/blender/editors/asset/ED_asset_catalog.h
index be99de01173..acb0b67d9c0 100644
--- a/source/blender/editors/asset/ED_asset_catalog.h
+++ b/source/blender/editors/asset/ED_asset_catalog.h
@@ -28,8 +28,8 @@
extern "C" {
#endif
-struct Main;
struct AssetLibrary;
+struct Main;
void ED_asset_catalogs_save_from_main_path(struct AssetLibrary *library, const struct Main *bmain);
diff --git a/source/blender/editors/asset/ED_asset_mark_clear.h b/source/blender/editors/asset/ED_asset_mark_clear.h
index 8e6a8e11d69..8f10e769c52 100644
--- a/source/blender/editors/asset/ED_asset_mark_clear.h
+++ b/source/blender/editors/asset/ED_asset_mark_clear.h
@@ -25,8 +25,8 @@ extern "C" {
#endif
struct ID;
-struct bContext;
struct Main;
+struct bContext;
/**
* Mark the datablock as asset.
@@ -50,7 +50,8 @@ void ED_asset_generate_preview(const struct bContext *C, struct ID *id);
* This clears the Fake User. If for some reason the datablock is meant to be saved anyway, the
* caller is responsible for explicitly setting the Fake User.
*
- * \return whether the asset metadata was actually removed; false when the ID was not an asset. */
+ * \return whether the asset metadata was actually removed; false when the ID was not an asset.
+ */
bool ED_asset_clear_id(struct ID *id);
void ED_assets_pre_save(struct Main *bmain);
diff --git a/source/blender/editors/asset/ED_asset_type.h b/source/blender/editors/asset/ED_asset_type.h
index 36cbb4591e9..e1c327808aa 100644
--- a/source/blender/editors/asset/ED_asset_type.h
+++ b/source/blender/editors/asset/ED_asset_type.h
@@ -30,7 +30,7 @@ struct ID;
bool ED_asset_type_id_is_non_experimental(const struct ID *id);
#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS \
- (FILTER_ID_MA | FILTER_ID_OB | FILTER_ID_AC | FILTER_ID_WO)
+ (FILTER_ID_MA | FILTER_ID_OB | FILTER_ID_AC | FILTER_ID_WO | FILTER_ID_NT)
/**
* Check if the asset type for \a id (which doesn't need to be an asset right now) can be an asset,
@@ -52,7 +52,8 @@ int64_t ED_asset_types_supported_as_filter_flags(void);
* strings with this (not all UI code supports dynamic strings nicely).
* Should start with a consonant, so usages can prefix it with "a" (not "an").
*/
-#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING "Material, Object, Pose Action, or World"
+#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING \
+ "Material, Object, Pose Action, Node Group or World"
#ifdef __cplusplus
}
diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc
index 4107d28b5e3..336ccff900c 100644
--- a/source/blender/editors/asset/intern/asset_indexer.cc
+++ b/source/blender/editors/asset/intern/asset_indexer.cc
@@ -39,6 +39,7 @@
#include "BKE_appdir.h"
#include "BKE_asset.h"
#include "BKE_asset_catalog.hh"
+#include "BKE_idprop.hh"
#include "BKE_preferences.h"
#include "CLG_log.h"
@@ -49,6 +50,7 @@ namespace blender::ed::asset::index {
using namespace blender::io::serialize;
using namespace blender::bke;
+using namespace blender::bke::idprop;
/**
* \file asset_indexer.cc
@@ -69,12 +71,13 @@ using namespace blender::bke;
* "catalog_name": "<catalog_name>",
* "description": "<description>",
* "author": "<author>",
- * "tags": ["<tag>"]
+ * "tags": ["<tag>"],
+ * "properties": [..]
* }]
* }
* \endcode
*
- * NOTE: entries, author, description and tags are optional attributes.
+ * NOTE: entries, author, description, tags and properties are optional attributes.
*
* NOTE: File browser uses name and idcode separate. Inside the index they are joined together like
* #ID.name.
@@ -88,6 +91,7 @@ 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");
+constexpr StringRef ATTRIBUTE_ENTRIES_PROPERTIES("properties");
/** Abstract class for #BlendFile and #AssetIndexFile. */
class AbstractFile {
@@ -145,7 +149,7 @@ struct AssetEntryReader {
/**
* \brief Lookup table containing the elements of the entry.
*/
- ObjectValue::Lookup lookup;
+ DictionaryValue::Lookup lookup;
StringRefNull get_name_with_idcode() const
{
@@ -153,7 +157,7 @@ struct AssetEntryReader {
}
public:
- AssetEntryReader(const ObjectValue &entry) : lookup(entry.create_lookup())
+ AssetEntryReader(const DictionaryValue &entry) : lookup(entry.create_lookup())
{
}
@@ -204,7 +208,7 @@ struct AssetEntryReader {
void add_tags_to_meta_data(AssetMetaData *asset_data) const
{
- const ObjectValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS);
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS);
if (value_ptr == nullptr) {
return;
}
@@ -216,14 +220,28 @@ struct AssetEntryReader {
BKE_asset_metadata_tag_add(asset_data, tag_name.c_str());
}
}
+
+ void add_properties_to_meta_data(AssetMetaData *asset_data) const
+ {
+ BLI_assert(asset_data->properties == nullptr);
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(
+ ATTRIBUTE_ENTRIES_PROPERTIES);
+ if (value_ptr == nullptr) {
+ return;
+ }
+
+ const Value &value = *(value_ptr->get());
+ IDProperty *properties = convert_from_serialize_value(value);
+ asset_data->properties = properties;
+ }
};
struct AssetEntryWriter {
private:
- ObjectValue::Items &attributes;
+ DictionaryValue::Items &attributes;
public:
- AssetEntryWriter(ObjectValue &entry) : attributes(entry.elements())
+ AssetEntryWriter(DictionaryValue &entry) : attributes(entry.elements())
{
}
@@ -274,6 +292,15 @@ struct AssetEntryWriter {
tag_items.append_as(new StringValue(tag->name));
}
}
+
+ void add_properties(const IDProperty *properties)
+ {
+ std::unique_ptr<Value> value = convert_to_serialize_values(properties);
+ if (value == nullptr) {
+ return;
+ }
+ attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_PROPERTIES, value.release()));
+ }
};
static void init_value_from_file_indexer_entry(AssetEntryWriter &result,
@@ -298,10 +325,14 @@ static void init_value_from_file_indexer_entry(AssetEntryWriter &result,
result.add_tags(&asset_data.tags);
}
+ if (asset_data.properties != nullptr) {
+ result.add_properties(asset_data.properties);
+ }
+
/* TODO: asset_data.IDProperties */
}
-static void init_value_from_file_indexer_entries(ObjectValue &result,
+static void init_value_from_file_indexer_entries(DictionaryValue &result,
const FileIndexerEntries &indexer_entries)
{
ArrayValue *entries = new ArrayValue();
@@ -313,7 +344,7 @@ static void init_value_from_file_indexer_entries(ObjectValue &result,
if (indexer_entry->datablock_info.asset_data == nullptr) {
continue;
}
- ObjectValue *entry_value = new ObjectValue();
+ DictionaryValue *entry_value = new DictionaryValue();
AssetEntryWriter entry(*entry_value);
init_value_from_file_indexer_entry(entry, indexer_entry);
items.append_as(entry_value);
@@ -326,7 +357,7 @@ static void init_value_from_file_indexer_entries(ObjectValue &result,
return;
}
- ObjectValue::Items &attributes = result.elements();
+ DictionaryValue::Items &attributes = result.elements();
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries));
}
@@ -363,13 +394,14 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
asset_data->catalog_id = entry.get_catalog_id();
entry.add_tags_to_meta_data(asset_data);
+ entry.add_properties_to_meta_data(asset_data);
}
static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries,
- const ObjectValue &value)
+ const DictionaryValue &value)
{
- const ObjectValue::Lookup attributes = value.create_lookup();
- const ObjectValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES);
+ const DictionaryValue::Lookup attributes = value.create_lookup();
+ const DictionaryValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES);
BLI_assert(entries_value != nullptr);
if (entries_value == nullptr) {
@@ -379,7 +411,7 @@ static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries,
int num_entries_read = 0;
const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements();
for (ArrayValue::Item element : elements) {
- const AssetEntryReader asset_entry(*element->as_object_value());
+ const AssetEntryReader asset_entry(*element->as_dictionary_value());
FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
MEM_callocN(sizeof(FileIndexerEntry), __func__));
@@ -534,9 +566,9 @@ struct AssetIndex {
/**
* `blender::io::serialize::Value` representing the contents of an index file.
*
- * Value is used over #ObjectValue as the contents of the index could be corrupted and doesn't
- * represent an object. In case corrupted files are detected the `get_version` would return
- * `UNKNOWN_VERSION`.
+ * Value is used over #DictionaryValue as the contents of the index could be corrupted and
+ * doesn't represent an object. In case corrupted files are detected the `get_version` would
+ * return `UNKNOWN_VERSION`.
*/
std::unique_ptr<Value> contents;
@@ -546,8 +578,8 @@ struct AssetIndex {
*/
AssetIndex(const FileIndexerEntries &indexer_entries)
{
- std::unique_ptr<ObjectValue> root = std::make_unique<ObjectValue>();
- ObjectValue::Items &root_attributes = root->elements();
+ std::unique_ptr<DictionaryValue> root = std::make_unique<DictionaryValue>();
+ DictionaryValue::Items &root_attributes = root->elements();
root_attributes.append_as(std::pair(ATTRIBUTE_VERSION, new IntValue(CURRENT_VERSION)));
init_value_from_file_indexer_entries(*root, indexer_entries);
@@ -564,12 +596,12 @@ struct AssetIndex {
int get_version() const
{
- const ObjectValue *root = contents->as_object_value();
+ const DictionaryValue *root = contents->as_dictionary_value();
if (root == nullptr) {
return UNKNOWN_VERSION;
}
- const ObjectValue::Lookup attributes = root->create_lookup();
- const ObjectValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION);
+ const DictionaryValue::Lookup attributes = root->create_lookup();
+ const DictionaryValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION);
if (version_value == nullptr) {
return UNKNOWN_VERSION;
}
@@ -588,7 +620,7 @@ struct AssetIndex {
*/
int extract_into(FileIndexerEntries &indexer_entries) const
{
- const ObjectValue *root = contents->as_object_value();
+ const DictionaryValue *root = contents->as_dictionary_value();
const int num_entries_read = init_indexer_entries_from_value(indexer_entries, *root);
return num_entries_read;
}
@@ -742,16 +774,15 @@ static void update_index(const char *filename, FileIndexerEntries *entries, void
static void *init_user_data(const char *root_directory, size_t root_directory_maxlen)
{
- AssetLibraryIndex *library_index = OBJECT_GUARDED_NEW(
- AssetLibraryIndex,
- StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen)));
+ AssetLibraryIndex *library_index = MEM_new<AssetLibraryIndex>(
+ __func__, StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen)));
library_index->init_unused_index_files();
return library_index;
}
static void free_user_data(void *user_data)
{
- OBJECT_GUARDED_DELETE(user_data, AssetLibraryIndex);
+ MEM_delete((AssetLibraryIndex *)user_data);
}
static void filelist_finished(void *user_data)
diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc
index 1bfdd83b8e3..c075ae390d9 100644
--- a/source/blender/editors/asset/intern/asset_list.cc
+++ b/source/blender/editors/asset/intern/asset_list.cc
@@ -49,10 +49,6 @@
#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 {
/* -------------------------------------------------------------------- */
@@ -174,9 +170,7 @@ void AssetList::setup()
"",
"");
-#ifdef SPACE_FILE_ENABLE_ASSET_INDEXING
filelist_setindexer(files, &file_indexer_asset);
-#endif
char path[FILE_MAXDIR] = "";
if (user_library) {
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index e4edff19a21..f7755aa9fea 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -934,10 +934,10 @@ static bool has_external_files(Main *bmain, struct ReportList *reports)
BKE_reportf(
callback_info.reports,
RPT_ERROR,
- "Unable to copy bundle due to %ld external dependencies; more details on the console",
- callback_info.external_files.size());
- printf("Unable to copy bundle due to %ld external dependencies:\n",
- callback_info.external_files.size());
+ "Unable to copy bundle due to %zu external dependencies; more details on the console",
+ (size_t)callback_info.external_files.size());
+ printf("Unable to copy bundle due to %zu external dependencies:\n",
+ (size_t)callback_info.external_files.size());
for (const std::string &path : callback_info.external_files) {
printf(" \"%s\"\n", path.c_str());
}
diff --git a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
index f136c08f129..8790c907f05 100644
--- a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
+++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
@@ -88,12 +88,13 @@ AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle)
}
BLI_assert(handle->file_data->asset_data != nullptr);
return reinterpret_cast<AssetTempIDConsumer *>(
- OBJECT_GUARDED_NEW(AssetTemporaryIDConsumer, *handle));
+ MEM_new<AssetTemporaryIDConsumer>(__func__, *handle));
}
void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer)
{
- OBJECT_GUARDED_SAFE_DELETE(*consumer, AssetTemporaryIDConsumer);
+ MEM_delete(reinterpret_cast<AssetTemporaryIDConsumer *>(*consumer));
+ *consumer = nullptr;
}
ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer_,
diff --git a/source/blender/editors/asset/intern/asset_type.cc b/source/blender/editors/asset/intern/asset_type.cc
index 028c0cb9ffc..3d6ce3e3409 100644
--- a/source/blender/editors/asset/intern/asset_type.cc
+++ b/source/blender/editors/asset/intern/asset_type.cc
@@ -30,7 +30,7 @@ bool ED_asset_type_id_is_non_experimental(const ID *id)
{
/* Remember to update #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING and
* #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS() with this! */
- return ELEM(GS(id->name), ID_MA, ID_OB, ID_AC, ID_WO);
+ return ELEM(GS(id->name), ID_MA, ID_OB, ID_AC, ID_WO, ID_NT);
}
bool ED_asset_type_is_supported(const ID *id)
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 03ddeebde42..0d17af1983d 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -155,7 +155,7 @@ void ed_editnurb_translate_flag(struct ListBase *editnurb,
/**
* Only for #OB_SURF.
*/
-bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, const uint8_t flag);
+bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, uint8_t flag);
/**
* \param axis: is in world-space.
* \param cent: is in object-space.
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index a034e4bb10e..a70bc1c0350 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -4953,19 +4953,22 @@ bool ed_editnurb_spin(
if ((a & 1) == 0) {
rotateflagNurb(editnurb, SELECT, cent, scalemat1);
- weightflagNurb(editnurb, SELECT, 0.25 * M_SQRT2);
+ weightflagNurb(editnurb, SELECT, 0.5 * M_SQRT2);
}
else {
rotateflagNurb(editnurb, SELECT, cent, scalemat2);
- weightflagNurb(editnurb, SELECT, 4.0 / M_SQRT2);
+ weightflagNurb(editnurb, SELECT, 2.0 / M_SQRT2);
}
}
if (ok) {
LISTBASE_FOREACH (Nurb *, nu, editnurb) {
if (ED_curve_nurb_select_check(v3d, nu)) {
- nu->orderv = 4;
- nu->flagv |= CU_NURB_CYCLIC;
+ nu->orderv = 3;
+ /* It is challenging to create a good approximation of a circle with uniform knots vector
+ * (which is forced in Blender for cyclic NURBS curves). Here a NURBS circle is constructed
+ * by connecting four Bezier arcs. */
+ nu->flagv |= CU_NURB_CYCLIC | CU_NURB_BEZIER;
BKE_nurb_knot_calc_v(nu);
}
}
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 614805a70f5..daef4a21692 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -306,9 +306,9 @@ Nurb *ED_curve_add_nurbs_primitive(
else if (cutype == CU_NURBS) { /* nurb */
nu->pntsu = 8;
nu->pntsv = 1;
- nu->orderu = 4;
+ nu->orderu = 3;
nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "addNurbprim6");
- nu->flagu = CU_NURB_CYCLIC;
+ nu->flagu = CU_NURB_CYCLIC | CU_NURB_BEZIER;
bp = nu->bp;
for (a = 0; a < 8; a++) {
@@ -322,7 +322,7 @@ Nurb *ED_curve_add_nurbs_primitive(
bp->vec[2] += 0.25f * nurbcircle[a][1] * grid;
}
if (a & 1) {
- bp->vec[3] = 0.25 * M_SQRT2;
+ bp->vec[3] = 0.5 * M_SQRT2;
}
else {
bp->vec[3] = 1.0;
diff --git a/source/blender/editors/geometry/CMakeLists.txt b/source/blender/editors/geometry/CMakeLists.txt
index 75b334b9ec6..8c920915937 100644
--- a/source/blender/editors/geometry/CMakeLists.txt
+++ b/source/blender/editors/geometry/CMakeLists.txt
@@ -20,19 +20,21 @@ set(INC
../../blenkernel
../../blenlib
../../depsgraph
+ ../../functions
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/guardedalloc
)
set(INC_SYS
)
set(SRC
- geometry_attributes.c
- geometry_ops.c
+ geometry_attributes.cc
+ geometry_ops.cc
- geometry_intern.h
+ geometry_intern.hh
)
set(LIB
diff --git a/source/blender/editors/geometry/geometry_attributes.c b/source/blender/editors/geometry/geometry_attributes.c
deleted file mode 100644
index 5cb491f116a..00000000000
--- a/source/blender/editors/geometry/geometry_attributes.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2020 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup edgeometry
- */
-
-#include "BKE_attribute.h"
-#include "BKE_context.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
-#include "DEG_depsgraph.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_object.h"
-
-#include "geometry_intern.h"
-
-/*********************** Attribute Operators ************************/
-
-static bool geometry_attributes_poll(bContext *C)
-{
- Object *ob = ED_object_context(C);
- ID *data = (ob) ? ob->data : NULL;
- return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data)) &&
- BKE_id_attributes_supported(data);
-}
-
-static bool geometry_attributes_remove_poll(bContext *C)
-{
- if (!geometry_attributes_poll(C)) {
- return false;
- }
-
- Object *ob = ED_object_context(C);
- ID *data = (ob) ? ob->data : NULL;
- if (BKE_id_attributes_active_get(data) != NULL) {
- return true;
- }
-
- return false;
-}
-
-static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C,
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
-{
- if (C == NULL) {
- return DummyRNA_NULL_items;
- }
-
- Object *ob = ED_object_context(C);
- if (ob == NULL) {
- return DummyRNA_NULL_items;
- }
-
- return rna_enum_attribute_domain_itemf(ob->data, r_free);
-}
-
-static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_object_context(C);
- ID *id = ob->data;
-
- char name[MAX_NAME];
- RNA_string_get(op->ptr, "name", name);
- CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type");
- AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain");
- CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
-
- if (layer == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_id_attributes_active_set(id, layer);
-
- DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, id);
-
- return OPERATOR_FINISHED;
-}
-
-void GEOMETRY_OT_attribute_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Geometry Attribute";
- ot->description = "Add attribute to geometry";
- ot->idname = "GEOMETRY_OT_attribute_add";
-
- /* api callbacks */
- ot->poll = geometry_attributes_poll;
- ot->exec = geometry_attribute_add_exec;
- ot->invoke = WM_operator_props_popup_confirm;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- PropertyRNA *prop;
-
- prop = RNA_def_string(ot->srna, "name", "Attribute", MAX_NAME, "Name", "Name of new attribute");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_enum(ot->srna,
- "domain",
- rna_enum_attribute_domain_items,
- ATTR_DOMAIN_POINT,
- "Domain",
- "Type of element that attribute is stored on");
- RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_enum(ot->srna,
- "data_type",
- rna_enum_attribute_type_items,
- CD_PROP_FLOAT,
- "Data Type",
- "Type of data stored in attribute");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_object_context(C);
- ID *id = ob->data;
- CustomDataLayer *layer = BKE_id_attributes_active_get(id);
-
- if (layer == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- if (!BKE_id_attribute_remove(id, layer, op->reports)) {
- return OPERATOR_CANCELLED;
- }
-
- int *active_index = BKE_id_attributes_active_index_p(id);
- if (*active_index > 0) {
- *active_index -= 1;
- }
-
- DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
- WM_main_add_notifier(NC_GEOM | ND_DATA, id);
-
- return OPERATOR_FINISHED;
-}
-
-void GEOMETRY_OT_attribute_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Geometry Attribute";
- ot->description = "Remove attribute from geometry";
- ot->idname = "GEOMETRY_OT_attribute_remove";
-
- /* api callbacks */
- ot->exec = geometry_attribute_remove_exec;
- ot->poll = geometry_attributes_remove_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
new file mode 100644
index 00000000000..56ecd108bba
--- /dev/null
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -0,0 +1,385 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edgeometry
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_attribute.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_geometry_set.hh"
+#include "BKE_object_deform.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "ED_object.h"
+
+#include "geometry_intern.hh"
+
+namespace blender::ed::geometry {
+
+using fn::CPPType;
+using fn::GArray;
+using fn::GVArray;
+
+/*********************** Attribute Operators ************************/
+
+static bool geometry_attributes_poll(bContext *C)
+{
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
+ return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data)) &&
+ BKE_id_attributes_supported(data);
+}
+
+static bool geometry_attributes_remove_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
+ if (BKE_id_attributes_active_get(data) != nullptr) {
+ return true;
+ }
+
+ return false;
+}
+
+static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ if (C == nullptr) {
+ return DummyRNA_NULL_items;
+ }
+
+ Object *ob = ED_object_context(C);
+ if (ob == nullptr) {
+ return DummyRNA_NULL_items;
+ }
+
+ return rna_enum_attribute_domain_itemf(static_cast<ID *>(ob->data), false, r_free);
+}
+
+static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+
+ char name[MAX_NAME];
+ RNA_string_get(op->ptr, "name", name);
+ CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type");
+ AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain");
+ CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
+
+ if (layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_id_attributes_active_set(id, layer);
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+}
+
+void GEOMETRY_OT_attribute_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Geometry Attribute";
+ ot->description = "Add attribute to geometry";
+ ot->idname = "GEOMETRY_OT_attribute_add";
+
+ /* api callbacks */
+ ot->poll = geometry_attributes_poll;
+ ot->exec = geometry_attribute_add_exec;
+ ot->invoke = WM_operator_props_popup_confirm;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", "Attribute", MAX_NAME, "Name", "Name of new attribute");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "domain",
+ rna_enum_attribute_domain_items,
+ ATTR_DOMAIN_POINT,
+ "Domain",
+ "Type of element that attribute is stored on");
+ RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "data_type",
+ rna_enum_attribute_type_items,
+ CD_PROP_FLOAT,
+ "Data Type",
+ "Type of data stored in attribute");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+ CustomDataLayer *layer = BKE_id_attributes_active_get(id);
+
+ if (layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!BKE_id_attribute_remove(id, layer, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int *active_index = BKE_id_attributes_active_index_p(id);
+ if (*active_index > 0) {
+ *active_index -= 1;
+ }
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+}
+
+void GEOMETRY_OT_attribute_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Geometry Attribute";
+ ot->description = "Remove attribute from geometry";
+ ot->idname = "GEOMETRY_OT_attribute_remove";
+
+ /* api callbacks */
+ ot->exec = geometry_attribute_remove_exec;
+ ot->poll = geometry_attributes_remove_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+enum class ConvertAttributeMode {
+ Generic,
+ UVMap,
+ VertexGroup,
+ VertexColor,
+};
+
+static bool geometry_attribute_convert_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *data = static_cast<ID *>(ob->data);
+ if (GS(data->name) != ID_ME) {
+ return false;
+ }
+ CustomDataLayer *layer = BKE_id_attributes_active_get(data);
+ if (layer == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *ob_data = static_cast<ID *>(ob->data);
+ CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data);
+ const std::string name = layer->name;
+
+ const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>(
+ RNA_enum_get(op->ptr, "mode"));
+
+ Mesh *mesh = reinterpret_cast<Mesh *>(ob_data);
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+
+ /* General conversion steps are always the same:
+ * 1. Convert old data to right domain and data type.
+ * 2. Copy the data into a new array so that it does not depend on the old attribute anymore.
+ * 3. Delete the old attribute.
+ * 4. Create a new attribute based on the previously copied data. */
+ switch (mode) {
+ case ConvertAttributeMode::Generic: {
+ const AttributeDomain dst_domain = static_cast<AttributeDomain>(
+ RNA_enum_get(op->ptr, "domain"));
+ const CustomDataType dst_type = static_cast<CustomDataType>(
+ RNA_enum_get(op->ptr, "data_type"));
+
+ if (ELEM(dst_type, CD_PROP_STRING, CD_MLOOPCOL)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot convert to the selected type");
+ return OPERATOR_CANCELLED;
+ }
+
+ GVArray src_varray = mesh_component.attribute_get_for_read(name, dst_domain, dst_type);
+ const CPPType &cpp_type = src_varray.type();
+ void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__);
+ src_varray.materialize_to_uninitialized(new_data);
+ mesh_component.attribute_try_delete(name);
+ mesh_component.attribute_try_create(name, dst_domain, dst_type, AttributeInitMove(new_data));
+ break;
+ }
+ case ConvertAttributeMode::UVMap: {
+ MLoopUV *dst_uvs = static_cast<MLoopUV *>(
+ MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopUV), __func__));
+ VArray<float2> src_varray = mesh_component.attribute_get_for_read<float2>(
+ name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f});
+ for (const int i : IndexRange(mesh->totloop)) {
+ copy_v2_v2(dst_uvs[i].uv, src_varray[i]);
+ }
+ mesh_component.attribute_try_delete(name);
+ CustomData_add_layer_named(
+ &mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str());
+ break;
+ }
+ case ConvertAttributeMode::VertexColor: {
+ MLoopCol *dst_colors = static_cast<MLoopCol *>(
+ MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopCol), __func__));
+ VArray<ColorGeometry4f> src_varray = mesh_component.attribute_get_for_read<ColorGeometry4f>(
+ name, ATTR_DOMAIN_CORNER, ColorGeometry4f{0.0f, 0.0f, 0.0f, 1.0f});
+ for (const int i : IndexRange(mesh->totloop)) {
+ ColorGeometry4b encoded_color = src_varray[i].encode();
+ copy_v4_v4_uchar(&dst_colors[i].r, &encoded_color.r);
+ }
+ mesh_component.attribute_try_delete(name);
+ CustomData_add_layer_named(
+ &mesh->ldata, CD_MLOOPCOL, CD_ASSIGN, dst_colors, mesh->totloop, name.c_str());
+ break;
+ }
+ case ConvertAttributeMode::VertexGroup: {
+ Array<float> src_weights(mesh->totvert);
+ VArray<float> src_varray = mesh_component.attribute_get_for_read<float>(
+ name, ATTR_DOMAIN_POINT, 0.0f);
+ src_varray.materialize(src_weights);
+ mesh_component.attribute_try_delete(name);
+
+ bDeformGroup *defgroup = BKE_object_defgroup_new(ob, name.c_str());
+ const int defgroup_index = BLI_findindex(BKE_id_defgroup_list_get(&mesh->id), defgroup);
+ MDeformVert *dverts = BKE_object_defgroup_data_create(&mesh->id);
+ for (const int i : IndexRange(mesh->totvert)) {
+ const float weight = src_weights[i];
+ if (weight > 0.0f) {
+ BKE_defvert_add_index_notest(dverts + i, defgroup_index, weight);
+ }
+ }
+ break;
+ }
+ }
+
+ int *active_index = BKE_id_attributes_active_index_p(&mesh->id);
+ if (*active_index > 0) {
+ *active_index -= 1;
+ }
+
+ DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id);
+
+ return OPERATOR_FINISHED;
+}
+
+static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+
+ uiItemR(layout, op->ptr, "mode", 0, nullptr, ICON_NONE);
+
+ const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>(
+ RNA_enum_get(op->ptr, "mode"));
+
+ if (mode == ConvertAttributeMode::Generic) {
+ uiItemR(layout, op->ptr, "domain", 0, nullptr, ICON_NONE);
+ uiItemR(layout, op->ptr, "data_type", 0, nullptr, ICON_NONE);
+ }
+}
+
+static int geometry_attribute_convert_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ return WM_operator_props_dialog_popup(C, op, 300);
+}
+
+void GEOMETRY_OT_attribute_convert(wmOperatorType *ot)
+{
+ ot->name = "Convert Attribute";
+ ot->description = "Change how the attribute is stored";
+ ot->idname = "GEOMETRY_OT_attribute_convert";
+
+ ot->invoke = geometry_attribute_convert_invoke;
+ ot->exec = geometry_attribute_convert_exec;
+ ot->poll = geometry_attribute_convert_poll;
+ ot->ui = geometry_attribute_convert_ui;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ static EnumPropertyItem mode_items[] = {
+ {int(ConvertAttributeMode::Generic), "GENERIC", 0, "Generic", ""},
+ {int(ConvertAttributeMode::UVMap), "UV_MAP", 0, "UV Map", ""},
+ {int(ConvertAttributeMode::VertexGroup), "VERTEX_GROUP", 0, "Vertex Group", ""},
+ {int(ConvertAttributeMode::VertexColor), "VERTEX_COLOR", 0, "Vertex Color", ""},
+ {0, nullptr, 0, nullptr, nullptr},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_enum(
+ ot->srna, "mode", mode_items, static_cast<int>(ConvertAttributeMode::Generic), "Mode", "");
+
+ prop = RNA_def_enum(ot->srna,
+ "domain",
+ rna_enum_attribute_domain_items,
+ ATTR_DOMAIN_POINT,
+ "Domain",
+ "Which geometry element to move the attribute to");
+ RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf);
+
+ RNA_def_enum(
+ ot->srna, "data_type", rna_enum_attribute_type_items, CD_PROP_FLOAT, "Data Type", "");
+}
+
+} // namespace blender::ed::geometry
diff --git a/source/blender/editors/geometry/geometry_intern.h b/source/blender/editors/geometry/geometry_intern.hh
index 8a0f9294722..30a2a1d6eb1 100644
--- a/source/blender/editors/geometry/geometry_intern.h
+++ b/source/blender/editors/geometry/geometry_intern.hh
@@ -25,6 +25,11 @@
struct wmOperatorType;
-/* *** geometry_attributes.c *** */
+namespace blender::ed::geometry {
+
+/* *** geometry_attributes.cc *** */
void GEOMETRY_OT_attribute_add(struct wmOperatorType *ot);
void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot);
+void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot);
+
+} // namespace blender::ed::geometry
diff --git a/source/blender/editors/geometry/geometry_ops.c b/source/blender/editors/geometry/geometry_ops.cc
index ed0aeda731b..8933b2a7f00 100644
--- a/source/blender/editors/geometry/geometry_ops.c
+++ b/source/blender/editors/geometry/geometry_ops.cc
@@ -25,12 +25,15 @@
#include "ED_geometry.h"
-#include "geometry_intern.h"
+#include "geometry_intern.hh"
/**************************** registration **********************************/
void ED_operatortypes_geometry(void)
{
+ using namespace blender::ed::geometry;
+
WM_operatortype_append(GEOMETRY_OT_attribute_add);
WM_operatortype_append(GEOMETRY_OT_attribute_remove);
+ WM_operatortype_append(GEOMETRY_OT_attribute_convert);
}
diff --git a/source/blender/editors/gizmo_library/gizmo_library_intern.h b/source/blender/editors/gizmo_library/gizmo_library_intern.h
index a75a6b9a6ef..4a481f4bc59 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_intern.h
+++ b/source/blender/editors/gizmo_library/gizmo_library_intern.h
@@ -52,22 +52,19 @@ typedef struct GizmoInteraction {
float precision_offset;
} GizmoInteraction;
-float gizmo_offset_from_value(GizmoCommonData *data,
- const float value,
- const bool constrained,
- const bool inverted);
+float gizmo_offset_from_value(GizmoCommonData *data, float value, bool constrained, bool inverted);
float gizmo_value_from_offset(GizmoCommonData *data,
GizmoInteraction *inter,
- const float offset,
- const bool constrained,
- const bool inverted,
- const bool use_precision);
+ float offset,
+ bool constrained,
+ bool inverted,
+ bool use_precision);
void gizmo_property_data_update(struct wmGizmo *gz,
GizmoCommonData *data,
wmGizmoProperty *gz_prop,
- const bool constrained,
- const bool inverted);
+ bool constrained,
+ bool inverted);
void gizmo_property_value_reset(bContext *C,
const struct wmGizmo *gz,
@@ -76,7 +73,7 @@ void gizmo_property_value_reset(bContext *C,
/* -------------------------------------------------------------------- */
-void gizmo_color_get(const struct wmGizmo *gz, const bool highlight, float r_color[4]);
+void gizmo_color_get(const struct wmGizmo *gz, bool highlight, float r_color[4]);
/**
* Takes mouse coordinates and returns them in relation to the gizmo.
@@ -101,7 +98,7 @@ bool gizmo_window_project_3d(
* Main draw call for #GizmoGeomInfo data
*/
void wm_gizmo_geometryinfo_draw(const struct GizmoGeomInfo *info,
- const bool select,
+ bool select,
const float color[4]);
void wm_gizmo_vec_draw(
const float color[4], const float (*verts)[3], uint vert_count, uint pos, uint primitive_type);
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 3705ea38e11..ae00fc41f40 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -165,7 +165,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
immUniformColor3fvAlpha(ink, ink[3]);
immBegin(GPU_PRIM_POINTS, 1);
- immVertex2fv(pos, &pt->x);
+ immVertex2fv(pos, pt->m_xy);
}
else {
float oldpressure = points[0].pressure;
@@ -191,7 +191,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
if (fabsf(pt->pressure - oldpressure) > 0.2f) {
/* need to have 2 points to avoid immEnd assert error */
if (draw_points < 2) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
}
immEnd();
@@ -202,7 +202,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
/* need to roll-back one point to ensure that there are no gaps in the stroke */
if (i != 0) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
draw_points++;
}
@@ -210,12 +210,12 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
}
/* now the point we want */
- immVertex2fv(pos, &pt->x);
+ immVertex2fv(pos, pt->m_xy);
draw_points++;
}
/* need to have 2 points to avoid immEnd assert error */
if (draw_points < 2) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
}
}
@@ -227,14 +227,14 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
if ((sflag & GP_STROKE_USE_ARROW_END) &&
(runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) {
float end[2];
- copy_v2_fl2(end, points[1].x, points[1].y);
+ copy_v2_v2(end, points[1].m_xy);
annotation_draw_stroke_arrow_buffer(pos, end, runtime.arrow_end, runtime.arrow_end_style);
}
/* Draw starting arrow stroke. */
if ((sflag & GP_STROKE_USE_ARROW_START) &&
(runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) {
float start[2];
- copy_v2_fl2(start, points[0].x, points[0].y);
+ copy_v2_v2(start, points[0].m_xy);
annotation_draw_stroke_arrow_buffer(
pos, start, runtime.arrow_start, runtime.arrow_start_style);
}
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index fbc44ed58d8..e75e9314659 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -426,25 +426,25 @@ static void annotation_smooth_buffer(tGPsdata *p, float inf, int idx)
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- copy_v2_v2(a, &pta->x);
+ copy_v2_v2(a, pta->m_xy);
madd_v2_v2fl(sco, a, average_fac);
}
if (ptb) {
- copy_v2_v2(b, &ptb->x);
+ copy_v2_v2(b, ptb->m_xy);
madd_v2_v2fl(sco, b, average_fac);
}
if (ptc) {
- copy_v2_v2(c, &ptc->x);
+ copy_v2_v2(c, ptc->m_xy);
madd_v2_v2fl(sco, c, average_fac);
}
if (ptd) {
- copy_v2_v2(d, &ptd->x);
+ copy_v2_v2(d, ptd->m_xy);
madd_v2_v2fl(sco, d, average_fac);
}
/* Based on influence factor, blend between original and optimal smoothed coordinate */
interp_v2_v2v2(c, c, sco, inf);
- copy_v2_v2(&ptc->x, c);
+ copy_v2_v2(ptc->m_xy, c);
}
static void annotation_stroke_arrow_calc_points_segment(float stroke_points[8],
@@ -492,8 +492,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point,
case GP_STROKE_ARROWSTYLE_CLOSED:
mul_v2_fl(norm_dir, arrow_length);
if (point != NULL) {
- add_v2_v2(&point->x, norm_dir);
- copy_v2_v2(corner, &point->x);
+ add_v2_v2(point->m_xy, norm_dir);
+ copy_v2_v2(corner, point->m_xy);
}
annotation_stroke_arrow_calc_points_segment(stroke_points,
corner,
@@ -507,8 +507,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point,
case GP_STROKE_ARROWSTYLE_SQUARE:
mul_v2_fl(norm_dir, arrow_length * 1.5f);
if (point != NULL) {
- add_v2_v2(&point->x, norm_dir);
- copy_v2_v2(corner, &point->x);
+ add_v2_v2(point->m_xy, norm_dir);
+ copy_v2_v2(corner, point->m_xy);
}
annotation_stroke_arrow_calc_points_segment(stroke_points,
corner,
@@ -544,7 +544,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -560,7 +560,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -573,10 +573,10 @@ static short annotation_stroke_addpoint(tGPsdata *p,
if (gpd->runtime.sbuffer_sflag & (GP_STROKE_USE_ARROW_START | GP_STROKE_USE_ARROW_END)) {
/* Store start and end point coords for arrows. */
float end[2];
- copy_v2_v2(end, &pt->x);
+ copy_v2_v2(end, pt->m_xy);
pt = ((tGPspoint *)(gpd->runtime.sbuffer));
float start[2];
- copy_v2_v2(start, &pt->x);
+ copy_v2_v2(start, pt->m_xy);
/* Arrow end corner. */
if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) {
@@ -609,7 +609,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
pt->pressure = pressure;
/* Unused for annotations, but initialize for easier conversions to GP Object. */
pt->strength = 1.0f;
@@ -636,7 +636,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)gpd->runtime.sbuffer;
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -678,7 +678,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
}
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
+ annotation_stroke_convertcoords(p, pt->m_xy, &pts->x, NULL);
/* copy pressure and time */
pts->pressure = pt->pressure;
@@ -717,8 +717,8 @@ static void annotation_stroke_arrow_init_point(
{
/* NOTE: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */
const float real_co[2] = {co[co_idx], co[co_idx + 1]};
- copy_v2_v2(&ptc->x, real_co);
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ copy_v2_v2(ptc->m_xy, real_co);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
}
@@ -885,7 +885,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -903,7 +903,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
/* Convert screen-coordinates to appropriate coordinates (and store them). */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* Copy pressure and time. */
pt->pressure = ptc->pressure;
@@ -926,7 +926,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
/* End point. */
ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
/* Fill and convert arrow points to create arrow shape. */
@@ -947,7 +947,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
/* Start point. */
ptc = runtime.sbuffer;
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
/* Fill and convert arrow points to create arrow shape. */
@@ -961,7 +961,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -981,7 +981,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
const ViewDepths *depths = p->depths;
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) {
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
@@ -1041,7 +1041,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc;
i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -1132,7 +1132,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
gpencil_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
@@ -1174,7 +1174,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
gpencil_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
gpencil_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the eraser stroke */
+ /* Check that point segment of the bound-box of the eraser stroke. */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
@@ -1473,7 +1473,7 @@ static tGPsdata *annotation_session_initpaint(bContext *C)
return NULL;
}
- /* Radius for eraser circle is defined in userprefs */
+ /* Radius for eraser circle is defined in user-preferences. */
/* NOTE: we do this here, so that if we exit immediately,
* erase size won't get lost
*/
@@ -1811,7 +1811,7 @@ static void annotation_draw_stabilizer(bContext *C, int x, int y, void *p_ptr)
/* Rope Simple. */
immUniformColor4f(color[0], color[1], color[2], 0.8f);
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, pt->x + region->winrct.xmin, pt->y + region->winrct.ymin);
+ immVertex2f(pos, pt->m_xy[0] + region->winrct.xmin, pt->m_xy[1] + region->winrct.ymin);
immVertex2f(pos, x, y);
immEnd();
@@ -2575,8 +2575,7 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(
- p->area, RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy);
if (current_region) {
/* Assume that since we found the cursor in here, it is in bounds
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 6f63529298c..23b579b94f1 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -61,9 +61,12 @@
#include "WM_api.h"
+#include "GPU_batch.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
+#include "GPU_uniform_buffer.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
@@ -189,21 +192,27 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw,
};
immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE);
- immUniform2fv("Viewport", viewport);
- immUniform1f("pixsize", tgpw->rv3d->pixsize);
+
float obj_scale = tgpw->ob ?
(tgpw->ob->scale[0] + tgpw->ob->scale[1] + tgpw->ob->scale[2]) / 3.0f :
1.0f;
- immUniform1f("objscale", obj_scale);
+ struct GPencilStrokeData gpencil_stroke_data;
+ copy_v2_v2(gpencil_stroke_data.viewport, viewport);
+ gpencil_stroke_data.pixsize = tgpw->rv3d->pixsize;
+ gpencil_stroke_data.objscale = obj_scale;
int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
- immUniform1i("keep_size", keep_size);
- immUniform1f("pixfactor", tgpw->gpd->pixfactor);
+ gpencil_stroke_data.keep_size = keep_size;
+ gpencil_stroke_data.pixfactor = tgpw->gpd->pixfactor;
/* xray mode always to 3D space to avoid wrong zdepth calculation (T60051) */
- immUniform1i("xraymode", GP_XRAY_3DSPACE);
- immUniform1i("caps_start", (int)tgpw->gps->caps[0]);
- immUniform1i("caps_end", (int)tgpw->gps->caps[1]);
- immUniform1i("fill_stroke", (int)tgpw->is_fill_stroke);
+ gpencil_stroke_data.xraymode = GP_XRAY_3DSPACE;
+ gpencil_stroke_data.caps_start = tgpw->gps->caps[0];
+ gpencil_stroke_data.caps_end = tgpw->gps->caps[1];
+ gpencil_stroke_data.fill_stroke = tgpw->is_fill_stroke;
+
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(struct GPencilStrokeData), &gpencil_stroke_data, __func__);
+ immBindUniformBuf("gpencil_stroke_data", ubo);
/* draw stroke curve */
immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2);
@@ -255,6 +264,8 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw,
immEnd();
immUnbindProgram();
+
+ GPU_uniformbuf_free(ubo);
}
/* ----- Strokes Drawing ------ */
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index 046b3088360..3cc47198cbc 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -46,6 +46,8 @@
#include "WM_api.h"
+#include "DEG_depsgraph.h"
+
/* ***************************************** */
/* NOTE ABOUT THIS FILE:
* This file contains code for editing Grease Pencil data in the Action Editor
@@ -453,6 +455,9 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* get frame to copy data into (if no frame returned, then just ignore) */
gpf = BKE_gpencil_layer_frame_get(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW);
if (gpf) {
+ /* Ensure to use same keyframe type. */
+ gpf->key_type = gpfs->key_type;
+
bGPDstroke *gps, *gpsn;
/* This should be the right frame... as it may be a pre-existing frame,
@@ -479,6 +484,9 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* unapply offset from buffer-frame */
gpfs->framenum -= offset;
}
+
+ /* Tag destination datablock. */
+ DEG_id_tag_update(ale->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
/* clean up */
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index bea8126cfcc..916aa8184aa 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -1468,6 +1468,10 @@ static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEven
static int gpencil_layer_change_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (gpd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
bGPDlayer *gpl = NULL;
int layer_num = RNA_enum_get(op->ptr, "layer");
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 2a656ac3aad..e71a56894d0 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -3956,8 +3956,8 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
}
if (smooth_thickness) {
/* thickness need to repeat process several times */
- for (int r2 = 0; r2 < 20; r2++) {
- BKE_gpencil_stroke_smooth_thickness(gps, i, factor);
+ for (int r2 = 0; r2 < repeat * 2; r2++) {
+ BKE_gpencil_stroke_smooth_thickness(gps, i, 1.0f - factor);
}
}
if (smooth_uv) {
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index c3af28d4382..541b6673cb6 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1072,7 +1072,7 @@ static void gpencil_erase_processed_area(tGPDfill *tgpf)
/* First set in blue the perimeter. */
for (int i = 0; i < tgpf->sbuffer_used && point2D; i++, point2D++) {
- int image_idx = ibuf->x * (int)point2D->y + (int)point2D->x;
+ int image_idx = ibuf->x * (int)point2D->m_xy[1] + (int)point2D->m_xy[0];
set_pixel(ibuf, image_idx, blue_col);
}
@@ -1393,7 +1393,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf)
for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
int mval_i[2];
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, tgpf->depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
@@ -1437,9 +1437,9 @@ static int gpencil_points_from_stack(tGPDfill *tgpf)
while (!BLI_stack_is_empty(tgpf->stack)) {
int v[2];
BLI_stack_pop(tgpf->stack, &v);
- copy_v2fl_v2i(&point2D->x, v);
+ copy_v2fl_v2i(point2D->m_xy, v);
/* shift points to center of pixel */
- add_v2_fl(&point2D->x, 0.5f);
+ add_v2_fl(point2D->m_xy, 0.5f);
point2D->pressure = 1.0f;
point2D->strength = 1.0f;
point2D->time = 0.0f;
@@ -2108,8 +2108,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* first time the event is not enabled to show help lines. */
if ((tgpf->oldkey != -1) || (!help_lines)) {
- ARegion *region = BKE_area_find_region_xy(
- CTX_wm_area(C), RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ARegion *region = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->xy);
if (region) {
bool in_bounds = false;
/* Perform bounds check */
@@ -2126,7 +2125,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
tgpf->gps_mouse = BKE_gpencil_stroke_new(0, 1, 10.0f);
tGPspoint point2D;
bGPDspoint *pt = &tgpf->gps_mouse->points[0];
- copy_v2fl_v2i(&point2D.x, tgpf->mouse);
+ copy_v2fl_v2i(point2D.m_xy, tgpf->mouse);
gpencil_stroke_convertcoords_tpoint(
tgpf->scene, tgpf->region, tgpf->ob, &point2D, NULL, &pt->x);
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 601780ea651..0802b806060 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -322,7 +322,7 @@ void gpencil_apply_parent_point(struct Depsgraph *depsgraph,
* generic based on gpencil_point_to_xy_fl
*/
void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
- const short flag,
+ short flag,
const float pt[3],
float xy[2]);
@@ -410,7 +410,7 @@ int gpencil_delete_selected_point_wrap(bContext *C);
* \param gps: Stroke data
* \param subdivide: Number of times to subdivide
*/
-void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide);
+void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, int subdivide);
/* Layers Enums -------------------------------------- */
diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c
index 11e02b9832f..efe29e852f2 100644
--- a/source/blender/editors/gpencil/gpencil_mesh.c
+++ b/source/blender/editors/gpencil/gpencil_mesh.c
@@ -142,6 +142,9 @@ static bool gpencil_bake_ob_list(bContext *C, Depsgraph *depsgraph, Scene *scene
/* Add active object. In some files this could not be in selected array. */
Object *obact = CTX_data_active_object(C);
+ if (obact == NULL) {
+ return false;
+ }
if (obact->type == OB_MESH) {
elem = MEM_callocN(sizeof(GpBakeOb), __func__);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index dabe2050b28..79dda480a0a 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -54,6 +54,7 @@
#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_curve.h"
#include "BKE_gpencil_geom.h"
#include "BKE_layer.h"
#include "BKE_main.h"
@@ -493,7 +494,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit
/* Mouse movement in ints -> floats. */
if (gpd->runtime.sbuffer_used > 1) {
tGPspoint *pt_prev = pt - 1;
- sub_v2_v2v2(mvec, &pt->x, &pt_prev->x);
+ sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy);
normalize_v2(mvec);
/* Rotate mvec by 90 degrees... */
float angle = angle_v2v2(mvec, axis);
@@ -502,7 +503,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit
mvec[1] *= sin(angle);
/* Scale by displacement amount, and apply. */
- madd_v2_v2fl(&pt->x, mvec, amplitude * 10.0f);
+ madd_v2_v2fl(pt->m_xy, mvec, amplitude * 10.0f);
}
}
@@ -520,8 +521,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const
/* Apply to first point (only if there are 2 points because before no data to do it ) */
if (gpd->runtime.sbuffer_used == 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
+ sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy);
normalize_v2(mvec);
/* uses > 1.0f to get a smooth transition in first point */
@@ -533,8 +533,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const
/* apply from second point */
if (gpd->runtime.sbuffer_used >= 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
+ sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy);
normalize_v2(mvec);
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
@@ -581,25 +580,25 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx)
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- copy_v2_v2(a, &pta->x);
+ copy_v2_v2(a, pta->m_xy);
madd_v2_v2fl(sco, a, average_fac);
pressure += pta->pressure * average_fac;
strength += pta->strength * average_fac;
}
if (ptb) {
- copy_v2_v2(b, &ptb->x);
+ copy_v2_v2(b, ptb->m_xy);
madd_v2_v2fl(sco, b, average_fac);
pressure += ptb->pressure * average_fac;
strength += ptb->strength * average_fac;
}
if (ptc) {
- copy_v2_v2(c, &ptc->x);
+ copy_v2_v2(c, ptc->m_xy);
madd_v2_v2fl(sco, c, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
if (ptd) {
- copy_v2_v2(d, &ptd->x);
+ copy_v2_v2(d, ptd->m_xy);
madd_v2_v2fl(sco, d, average_fac);
pressure += ptd->pressure * average_fac;
strength += ptd->strength * average_fac;
@@ -609,7 +608,7 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx)
* for Guide mode. */
if (!guide->use_guide) {
interp_v2_v2v2(c, c, sco, inf);
- copy_v2_v2(&ptc->x, c);
+ copy_v2_v2(ptc->m_xy, c);
}
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
@@ -646,37 +645,37 @@ static void gpencil_smooth_segment(bGPdata *gpd, const float inf, int from_idx,
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- madd_v2_v2fl(sco, &pta->x, average_fac);
+ madd_v2_v2fl(sco, pta->m_xy, average_fac);
pressure += pta->pressure * average_fac;
strength += pta->strength * average_fac;
}
else {
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
if (ptb) {
- madd_v2_v2fl(sco, &ptb->x, average_fac);
+ madd_v2_v2fl(sco, ptb->m_xy, average_fac);
pressure += ptb->pressure * average_fac;
strength += ptb->strength * average_fac;
}
else {
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
- madd_v2_v2fl(sco, &ptd->x, average_fac);
+ madd_v2_v2fl(sco, ptd->m_xy, average_fac);
pressure += ptd->pressure * average_fac;
strength += ptd->strength * average_fac;
/* Based on influence factor, blend between original and optimal smoothed coordinate. */
- interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf);
+ interp_v2_v2v2(ptc->m_xy, ptc->m_xy, sco, inf);
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
@@ -738,7 +737,8 @@ static void gpencil_apply_randomness(tGPsdata *p,
/* Apply randomness to uv texture rotation. */
if ((brush_settings->uv_random > 0.0f) && (uv)) {
if ((brush_settings->flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) {
- float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used)) * 2.0f -
+ float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->m_xy[0], gpd->runtime.sbuffer_used)) *
+ 2.0f -
1.0f;
value = rand * M_PI_2 * brush_settings->uv_random;
}
@@ -778,7 +778,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -794,7 +794,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -825,7 +825,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt->strength = brush_settings->draw_strength;
pt->pressure = 1.0f;
pt->uv_rot = 0.0f;
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* pressure */
if (brush_settings->flag & GP_BRUSH_USE_PRESSURE) {
@@ -835,7 +835,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
/* color strength */
if (brush_settings->flag & GP_BRUSH_USE_STRENGTH_PRESSURE) {
pt->strength *= BKE_curvemapping_evaluateF(brush_settings->curve_strength, 0, pressure);
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
}
/* Set vertex colors for buffer. */
@@ -919,6 +919,19 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
return GP_STROKEADD_INVALID;
}
+static void gpencil_stroke_unselect(bGPdata *gpd, bGPDstroke *gps)
+{
+ gps->flag &= ~GP_STROKE_SELECT;
+ BKE_gpencil_stroke_select_index_reset(gps);
+ for (int i = 0; i < gps->totpoints; i++) {
+ gps->points[i].flag &= ~GP_SPOINT_SELECT;
+ }
+ /* Update the selection from the stroke to the curve. */
+ if (gps->editcurve) {
+ BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve);
+ }
+}
+
/* make a new stroke from the buffer data */
static void gpencil_stroke_newfrombuffer(tGPsdata *p)
{
@@ -929,6 +942,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
tGPspoint *ptc;
MDeformVert *dvert = NULL;
Brush *brush = p->brush;
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
ToolSettings *ts = p->scene->toolsettings;
Depsgraph *depsgraph = p->depsgraph;
Object *obact = (Object *)p->ownerPtr.data;
@@ -1013,11 +1027,11 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
/* Apply the vertex color to point. */
@@ -1047,11 +1061,11 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_used - 1);
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
pt->time = ptc->time;
/* Apply the vertex color to point. */
ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
@@ -1100,7 +1114,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
int i;
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) {
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
@@ -1171,12 +1185,12 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc;
i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f);
copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
pt->uv_fac = ptc->uv_fac;
@@ -1283,7 +1297,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* Join with existing strokes. */
if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) {
- if (gps->prev != NULL) {
+ if ((gps->prev != NULL) || (gps->next != NULL)) {
BKE_gpencil_stroke_boundingbox_calc(gps);
float diff_mat[4][4], ctrl1[2], ctrl2[2];
BKE_gpencil_layer_transform_matrix_get(depsgraph, p->ob, gpl, diff_mat);
@@ -1301,7 +1315,12 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
ctrl2,
GPENCIL_MINIMUM_JOIN_DIST,
&pt_index);
+
if (gps_target != NULL) {
+ /* Unselect all points of source and destination strokes. This is required to avoid
+ * a change in the resolution of the original strokes during the join. */
+ gpencil_stroke_unselect(gpd, gps);
+ gpencil_stroke_unselect(gpd, gps_target);
gps = ED_gpencil_stroke_join_and_trim(p->gpd, p->gpf, gps, gps_target, pt_index);
}
else {
@@ -1487,7 +1506,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
bGPDspoint pt_temp;
gpencil_point_to_parent_space(gps->points, p->diff_mat, &pt_temp);
gpencil_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
@@ -1512,7 +1531,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
@@ -1567,6 +1586,12 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
}
bGPDspoint npt;
+ gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
+ gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ gpencil_point_to_parent_space(pt2, p->diff_mat, &npt);
+ gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
+
if (pt0) {
gpencil_point_to_parent_space(pt0, p->diff_mat, &npt);
gpencil_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]);
@@ -1576,13 +1601,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
copy_v2_v2_int(pc0, pc1);
}
- gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
- gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
-
- gpencil_point_to_parent_space(pt2, p->diff_mat, &npt);
- gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
-
- /* Check that point segment of the boundbox of the eraser stroke */
+ /* Check that point segment of the bound-box of the eraser stroke. */
if (((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1])) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
@@ -2798,14 +2817,14 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy);
}
}
else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) &&
(gpd->runtime.sbuffer_used > 0)) {
pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy);
}
}
}
@@ -3303,8 +3322,7 @@ static void gpencil_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoi
/* angle vector of the brush with full thickness */
const float v0[2] = {cos(angle), sin(angle)};
- mvec[0] = pt->x - pt_prev->x;
- mvec[1] = pt->y - pt_prev->y;
+ sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy);
normalize_v2(mvec);
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
/* interpolate with previous point for smoother transitions */
@@ -3355,11 +3373,11 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
* for arc curve.
*/
float v_prev[2], v_cur[2], v_half[2];
- sub_v2_v2v2(v_cur, mval, &pt_prev->x);
+ sub_v2_v2v2(v_cur, mval, pt_prev->m_xy);
- sub_v2_v2v2(v_prev, &pt_prev->x, &pt_before->x);
- interp_v2_v2v2(v_half, &pt_prev->x, mval, 0.5f);
- sub_v2_v2(v_half, &pt_prev->x);
+ sub_v2_v2v2(v_prev, pt_prev->m_xy, pt_before->m_xy);
+ interp_v2_v2v2(v_half, pt_prev->m_xy, mval, 0.5f);
+ sub_v2_v2(v_half, pt_prev->m_xy);
/* If angle is too sharp undo all changes and return. */
const float min_angle = DEG2RADF(120.0f);
@@ -3378,14 +3396,14 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
/* Calc the position of the control point. */
float ctl[2];
- add_v2_v2v2(ctl, &pt_prev->x, v_prev);
+ add_v2_v2v2(ctl, pt_prev->m_xy, v_prev);
float step = M_PI_2 / (float)(segments + 1);
float a = step;
float midpoint[2], start[2], end[2], cp1[2], corner[2];
- mid_v2_v2v2(midpoint, &pt_prev->x, mval);
- copy_v2_v2(start, &pt_prev->x);
+ mid_v2_v2v2(midpoint, pt_prev->m_xy, mval);
+ copy_v2_v2(start, pt_prev->m_xy);
copy_v2_v2(end, mval);
copy_v2_v2(cp1, ctl);
@@ -3396,8 +3414,8 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
tGPspoint *pt_step = pt_prev;
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
- pt->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
+ pt->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
+ pt->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_prev->pressure;
@@ -3460,8 +3478,8 @@ static void gpencil_add_guide_points(const tGPsdata *p,
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- gpencil_rotate_v2_v2v2fl(&pt->x, start, p->guide.origin, -a);
- gpencil_snap_to_guide(p, guide, &pt->x);
+ gpencil_rotate_v2_v2v2fl(pt->m_xy, start, p->guide.origin, -a);
+ gpencil_snap_to_guide(p, guide, pt->m_xy);
a += step;
/* Set pressure and strength equals to previous. It will be smoothed later. */
@@ -3477,8 +3495,8 @@ static void gpencil_add_guide_points(const tGPsdata *p,
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- interp_v2_v2v2(&pt->x, start, end, a);
- gpencil_snap_to_guide(p, guide, &pt->x);
+ interp_v2_v2v2(pt->m_xy, start, end, a);
+ gpencil_snap_to_guide(p, guide, pt->m_xy);
a += step;
/* Set pressure and strength equals to previous. It will be smoothed later. */
@@ -3681,8 +3699,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(
- p->area, RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy);
if (current_region) {
/* Assume that since we found the cursor in here, it is in bounds
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 8157e9d8fe7..2715491414a 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -423,6 +423,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
Scene *scene = tgpi->scene;
char status_str[UI_MAX_DRAW_STR];
char msg_str[UI_MAX_DRAW_STR];
+ const int cur_subdiv = tgpi->type == GP_STROKE_BOX ? tgpi->tot_edges - 1 : tgpi->tot_edges - 2;
if (tgpi->type == GP_STROKE_LINE) {
BLI_strncpy(msg_str,
@@ -480,7 +481,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d) (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->start[0],
(int)tgpi->start[1],
(int)tgpi->end[0],
@@ -491,7 +492,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->end[0],
(int)tgpi->end[1]);
}
@@ -503,7 +504,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d) (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->start[0],
(int)tgpi->start[1],
(int)tgpi->end[0],
@@ -540,7 +541,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D
if (tgpi->tot_edges == 1) {
for (int j = 0; j < 4; j++) {
tGPspoint *p2d = &points2D[j];
- copy_v2_v2(&p2d->x, coords[j]);
+ copy_v2_v2(p2d->m_xy, coords[j]);
}
}
else {
@@ -550,7 +551,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D
float a = 0.0f;
for (int k = 0; k < tgpi->tot_edges; k++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2(&p2d->x, coords[j], coords[j + 1], a);
+ interp_v2_v2v2(p2d->m_xy, coords[j], coords[j + 1], a);
a += step;
i++;
}
@@ -581,7 +582,7 @@ static void gpencil_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, boo
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2(&p2d->x, tgpi->start, tgpi->end, a);
+ interp_v2_v2v2(p2d->m_xy, tgpi->start, tgpi->end, a);
a += step;
}
@@ -627,8 +628,8 @@ static void gpencil_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- p2d->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
- p2d->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
+ p2d->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
+ p2d->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
a += step;
}
float color[4];
@@ -663,7 +664,7 @@ static void gpencil_primitive_bezier(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2v2v2_cubic(&p2d->x, bcp1, bcp2, bcp3, bcp4, a);
+ interp_v2_v2v2v2v2_cubic(p2d->m_xy, bcp1, bcp2, bcp3, bcp4, a);
a += step;
}
float color[4];
@@ -697,8 +698,8 @@ static void gpencil_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- p2d->x = (center[0] + cosf(a) * radius[0]);
- p2d->y = (center[1] + sinf(a) * radius[1]);
+ p2d->m_xy[0] = (center[0] + cosf(a) * radius[0]);
+ p2d->m_xy[1] = (center[1] + sinf(a) * radius[1]);
a += step;
}
float color[4];
@@ -726,7 +727,6 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
const bool is_camera = is_lock_axis_view && (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth);
if (tgpi->type == GP_STROKE_BOX) {
- tgpi->tot_edges--;
gps->totpoints = (tgpi->tot_edges * 4 + tgpi->tot_stored_edges);
}
else {
@@ -801,7 +801,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
const ViewDepths *depths = tgpi->depths;
tGPspoint *ptc = &points2D[0];
for (int i = 0; i < gps->totpoints; i++, ptc++) {
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
@@ -894,7 +894,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* Store original points */
float tmp_xyp[2];
- copy_v2_v2(tmp_xyp, &p2d->x);
+ copy_v2_v2(tmp_xyp, p2d->m_xy);
/* calc pressure */
float curve_pressure = 1.0;
@@ -926,8 +926,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* vector */
float mvec[2], svec[2];
if (i > 0) {
- mvec[0] = (p2d->x - (p2d - 1)->x);
- mvec[1] = (p2d->y - (p2d - 1)->y);
+ sub_v2_v2v2(mvec, p2d->m_xy, (p2d - 1)->m_xy);
normalize_v2(mvec);
}
else {
@@ -942,7 +941,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
else {
mul_v2_fl(svec, fac);
}
- add_v2_v2(&p2d->x, svec);
+ add_v2_v2(p2d->m_xy, svec);
}
/* color strength */
@@ -992,7 +991,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
}
- copy_v2_v2(&tpt->x, &p2d->x);
+ copy_v2_v2(tpt->m_xy, p2d->m_xy);
tpt->pressure = pressure;
tpt->strength = strength;
@@ -1064,7 +1063,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
/* Restore original points */
- copy_v2_v2(&p2d->x, tmp_xyp);
+ copy_v2_v2(p2d->m_xy, tmp_xyp);
}
/* store cps and convert coords */
@@ -1254,7 +1253,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
tgpi->tot_stored_edges = 0;
tgpi->subdiv = RNA_int_get(op->ptr, "subdivision");
- RNA_int_set(op->ptr, "edges", tgpi->subdiv + 2);
+ RNA_int_set(op->ptr, "edges", tgpi->type == GP_STROKE_BOX ? tgpi->subdiv + 1 : tgpi->subdiv + 2);
tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
tgpi->flag = IDLE;
tgpi->lock_axis = ts->gp_sculpt.lock_axis;
@@ -1617,7 +1616,7 @@ static void gpencil_primitive_move(tGPDprimitive *tgpi, bool reset)
for (int i = 0; i < gps->totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- add_v2_v2(&p2d->x, move);
+ add_v2_v2(p2d->m_xy, move);
}
add_v2_v2(tgpi->start, move);
@@ -1720,7 +1719,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELUPMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges + 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1730,7 +1729,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELDOWNMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges - 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1886,7 +1885,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELUPMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges + 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
/* update screen */
@@ -1898,7 +1897,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELDOWNMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges - 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
/* update screen */
@@ -2038,15 +2037,8 @@ static void gpencil_primitive_common_props(wmOperatorType *ot, int subdiv, int t
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* Internal prop. */
- prop = RNA_def_int(ot->srna,
- "edges",
- MIN_EDGES,
- MIN_EDGES,
- MAX_EDGES,
- "Edges",
- "Number of points by edge",
- MIN_EDGES,
- MAX_EDGES);
+ prop = RNA_def_int(
+ ot->srna, "edges", 1, 1, MAX_EDGES, "Edges", "Number of points by edge", 1, MAX_EDGES);
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
RNA_def_enum(ot->srna, "type", gpencil_primitive_type, type, "Type", "Type of shape");
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 186c45c9f39..50c7202599a 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -1454,7 +1454,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
@@ -1492,7 +1492,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
gpencil_point_to_parent_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the selection stroke */
+ /* Check that point segment of the bound-box of the selection stroke. */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
diff --git a/source/blender/editors/gpencil/gpencil_trace.h b/source/blender/editors/gpencil/gpencil_trace.h
index 7c62288f65d..77fb823b3b6 100644
--- a/source/blender/editors/gpencil/gpencil_trace.h
+++ b/source/blender/editors/gpencil/gpencil_trace.h
@@ -91,7 +91,7 @@ void ED_gpencil_trace_bitmap_invert(const potrace_bitmap_t *bm);
*/
void ED_gpencil_trace_image_to_bitmap(struct ImBuf *ibuf,
const potrace_bitmap_t *bm,
- const float threshold);
+ float threshold);
/**
* Convert Potrace Bitmap to Grease Pencil strokes
@@ -106,7 +106,7 @@ void ED_gpencil_trace_data_to_strokes(struct Main *bmain,
struct Object *ob,
struct bGPDframe *gpf,
int32_t offset[2],
- const float scale,
- const float sample,
- const int32_t resolution,
- const int32_t thickness);
+ float scale,
+ float sample,
+ int32_t resolution,
+ int32_t thickness);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index f082af979a1..81a844cf6e1 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -870,7 +870,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
}
int mval_i[2];
- round_v2i_v2fl(mval_i, &point2D->x);
+ round_v2i_v2fl(mval_i, point2D->m_xy);
if ((depth != NULL) && (ED_view3d_autodist_simple(region, mval_i, r_out, 0, depth))) {
/* projecting onto 3D-Geometry
@@ -878,7 +878,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
*/
}
else {
- float mval_f[2] = {point2D->x, point2D->y};
+ float mval_f[2] = {UNPACK2(point2D->m_xy)};
float mval_prj[2];
float rvec[3], dvec[3];
float zfac;
@@ -2020,7 +2020,7 @@ static void gpencil_stroke_convertcoords(ARegion *region,
const float origin[3],
float out[3])
{
- float mval_f[2] = {(float)point2D->x, (float)point2D->y};
+ float mval_f[2] = {UNPACK2(point2D->m_xy)};
float mval_prj[2];
float rvec[3], dvec[3];
float zfac;
@@ -2808,8 +2808,8 @@ static void gpencil_sbuffer_vertex_color_random(
if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
- int ix = (int)(tpt->x * seed);
- int iy = (int)(tpt->y * seed);
+ int ix = (int)(tpt->m_xy[0] * seed);
+ int iy = (int)(tpt->m_xy[1] * seed);
int iz = ix + iy * seed;
float hsv[3];
float factor_value[3];
diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c
index 633e371cbd1..05304f9914f 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_paint.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c
@@ -441,12 +441,12 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso,
CLAMP_MIN(pt->vert_color[3], 0.0f);
}
else {
- /* Premult. */
+ /* Pre-multiply. */
mul_v3_fl(pt->vert_color, pt->vert_color[3]);
/* "Alpha over" blending. */
interp_v3_v3v3(pt->vert_color, pt->vert_color, gso->linear_color, inf);
pt->vert_color[3] = pt->vert_color[3] * (1.0 - inf) + inf;
- /* Un-premult. */
+ /* Un pre-multiply. */
if (pt->vert_color[3] > 0.0f) {
mul_v3_fl(pt->vert_color, 1.0f / pt->vert_color[3]);
}
@@ -460,12 +460,12 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso,
CLAMP_MIN(gps->vert_color_fill[3], 0.0f);
}
else {
- /* Premult. */
+ /* Pre-multiply. */
mul_v3_fl(gps->vert_color_fill, gps->vert_color_fill[3]);
/* "Alpha over" blending. */
interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, gso->linear_color, inf_fill);
gps->vert_color_fill[3] = gps->vert_color_fill[3] * (1.0 - inf_fill) + inf_fill;
- /* Un-premult. */
+ /* Un pre-multiply. */
if (gps->vert_color_fill[3] > 0.0f) {
mul_v3_fl(gps->vert_color_fill, 1.0f / gps->vert_color_fill[3]);
}
@@ -865,7 +865,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
@@ -905,7 +905,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
gpencil_point_to_parent_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the selection stroke */
+ /* Check that point segment of the bound-box of the selection stroke. */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c
index b3249294119..15f99d83f6d 100644
--- a/source/blender/editors/gpencil/gpencil_weight_paint.c
+++ b/source/blender/editors/gpencil/gpencil_weight_paint.c
@@ -432,7 +432,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
- /* do boundbox check first */
+ /* Do bound-box check first. */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
@@ -461,7 +461,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
gpencil_point_to_parent_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
- /* Check that point segment of the boundbox of the selection stroke */
+ /* Check that point segment of the bound-box of the selection stroke */
if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 8f2a189e35e..61dd0adc84d 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -55,6 +55,36 @@ typedef struct IMMDrawPixelsTexState {
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
/**
+ * Unlike the `immDrawPixelsTexTiled` functions, this doesn't do tiled drawing, but draws into a
+ * full texture.
+ *
+ * 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
+ *
+ * Unless <em>state->do_shader_unbind<em> is explicitly set to `false`, the shader is unbound when
+ * finished.
+ */
+void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state,
+ const float x,
+ const float y,
+ const int img_w,
+ const int img_h,
+ const eGPUTextureFormat gpu_format,
+ const bool use_filter,
+ const void *rect,
+ const float scaleX,
+ const float scaleY,
+ const float xzoom,
+ const float yzoom,
+ const float color[4]);
+
+/**
* #immDrawPixelsTex - Functions like a limited #glDrawPixels, but actually draws the
* image using textures, which can be tremendously faster on low-end
* cards, and also avoids problems with the raster position being
@@ -68,45 +98,45 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
* model-view and projection matrices are assumed to define a
* 1-to-1 mapping to screen space.
*/
-void immDrawPixelsTex(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float xzoom,
- float yzoom,
- const float color[4]);
-void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4]);
-void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float xzoom,
- float yzoom,
- const float color[4]);
+void immDrawPixelsTexTiled(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
+void immDrawPixelsTexTiled_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
+void immDrawPixelsTexTiled_scaling(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
/**
* Use the currently bound shader.
*
@@ -118,26 +148,26 @@ void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
*
* If color is NULL then use white by default
*
- * Be also aware that this function unbinds the shader when
- * it's finished.
+ * Unless <em>state->do_shader_unbind<em> is explicitly set to `false`, the shader is unbound when
+ * finished.
*/
-void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4]);
+void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4]);
/* Image buffer drawing functions, with display transform
*
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 0053bf5c865..7631bd35e79 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -94,7 +94,7 @@ struct EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm,
*/
float ED_armature_ebone_roll_to_vector(const struct EditBone *bone,
const float align_axis[3],
- const bool axis_only);
+ bool axis_only);
/**
* \param centermode: 0 == do center, 1 == center new, 2 == center cursor.
*
@@ -105,8 +105,8 @@ void ED_armature_origin_set(
/**
* 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);
+void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], bool do_props);
+void ED_armature_transform(struct bArmature *arm, const float mat[4][4], bool do_props);
/* armature_naming.c */
@@ -138,7 +138,7 @@ void ED_armature_bone_rename(struct Main *bmain,
void ED_armature_bones_flip_names(struct Main *bmain,
struct bArmature *arm,
struct ListBase *bones_names,
- const bool do_strip_numbers);
+ bool do_strip_numbers);
/* armature_ops.c */
@@ -203,7 +203,7 @@ bool ED_armature_edit_select_pick(
*
* \note Visibility checks must be done by the caller.
*/
-bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, const int sel_op);
+bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, int sel_op);
/* armature_skinning.c */
@@ -215,8 +215,8 @@ void ED_object_vgroup_calc_from_armature(struct ReportList *reports,
struct Scene *scene,
struct Object *ob,
struct Object *par,
- const int mode,
- const bool mirror);
+ int mode,
+ bool mirror);
/* editarmature_undo.c */
@@ -251,7 +251,7 @@ bool ED_armature_ebone_is_child_recursive(struct EditBone *ebone_parent,
* \return The shared parent or NULL.
*/
struct EditBone *ED_armature_ebone_find_shared_parent(struct EditBone *ebone_child[],
- const unsigned int ebone_child_tot);
+ 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]);
@@ -282,10 +282,10 @@ 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_free(struct ListBase *lb, bool do_id_user);
void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst,
struct ListBase *lb_src,
- const bool do_id_user);
+ bool do_id_user);
int ED_armature_ebone_selectflag_get(const struct EditBone *ebone);
void ED_armature_ebone_selectflag_set(struct EditBone *ebone, int flag);
@@ -353,14 +353,14 @@ void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer,
bool ED_pose_deselect_all_multi_ex(struct Base **bases,
uint bases_len,
int select_mode,
- const bool ignore_visibility);
-bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool ignore_visibility);
+ bool ignore_visibility);
+bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, 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);
+bool ED_pose_deselect_all(struct Object *ob, int select_mode, bool ignore_visibility);
void ED_pose_bone_select_tag_update(struct Object *ob);
/**
* Utility method for changing the selection status of a bone.
diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h
index 79404aada41..c3479c10d58 100644
--- a/source/blender/editors/include/ED_buttons.h
+++ b/source/blender/editors/include/ED_buttons.h
@@ -36,7 +36,7 @@ struct bContext;
* \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);
+bool ED_buttons_tab_has_search_result(struct SpaceProperties *sbuts, int index);
void ED_buttons_search_string_set(struct SpaceProperties *sbuts, const char *value);
int ED_buttons_search_string_length(struct SpaceProperties *sbuts);
@@ -48,7 +48,7 @@ bool ED_buttons_should_sync_with_outliner(const struct bContext *C,
void ED_buttons_set_context(const struct bContext *C,
struct SpaceProperties *sbuts,
PointerRNA *ptr,
- const int context);
+ int context);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 805d42b6fbc..a9225a5db60 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -100,7 +100,7 @@ void ED_curve_editfont_load(struct Object *obedit);
void ED_curve_editfont_make(struct Object *obedit);
void ED_curve_editfont_free(struct Object *obedit);
-void ED_text_to_object(struct bContext *C, const struct Text *text, const bool split_lines);
+void ED_text_to_object(struct bContext *C, const struct Text *text, bool split_lines);
void ED_curve_beztcpy(struct EditNurb *editnurb,
struct BezTriple *dst,
diff --git a/source/blender/editors/include/ED_file_indexer.h b/source/blender/editors/include/ED_file_indexer.h
index 0afa8819def..3b19a738b90 100644
--- a/source/blender/editors/include/ED_file_indexer.h
+++ b/source/blender/editors/include/ED_file_indexer.h
@@ -146,7 +146,7 @@ void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries);
void ED_file_indexer_entries_extend_from_datablock_infos(
FileIndexerEntries *indexer_entries,
const LinkNode * /* BLODataBlockInfo */ datablock_infos,
- const int idcode);
+ int idcode);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 460de58bdb2..0528057fb54 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -127,7 +127,7 @@ void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile);
*/
void ED_fileselect_params_to_userdef(struct SpaceFile *sfile,
const int temp_win_size[2],
- const bool is_maximized);
+ bool is_maximized);
void ED_fileselect_init_layout(struct SpaceFile *sfile, struct ARegion *region);
@@ -171,9 +171,7 @@ void ED_fileselect_activate_asset_catalog(const struct SpaceFile *sfile, bUUID c
* 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);
+void ED_fileselect_activate_by_id(struct SpaceFile *sfile, struct ID *asset_id, bool deferred);
void ED_fileselect_deselect_all(struct SpaceFile *sfile);
void ED_fileselect_activate_by_relpath(struct SpaceFile *sfile, const char *relative_path);
@@ -256,7 +254,7 @@ char *ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry);
void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name);
int ED_fsmenu_entry_get_icon(struct FSMenuEntry *fsentry);
-void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, const int icon);
+void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, int icon);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 55beff40177..8d4177faa0c 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -65,7 +65,7 @@ void ED_gizmo_draw_preset_circle(const struct wmGizmo *gz,
void ED_gizmo_draw_preset_facemap(const struct bContext *C,
const struct wmGizmo *gz,
struct Object *ob,
- const int facemap,
+ int facemap,
int select_id);
/* -------------------------------------------------------------------- */
@@ -97,13 +97,13 @@ enum {
*
* \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);
+void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, float min, 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);
+void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, float range_fac);
/* -------------------------------------------------------------------- */
/* Cage Gizmo */
@@ -248,9 +248,9 @@ struct Dial3dParams {
};
void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
const float matrix_final[4][4],
- const float line_width,
+ float line_width,
const float color[4],
- const bool select,
+ bool select,
struct Dial3dParams *params);
/* snap3d_gizmo.c */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 99164bbe439..919ea3e4a6b 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -94,7 +94,7 @@ typedef enum eGP_TargetObjectMode {
*/
typedef struct tGPspoint {
/** Coordinates x and y of cursor (in relative to area). */
- float x, y;
+ float m_xy[2];
/** Pressure of tablet at this point. */
float pressure;
/** Pressure of tablet at this point for alpha factor. */
@@ -193,7 +193,7 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr
/* ----------- 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);
+bool ED_gpencil_layer_has_selected_stroke(const struct bGPDlayer *gpl, bool is_multiedit);
/**
* Check whether given stroke can be edited given the supplied context.
@@ -250,12 +250,8 @@ void ED_annotation_draw_view3d(struct Scene *scene,
struct View3D *v3d,
struct ARegion *region,
bool only3d);
-void ED_annotation_draw_ex(struct Scene *scene,
- struct bGPdata *gpd,
- int winx,
- int winy,
- const int cfra,
- const char spacetype);
+void ED_annotation_draw_ex(
+ struct Scene *scene, struct bGPdata *gpd, int winx, int winy, int cfra, char spacetype);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
/**
@@ -315,7 +311,7 @@ void ED_gpencil_layer_frames_duplicate(struct bGPDlayer *gpl);
void ED_gpencil_layer_merge(struct bGPdata *gpd,
struct bGPDlayer *gpl_src,
struct bGPDlayer *gpl_dst,
- const bool reverse);
+ bool reverse);
/**
* Set keyframe type for selected frames from given gp-layer
@@ -348,14 +344,14 @@ 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);
+bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, 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. */
+int ED_undo_gpencil_step(struct bContext *C, int step); /* eUndoStepDir. */
/* ------------ Grease-Pencil Armature ------------------ */
bool ED_gpencil_add_armature(const struct bContext *C,
@@ -410,7 +406,7 @@ void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y);
*/
void ED_gpencil_stroke_init_data(struct bGPDstroke *gps,
const float *array,
- const int totpoints,
+ int totpoints,
const float mat[4][4]);
/**
@@ -457,7 +453,7 @@ void ED_gpencil_project_stroke_to_plane(const struct Scene *scene,
struct bGPDlayer *gpl,
struct bGPDstroke *gps,
const float origin[3],
- const int axis);
+ int axis);
/**
* Reproject given point to a plane locked to axis to avoid stroke offset
* \param pt: Point to affect (used for input & output).
@@ -467,7 +463,7 @@ void ED_gpencil_project_point_to_plane(const struct Scene *scene,
struct bGPDlayer *gpl,
const struct RegionView3D *rv3d,
const float origin[3],
- const int axis,
+ int axis,
struct bGPDspoint *pt);
/**
* Get drawing reference point for conversion or projection of the stroke
@@ -490,8 +486,8 @@ void ED_gpencil_stroke_reproject(struct Depsgraph *depsgraph,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
- const eGP_ReprojectModes mode,
- const bool keep_original);
+ eGP_ReprojectModes mode,
+ bool keep_original);
/**
* Turn brush cursor in on/off.
@@ -513,7 +509,7 @@ void ED_gpencil_vgroup_remove(struct bContext *C, struct Object *ob);
*/
void ED_gpencil_vgroup_select(struct bContext *C, struct Object *ob);
/**
- * Unselect points of vertex group.
+ * Un-select points of vertex group.
*/
void ED_gpencil_vgroup_deselect(struct bContext *C, struct Object *ob);
@@ -552,7 +548,7 @@ int ED_gpencil_select_stroke_segment(struct bGPdata *gpd,
struct bGPDspoint *pt,
bool select,
bool insert,
- const float scale,
+ float scale,
float r_hita[3],
float r_hitb[3]);
@@ -566,7 +562,7 @@ void ED_gpencil_select_curve_toggle_all(struct bContext *C, int action);
struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array,
int *buffer_size,
int *buffer_used,
- const bool clear);
+ bool clear);
void ED_gpencil_sbuffer_update_eval(struct bGPdata *gpd, struct Object *ob_eval);
/**
@@ -600,7 +596,7 @@ void ED_gpencil_init_random_settings(struct Brush *brush,
bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc,
struct bGPDstroke *gps,
const float mouse[2],
- const int radius,
+ int radius,
const float diff_mat[4][4]);
/**
* Check if a point is inside of the stroke.
@@ -631,7 +627,7 @@ struct bGPDstroke *ED_gpencil_stroke_nearest_to_ends(struct bContext *C,
struct bGPDstroke *gps,
const float ctrl1[2],
const float ctrl2[2],
- const float radius,
+ float radius,
int *r_index);
/**
* Get extremes of stroke in 2D using current view.
@@ -649,12 +645,12 @@ 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);
+ 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);
+void ED_gpencil_stroke_close_by_distance(struct bGPDstroke *gps, float threshold);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 3308ae2c178..3c1b8e4ecc1 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -38,24 +38,24 @@ struct Main;
struct ReportList;
struct Scene;
struct SpaceImage;
+struct View2D;
struct bContext;
struct wmOperator;
struct wmWindowManager;
-struct View2D;
/* image_draw.c */
-float ED_space_image_zoom_level(const struct View2D *v2d, const int grid_dimension);
+float ED_space_image_zoom_level(const struct View2D *v2d, int grid_dimension);
void ED_space_image_grid_steps(struct SpaceImage *sima,
float grid_steps[SI_GRID_STEPS_LEN],
- const int grid_dimension);
+ 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,
+float ED_space_image_increment_snap_value(int grid_dimesnions,
const float grid_steps[SI_GRID_STEPS_LEN],
- const float zoom_factor);
+ float zoom_factor);
/* image_edit.c, exported for transform. */
@@ -198,7 +198,7 @@ typedef struct ImageFrameRange {
*/
ListBase ED_image_filesel_detect_sequences(struct Main *bmain,
struct wmOperator *op,
- const bool detect_udim);
+ bool detect_udim);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index bafe68bd28d..f006378658b 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -93,6 +93,13 @@ typedef enum eEditKeyframes_Snap {
SNAP_KEYS_TIME,
} eEditKeyframes_Snap;
+/* equalizing tools */
+typedef enum eEditKeyframes_Equalize {
+ EQUALIZE_HANDLES_LEFT = (1 << 0),
+ EQUALIZE_HANDLES_RIGHT = (1 << 1),
+ EQUALIZE_HANDLES_BOTH = (EQUALIZE_HANDLES_LEFT | EQUALIZE_HANDLES_RIGHT),
+} eEditKeyframes_Equalize;
+
/* mirroring tools */
typedef enum eEditKeyframes_Mirror {
MIRROR_KEYS_CURFRAME = 1,
@@ -259,6 +266,18 @@ short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb);
/**
+ * Sets selected keyframes' bezier handles to an equal length and optionally makes
+ * the keyframes' handles horizontal.
+ * \param handle_length: Desired handle length, must be positive.
+ * \param flatten: Makes the keyframes' handles the same value as the keyframe,
+ * flattening the curve at that point.
+ */
+void ANIM_fcurve_equalize_keyframes_loop(struct FCurve *fcu,
+ eEditKeyframes_Equalize mode,
+ float handle_length,
+ bool flatten);
+
+/**
* Function for working with any type (i.e. one of the known types) of animation channel.
*/
short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
@@ -327,13 +346,13 @@ KeyframeEditFunc ANIM_editkeyframes_easing(short mode);
/**
* Get a callback to populate the selection settings map
- * requires: ked->custom = char[] of length fcurve->totvert.
+ * 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.
+ * requires: `ked->custom = char[]` of length `fcurve->totvert`.
*/
short bezt_selmap_flush(KeyframeEditData *ked, struct BezTriple *bezt);
@@ -380,10 +399,26 @@ bool delete_fcurve_keys(struct FCurve *fcu);
void clear_fcurve_keys(struct FCurve *fcu);
void duplicate_fcurve_keys(struct FCurve *fcu);
+typedef struct FCurveSegment {
+ struct FCurveSegment *next, *prev;
+ int start_index, length;
+} FCurveSegment;
+
+/**
+ * Return a list of #FCurveSegment with a start index and a length.
+ * A segment is a continuous selection of keyframes.
+ * Keys that have BEZT_FLAG_IGNORE_TAG set are treated as unselected.
+ * The caller is responsible for freeing the memory.
+ */
+ListBase find_fcurve_segments(struct FCurve *fcu);
void clean_fcurve(struct bAnimContext *ac,
struct bAnimListElem *ale,
float thresh,
bool cleardefault);
+void blend_to_neighbor_fcurve_segment(struct FCurve *fcu,
+ struct FCurveSegment *segment,
+ float factor);
+void breakdown_fcurve_segment(struct FCurve *fcu, struct FCurveSegment *segment, float factor);
bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max);
/**
* Use a weighted moving-means method to reduce intensity of fluctuations.
@@ -397,8 +432,8 @@ void ANIM_fcurves_copybuf_free(void);
short copy_animedit_keys(struct bAnimContext *ac, ListBase *anim_data);
short paste_animedit_keys(struct bAnimContext *ac,
ListBase *anim_data,
- const eKeyPasteOffset offset_mode,
- const eKeyMergeMode merge_mode,
+ eKeyPasteOffset offset_mode,
+ eKeyMergeMode merge_mode,
bool flip);
/* ************************************************ */
diff --git a/source/blender/editors/include/ED_keyframes_keylist.h b/source/blender/editors/include/ED_keyframes_keylist.h
index 4194444ca0f..36a30bd5ee6 100644
--- a/source/blender/editors/include/ED_keyframes_keylist.h
+++ b/source/blender/editors/include/ED_keyframes_keylist.h
@@ -140,12 +140,9 @@ typedef enum eKeyframeExtremeDrawOpts {
struct AnimKeylist *ED_keylist_create(void);
void ED_keylist_free(struct AnimKeylist *keylist);
void ED_keylist_prepare_for_direct_access(struct AnimKeylist *keylist);
-const struct ActKeyColumn *ED_keylist_find_exact(const struct AnimKeylist *keylist,
- const float cfra);
-const struct ActKeyColumn *ED_keylist_find_next(const struct AnimKeylist *keylist,
- const float cfra);
-const struct ActKeyColumn *ED_keylist_find_prev(const struct AnimKeylist *keylist,
- const float cfra);
+const struct ActKeyColumn *ED_keylist_find_exact(const struct AnimKeylist *keylist, float cfra);
+const struct ActKeyColumn *ED_keylist_find_next(const struct AnimKeylist *keylist, float cfra);
+const struct ActKeyColumn *ED_keylist_find_prev(const struct AnimKeylist *keylist, float cfra);
const struct ActKeyColumn *ED_keylist_find_any_between(const struct AnimKeylist *keylist,
const Range2f frame_range);
bool ED_keylist_is_empty(const struct AnimKeylist *keylist);
@@ -160,41 +157,39 @@ int64_t ED_keylist_array_len(const struct AnimKeylist *keylist);
void fcurve_to_keylist(struct AnimData *adt,
struct FCurve *fcu,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Action Group */
void agroup_to_keylist(struct AnimData *adt,
struct bActionGroup *agrp,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Action */
void action_to_keylist(struct AnimData *adt,
struct bAction *act,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Object */
void ob_to_keylist(struct bDopeSheet *ads,
struct Object *ob,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Cache File */
void cachefile_to_keylist(struct bDopeSheet *ads,
struct CacheFile *cache_file,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* Scene */
void scene_to_keylist(struct bDopeSheet *ads,
struct Scene *sce,
struct AnimKeylist *keylist,
- const int saction_flag);
+ int saction_flag);
/* DopeSheet Summary */
-void summary_to_keylist(struct bAnimContext *ac,
- struct AnimKeylist *keylist,
- const int saction_flag);
+void summary_to_keylist(struct bAnimContext *ac, struct AnimKeylist *keylist, int saction_flag);
/* Grease Pencil datablock summary */
void gpencil_to_keylist(struct bDopeSheet *ads,
struct bGPdata *gpd,
struct AnimKeylist *keylist,
- const bool active);
+ bool active);
/* Grease Pencil Layer */
void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct AnimKeylist *keylist);
/* Mask */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index d539c7b688c..8d89555c732 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -62,7 +62,7 @@ struct NlaKeyframingContext;
* \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);
+eInsertKeyFlags ANIM_get_keyframing_flags(struct Scene *scene, bool use_autokey_mode);
/* -------- */
@@ -81,15 +81,13 @@ struct FCurve *ED_action_fcurve_ensure(struct Main *bmain,
const char group[],
struct PointerRNA *ptr,
const char rna_path[],
- const int array_index);
+ 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);
+struct FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], int array_index);
/* -------- */
@@ -449,11 +447,11 @@ typedef enum eDriverFCurveCreationMode {
*/
struct FCurve *verify_driver_fcurve(struct ID *id,
const char rna_path[],
- const int array_index,
+ int array_index,
eDriverFCurveCreationMode creation_mode);
struct FCurve *alloc_driver_fcurve(const char rna_path[],
- const int array_index,
+ int array_index,
eDriverFCurveCreationMode creation_mode);
/* -------- */
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index dc800d78007..3d779fd14ef 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -43,7 +43,7 @@ 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);
-bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len);
+bool ED_lattice_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool ED_lattice_deselect_all_multi(struct bContext *C);
/* editlattice_undo.c */
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 3aab6882dc2..1a4c36acff9 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -79,7 +79,7 @@ bool ED_mask_selected_minmax(const struct bContext *C,
/* mask_draw.c */
-void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type);
+void ED_mask_draw(const struct bContext *C, char draw_flag, char draw_type);
/**
* Sets up the opengl context.
* width, height are to match the values from #ED_mask_get_size().
@@ -87,26 +87,25 @@ void ED_mask_draw(const struct bContext *C, const char draw_flag, const char dra
void ED_mask_draw_region(struct Depsgraph *depsgraph,
struct Mask *mask,
struct ARegion *region,
- const char draw_flag,
- const char draw_type,
- const eMaskOverlayMode overlay_mode,
- const int width_i,
- const int height_i,
- const float aspx,
- const float aspy,
- const bool do_scale_applied,
- const bool do_draw_cb,
+ char draw_flag,
+ char draw_type,
+ eMaskOverlayMode overlay_mode,
+ int width_i,
+ int height_i,
+ float aspx,
+ float aspy,
+ bool do_scale_applied,
+ bool do_draw_cb,
float stabmat[4][4],
const struct bContext *C);
-void ED_mask_draw_frames(
- struct Mask *mask, struct ARegion *region, const int cfra, const int sfra, const int efra);
+void ED_mask_draw_frames(struct Mask *mask, struct ARegion *region, int cfra, int sfra, 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);
+void ED_mask_layer_shape_auto_key(struct MaskLayer *mask_layer, int frame);
+bool ED_mask_layer_shape_auto_key_all(struct Mask *mask, int frame);
+bool ED_mask_layer_shape_auto_key_select(struct Mask *mask, int frame);
/* ----------- Mask AnimEdit API ------------------ */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 35838f4ce48..0721aa21a16 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -60,30 +60,30 @@ struct wmOperator;
/* editmesh_utils.c */
/**
- * \param em: Editmesh.
- * \param use_self: Allow a vertex to point to its self (middle verts).
+ * \param em: Edit-mesh used for generating mirror data.
+ * \param use_self: Allow a vertex to point to itself (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
+ * \param r_index: Optional array to write into, as an alternative to a custom-data layer
* (length of total verts).
*/
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em,
- const int axis,
- const bool use_self,
- const bool use_select,
- const bool respecthide,
- const bool use_topology,
+ int axis,
+ bool use_self,
+ bool use_select,
+ bool respecthide,
+ bool use_topology,
float maxdist,
int *r_index);
void EDBM_verts_mirror_cache_begin(struct BMEditMesh *em,
- const int axis,
- const bool use_self,
- const bool use_select,
- const bool respecthide,
- const bool use_topology);
-void EDBM_verts_mirror_apply(struct BMEditMesh *em, const int sel_from, const int sel_to);
+ int axis,
+ bool use_self,
+ bool use_select,
+ bool respecthide,
+ bool use_topology);
+void EDBM_verts_mirror_apply(struct BMEditMesh *em, int sel_from, int sel_to);
struct BMVert *EDBM_verts_mirror_get(struct BMEditMesh *em, struct BMVert *v);
struct BMEdge *EDBM_verts_mirror_get_edge(struct BMEditMesh *em, struct BMEdge *e);
struct BMFace *EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace *f);
@@ -96,7 +96,7 @@ void EDBM_mesh_normals_update(struct BMEditMesh *em);
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);
+void EDBM_mesh_make(struct Object *ob, int select_mode, bool add_key_index);
/**
* Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data.
*/
@@ -115,10 +115,10 @@ void EDBM_mesh_load(struct Main *bmain, struct Object *ob);
* edges select/deselect faces and vertices, and in face select mode faces select/deselect
* 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);
+void EDBM_select_more(struct BMEditMesh *em, bool use_face_step);
+void EDBM_select_less(struct BMEditMesh *em, bool use_face_step);
-void EDBM_selectmode_flush_ex(struct BMEditMesh *em, const short selectmode);
+void EDBM_selectmode_flush_ex(struct BMEditMesh *em, short selectmode);
void EDBM_selectmode_flush(struct BMEditMesh *em);
void EDBM_deselect_flush(struct BMEditMesh *em);
@@ -145,17 +145,17 @@ 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);
+void EDBM_update_extern(struct Mesh *me, bool do_tessellation, 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,
- const bool uv_selected,
- const bool use_winding,
- const bool do_islands);
+ bool face_selected,
+ bool uv_selected,
+ bool use_winding,
+ bool do_islands);
void BM_uv_element_map_free(struct UvElementMap *element_map);
struct UvElement *BM_uv_element_get(struct UvElementMap *map,
struct BMFace *efa,
@@ -169,21 +169,17 @@ 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);
+struct BMFace *EDBM_uv_active_face_get(struct BMEditMesh *em, bool sloppy, 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);
+struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm, bool use_select, bool use_winding);
-void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag);
-void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
+void EDBM_flag_enable_all(struct BMEditMesh *em, char hflag);
+void EDBM_flag_disable_all(struct BMEditMesh *em, char hflag);
bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
struct BMEdge *e,
@@ -200,13 +196,9 @@ void EDBM_project_snap_verts(struct bContext *C,
/* 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,
- const bool split_faces,
- const bool update,
- const char hflag,
- const float dist);
+void EDBM_automerge(struct Object *ob, bool update, char hflag, float dist);
+void EDBM_automerge_and_split(
+ struct Object *ob, bool split_edges, bool split_faces, bool update, char hflag, float dist);
/* editmesh_undo.c */
@@ -217,8 +209,8 @@ void ED_mesh_undosys_type(struct UndoType *ut);
void EDBM_select_mirrored(struct BMEditMesh *em,
const struct Mesh *me,
- const int axis,
- const bool extend,
+ int axis,
+ bool extend,
int *r_totmirr,
int *r_totfail);
@@ -235,7 +227,7 @@ void EDBM_select_mirrored(struct BMEditMesh *em,
*/
struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan_p,
- const bool use_select_bias,
+ bool use_select_bias,
bool use_cycle,
struct Base **bases,
uint bases_len,
@@ -245,7 +237,7 @@ struct BMVert *EDBM_vert_find_nearest(struct ViewContext *vc, float *dist_px_man
struct BMEdge *EDBM_edge_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan,
float *r_dist_center,
- const bool use_select_bias,
+ bool use_select_bias,
bool use_cycle,
struct BMEdge **r_eed_zbuf,
struct Base **bases,
@@ -263,8 +255,8 @@ struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *dist_px_man
struct BMFace *EDBM_face_find_nearest_ex(struct ViewContext *vc,
float *dist_px_manhattan,
float *r_dist_center,
- const bool use_zbuf_single_px,
- const bool use_select_bias,
+ bool use_zbuf_single_px,
+ bool use_select_bias,
bool use_cycle,
struct BMFace **r_efa_zbuf,
struct Base **bases,
@@ -274,7 +266,7 @@ struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, float *dist_px_man
bool EDBM_unified_findnearest(struct ViewContext *vc,
struct Base **bases,
- const uint bases_len,
+ uint bases_len,
int *r_base_index,
struct BMVert **r_eve,
struct BMEdge **r_eed,
@@ -282,7 +274,7 @@ bool EDBM_unified_findnearest(struct ViewContext *vc,
bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc,
struct Base **bases,
- const uint bases_len,
+ uint bases_len,
bool use_boundary_vertices,
bool use_boundary_edges,
int *r_base_index_vert,
@@ -314,22 +306,17 @@ void EDBM_selectmode_set(struct BMEditMesh *em);
* - face -> vert
* - edge -> vert
*/
-void EDBM_selectmode_convert(struct BMEditMesh *em,
- const short selectmode_old,
- const short selectmode_new);
+void EDBM_selectmode_convert(struct BMEditMesh *em, short selectmode_old, short selectmode_new);
/**
* User access this.
*/
-bool EDBM_selectmode_set_multi(struct bContext *C, const short selectmode);
+bool EDBM_selectmode_set_multi(struct bContext *C, 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);
+bool EDBM_selectmode_toggle_multi(
+ struct bContext *C, short selectmode_new, int action, bool use_extend, bool use_expand);
/**
* Use to disable a select-mode if its enabled, Using another mode as a fallback
@@ -339,10 +326,10 @@ bool EDBM_selectmode_toggle_multi(struct bContext *C,
*/
bool EDBM_selectmode_disable(struct Scene *scene,
struct BMEditMesh *em,
- const short selectmode_disable,
- const short selectmode_fallback);
+ short selectmode_disable,
+ short selectmode_fallback);
-bool EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const bool select);
+bool EDBM_deselect_by_material(struct BMEditMesh *em, short index, bool select);
void EDBM_select_toggle_all(struct BMEditMesh *em);
@@ -350,16 +337,16 @@ void EDBM_select_swap(struct BMEditMesh *em); /* exported for UV */
bool EDBM_select_interior_faces(struct BMEditMesh *em);
void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); /* rename? */
-bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len);
+bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool EDBM_mesh_deselect_all_multi(struct bContext *C);
bool EDBM_selectmode_disable_multi_ex(struct Scene *scene,
struct Base **bases,
- const uint bases_len,
- const short selectmode_disable,
- const short selectmode_fallback);
+ uint bases_len,
+ short selectmode_disable,
+ short selectmode_fallback);
bool EDBM_selectmode_disable_multi(struct bContext *C,
- const short selectmode_disable,
- const short selectmode_fallback);
+ short selectmode_disable,
+ short selectmode_fallback);
/* editmesh_preselect_edgering.c */
struct EditMesh_PreSelEdgeRing;
@@ -429,11 +416,11 @@ bool paintface_deselect_all_visible(struct bContext *C,
void paintface_select_linked(struct bContext *C,
struct Object *ob,
const int mval[2],
- const bool select);
+ bool select);
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);
+void paintface_hide(struct bContext *C, struct Object *ob, bool unselected);
+void paintface_reveal(struct bContext *C, struct Object *ob, bool select);
/**
* \note if the caller passes false to flush_flags,
@@ -463,7 +450,7 @@ bool ED_mesh_mirrtopo_recalc_check(struct BMEditMesh *em,
void ED_mesh_mirrtopo_init(struct BMEditMesh *em,
struct Mesh *me,
MirrTopoStore_t *mesh_topo_store,
- const bool skip_em_vert_array_init);
+ bool skip_em_vert_array_init);
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
/* object_vgroup.c */
@@ -476,7 +463,7 @@ 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);
+void ED_vgroup_data_clamp_range(struct ID *id, int total);
/**
* Matching index only.
*/
@@ -484,7 +471,7 @@ 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);
+ 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.
@@ -494,9 +481,9 @@ bool ED_vgroup_parray_alloc(struct ID *id,
*/
void ED_vgroup_parray_mirror_sync(struct Object *ob,
struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
const bool *vgroup_validmap,
- const int vgroup_tot);
+ int vgroup_tot);
/**
* Fill in the pointers for mirror verts (as if all mirror verts were selected too).
*
@@ -504,27 +491,27 @@ void ED_vgroup_parray_mirror_sync(struct Object *ob,
*/
void ED_vgroup_parray_mirror_assign(struct Object *ob,
struct MDeformVert **dvert_array,
- const int dvert_tot);
+ int dvert_tot);
void ED_vgroup_parray_remove_zero(struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
const bool *vgroup_validmap,
- const int vgroup_tot,
- const float epsilon,
- const bool keep_single);
+ int vgroup_tot,
+ float epsilon,
+ bool keep_single);
void ED_vgroup_parray_to_weight_array(const struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
float *dvert_weights,
- const int def_nr);
+ int def_nr);
void ED_vgroup_parray_from_weight_array(struct MDeformVert **dvert_array,
- const int dvert_tot,
+ int dvert_tot,
const float *dvert_weights,
- const int def_nr,
- const bool remove_zero);
+ int def_nr,
+ bool remove_zero);
void ED_vgroup_mirror(struct Object *ob,
- const bool mirror_weights,
- const bool flip_vgroups,
- const bool all_vgroups,
- const bool use_topology,
+ bool mirror_weights,
+ bool flip_vgroups,
+ bool all_vgroups,
+ bool use_topology,
int *r_totmirr,
int *r_totfail);
@@ -560,36 +547,27 @@ void ED_mesh_geometry_clear(struct Mesh *mesh);
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, bool calc_edges, bool calc_edges_loose);
void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name);
-int ED_mesh_uv_texture_add(struct Mesh *me,
- const char *name,
- const bool active_set,
- const bool do_init,
- struct ReportList *reports);
-bool ED_mesh_uv_texture_remove_index(struct Mesh *me, const int n);
+int ED_mesh_uv_texture_add(
+ struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
+bool ED_mesh_uv_texture_remove_index(struct Mesh *me, 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);
+void ED_mesh_uv_loop_reset_ex(struct Mesh *me, int layernum);
bool ED_mesh_color_ensure(struct Mesh *me, const char *name);
-int ED_mesh_color_add(struct Mesh *me,
- const char *name,
- const bool active_set,
- const bool do_init,
- struct ReportList *reports);
-bool ED_mesh_color_remove_index(struct Mesh *me, const int n);
+int ED_mesh_color_add(
+ struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
+bool ED_mesh_color_remove_index(struct Mesh *me, int n);
bool ED_mesh_color_remove_active(struct Mesh *me);
bool ED_mesh_color_remove_named(struct Mesh *me, const char *name);
bool ED_mesh_sculpt_color_ensure(struct Mesh *me, const char *name);
-int ED_mesh_sculpt_color_add(struct Mesh *me,
- const char *name,
- const bool active_set,
- const bool do_init,
- struct ReportList *reports);
-bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, const int n);
+int ED_mesh_sculpt_color_add(
+ struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports);
+bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, int n);
bool ED_mesh_sculpt_color_remove_active(struct Mesh *me);
bool ED_mesh_sculpt_color_remove_named(struct Mesh *me, const char *name);
@@ -654,16 +632,13 @@ 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.
*/
-int mesh_get_x_mirror_vert(struct Object *ob,
- struct Mesh *me_eval,
- int index,
- const bool use_topology);
+int mesh_get_x_mirror_vert(struct Object *ob, struct Mesh *me_eval, int index, bool use_topology);
struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob,
struct BMEditMesh *em,
struct BMVert *eve,
const float co[3],
int index,
- const bool use_topology);
+ bool use_topology);
/**
* This is a Mesh-based copy of #mesh_get_x_mirror_faces().
*/
@@ -672,7 +647,7 @@ int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em, struct Me
/**
* Wrapper for object-mode/edit-mode.
*
- * call #BM_mesh_elem_table_ensure first for editmesh.
+ * call #BM_mesh_elem_table_ensure first for edit-mesh.
*/
int ED_mesh_mirror_get_vert(struct Object *ob, int index);
@@ -702,12 +677,10 @@ struct MDeformVert *ED_mesh_active_dvert_get_ob(struct Object *ob, int *r_index)
struct MDeformVert *ED_mesh_active_dvert_get_only(struct Object *ob);
void EDBM_mesh_stats_multi(struct Object **objects,
- const uint objects_len,
+ uint objects_len,
int totelem[3],
int totelem_sel[3]);
-void EDBM_mesh_elem_index_ensure_multi(struct Object **objects,
- const uint objects_len,
- const char htype);
+void EDBM_mesh_elem_index_ensure_multi(struct Object **objects, uint objects_len, char htype);
#define ED_MESH_PICK_DEFAULT_VERT_DIST 25
#define ED_MESH_PICK_DEFAULT_FACE_DIST 1
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 5bac452c7c9..181b6848ac7 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -100,12 +100,7 @@ void ED_node_socket_draw(struct bNodeSocket *sock,
float scale);
void ED_node_tree_update(const struct bContext *C);
void ED_node_tag_update_id(struct ID *id);
-void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
-/**
- * Sort nodes by selection: unselected nodes first, then selected,
- * then the active node at the very end. Relative order is kept intact.
- */
-void ED_node_sort(struct bNodeTree *ntree);
+
float ED_node_grid_size(void);
/* node_relationships.c */
@@ -142,8 +137,6 @@ void ED_node_composit_default(const struct bContext *C, struct Scene *scene);
* 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);
void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree);
void ED_node_set_active(struct Main *bmain,
struct SpaceNode *snode,
@@ -152,6 +145,26 @@ void ED_node_set_active(struct Main *bmain,
bool *r_active_texture_changed);
/**
+ * Call after one or more node trees have been changed and tagged accordingly.
+ *
+ * This function will make sure that other parts of Blender update accordingly. For example, if the
+ * node group interface changed, parent node groups have to be updated as well.
+ *
+ * Additionally, this will send notifiers and tag the depsgraph based on the changes. Depsgraph
+ * relation updates have to be triggered by the caller.
+ *
+ * \param C: Context if available. This can be null.
+ * \param bmain: Main whose data-blocks should be updated based on the changes.
+ * \param ntree: Under some circumstances the caller knows that only one node tree has
+ * changed since the last update. In this case the function may be able to skip scanning #bmain
+ * for other things that have to be changed. It may still scan #bmain if the interface of the
+ * node tree has changed.
+ */
+void ED_node_tree_propagate_change(const struct bContext *C,
+ struct Main *bmain,
+ struct bNodeTree *ntree);
+
+/**
* \param scene_owner: is the owner of the job,
* we don't use it for anything else currently so could also be a void pointer,
* but for now keep it an 'Scene' for consistency.
diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index 84fa4488374..9fd77fa858e 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -114,7 +114,7 @@ bool user_string_to_number(bContext *C,
const struct UnitSettings *unit,
int type,
double *r_value,
- const bool use_single_line_error,
+ bool use_single_line_error,
char **r_error);
/** \} */
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 576c6f51362..805b48d9195 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -82,12 +82,12 @@ Object **ED_object_array_in_mode_or_selected(struct bContext *C,
/* object_utils.c */
bool ED_object_calc_active_center_for_editmode(struct Object *obedit,
- const bool select_only,
+ bool select_only,
float r_center[3]);
bool ED_object_calc_active_center_for_posemode(struct Object *ob,
- const bool select_only,
+ bool select_only,
float r_center[3]);
-bool ED_object_calc_active_center(struct Object *ob, const bool select_only, float r_center[3]);
+bool ED_object_calc_active_center(struct Object *ob, bool select_only, float r_center[3]);
/* Object Data Container helper API. */
struct XFormObjectData_Container;
@@ -189,10 +189,10 @@ bool ED_object_parent_set(struct ReportList *reports,
struct Object *const ob,
struct Object *const par,
int partype,
- const bool xmirror,
- const bool keep_transform,
+ bool xmirror,
+ bool keep_transform,
const int vert_par[3]);
-void ED_object_parent_clear(struct Object *ob, const int type);
+void ED_object_parent_clear(struct Object *ob, int type);
/**
* Simple API for object selection, rather than just using the flag
@@ -243,12 +243,9 @@ struct Base *ED_object_add_duplicate(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer,
struct Base *base,
- const eDupli_ID_Flags dupflag);
+ eDupli_ID_Flags dupflag);
-void ED_object_parent(struct Object *ob,
- struct Object *parent,
- const int type,
- const char *substr);
+void ED_object_parent(struct Object *ob, struct Object *parent, int type, const char *substr);
char *ED_object_ot_drop_named_material_tooltip(struct bContext *C,
struct PointerRNA *properties,
const int mval[2]);
@@ -323,7 +320,7 @@ void ED_object_sculptmode_enter_ex(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
- const bool force_dyntopo,
+ bool force_dyntopo,
struct ReportList *reports);
void ED_object_sculptmode_enter(struct bContext *C,
struct Depsgraph *depsgraph,
@@ -335,8 +332,8 @@ void ED_object_sculptmode_exit_ex(struct Main *bmain,
void ED_object_sculptmode_exit(struct bContext *C, struct Depsgraph *depsgraph);
void ED_object_location_from_view(struct bContext *C, float loc[3]);
-void ED_object_rotation_from_quat(float rot[3], const float quat[4], const char align_axis);
-void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char align_axis);
+void ED_object_rotation_from_quat(float rot[3], const float quat[4], char align_axis);
+void ED_object_rotation_from_view(struct bContext *C, float rot[3], char align_axis);
void ED_object_base_init_transform_on_add(struct Object *object,
const float loc[3],
const float rot[3]);
@@ -363,7 +360,7 @@ void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
void ED_object_add_mesh_props(struct wmOperatorType *ot);
bool ED_object_add_generic_get_opts(struct bContext *C,
struct wmOperator *op,
- const char view_align_axis,
+ char view_align_axis,
float r_loc[3],
float r_rot[3],
float r_scale[3],
@@ -378,20 +375,20 @@ bool ED_object_add_generic_get_opts(struct bContext *C,
* \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,
+ int type,
const char *name,
const float loc[3],
const float rot[3],
- const bool enter_editmode,
- const ushort local_view_bits,
+ bool enter_editmode,
+ ushort local_view_bits,
struct ID *obdata);
struct Object *ED_object_add_type(struct bContext *C,
- const int type,
+ int type,
const char *name,
const float loc[3],
const float rot[3],
- const bool enter_editmode,
- const unsigned short local_view_bits)
+ bool enter_editmode,
+ unsigned short local_view_bits)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
/**
@@ -468,9 +465,7 @@ void ED_object_constraint_dependency_tag_update(struct Main *bmain,
struct Object *ob,
struct bConstraint *con);
-bool ED_object_constraint_move_to_index(struct Object *ob,
- struct bConstraint *con,
- const int index);
+bool ED_object_constraint_move_to_index(struct Object *ob, struct bConstraint *con, int index);
void ED_object_constraint_link(struct Main *bmain,
struct Object *ob_dst,
struct ListBase *dst,
@@ -514,7 +509,7 @@ bool ED_object_mode_generic_has_data(struct Depsgraph *depsgraph, const struct O
void ED_object_posemode_set_for_weight_paint(struct bContext *C,
struct Main *bmain,
struct Object *ob,
- const bool is_mode_set);
+ bool is_mode_set);
/* object_modifier.c */
@@ -550,7 +545,7 @@ bool ED_object_modifier_move_up(struct ReportList *reports,
bool ED_object_modifier_move_to_index(struct ReportList *reports,
struct Object *ob,
struct ModifierData *md,
- const int index);
+ int index);
bool ED_object_modifier_convert(struct ReportList *reports,
struct Main *bmain,
@@ -588,7 +583,7 @@ void ED_object_modifier_copy_to_object(struct bContext *C,
*/
bool ED_object_iter_other(struct Main *bmain,
struct Object *orig_ob,
- const bool include_orig,
+ bool include_orig,
bool (*callback)(struct Object *ob, void *callback_data),
void *callback_data);
@@ -619,7 +614,7 @@ bool ED_object_gpencil_modifier_move_up(struct ReportList *reports,
bool ED_object_gpencil_modifier_move_to_index(struct ReportList *reports,
struct Object *ob,
struct GpencilModifierData *md,
- const int index);
+ int index);
bool ED_object_gpencil_modifier_apply(struct Main *bmain,
struct ReportList *reports,
struct Depsgraph *depsgraph,
@@ -653,7 +648,7 @@ int ED_object_shaderfx_move_up(struct ReportList *reports,
bool ED_object_shaderfx_move_to_index(struct ReportList *reports,
struct Object *ob,
struct ShaderFxData *fx,
- const int index);
+ int index);
void ED_object_shaderfx_link(struct Object *dst, struct Object *src);
void ED_object_shaderfx_copy(struct Object *dst, struct ShaderFxData *fx);
@@ -665,7 +660,7 @@ const struct EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free,
- const unsigned int selection_mask);
+ unsigned int selection_mask);
void ED_object_check_force_modifiers(struct Main *bmain,
struct Scene *scene,
@@ -683,7 +678,7 @@ struct Base *ED_object_find_first_by_data_id(struct ViewLayer *view_layer, struc
*
* \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);
+bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, 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.
@@ -694,7 +689,7 @@ bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, const bool
bool ED_object_jump_to_bone(struct bContext *C,
struct Object *ob,
const char *bone_name,
- const bool reveal_hidden);
+ bool reveal_hidden);
/* object_facemap_ops.c */
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index ce25943b40a..9671f5b2b09 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -72,16 +72,13 @@ void PE_update_object(struct Depsgraph *depsgraph,
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);
+bool PE_box_select(struct bContext *C, const struct rcti *rect, int sel_op);
bool PE_circle_select(struct bContext *C,
struct wmGenericUserData *wm_userdata,
- const int sel_op,
+ int sel_op,
const int mval[2],
float rad);
-int PE_lasso_select(struct bContext *C,
- const int mcoords[][2],
- const int mcoords_len,
- const int sel_op);
+int PE_lasso_select(struct bContext *C, const int mcoords[][2], int mcoords_len, int sel_op);
bool PE_deselect_all_visible_ex(struct PTCacheEdit *edit);
bool PE_deselect_all_visible(struct bContext *C);
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 50d7bfc3960..dabf8fb838b 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -23,6 +23,7 @@
#pragma once
+#include "DNA_ID_enums.h"
#include "DNA_vec_types.h"
#ifdef __cplusplus
@@ -41,7 +42,6 @@ struct bContext;
struct bScreen;
struct wmWindow;
struct wmWindowManager;
-enum eIconSizes;
/* render_ops.c */
@@ -49,7 +49,7 @@ void ED_operatortypes_render(void);
/* render_update.c */
-void ED_render_engine_changed(struct Main *bmain, const bool update_scene_data);
+void ED_render_engine_changed(struct Main *bmain, bool update_scene_data);
void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *area);
void ED_render_view_layer_changed(struct Main *bmain, struct bScreen *screen);
@@ -60,14 +60,14 @@ void ED_render_id_flush_update(const struct DEGEditorUpdateContext *update_ctx,
* 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);
+void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, 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,
- const bool updated);
+ bool updated);
struct Scene *ED_render_job_get_scene(const struct bContext *C);
struct Scene *ED_render_job_get_current_scene(const struct bContext *C);
@@ -77,14 +77,12 @@ 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);
@@ -102,7 +100,7 @@ void ED_preview_shader_job(const struct bContext *C,
struct MTex *slot,
int sizex,
int sizey,
- int method);
+ ePreviewRenderMethod method);
void ED_preview_icon_render(const struct bContext *C,
struct Scene *scene,
struct ID *id,
@@ -115,7 +113,7 @@ void ED_preview_icon_job(const struct bContext *C,
unsigned int *rect,
int sizex,
int sizey,
- const bool delay);
+ bool delay);
void ED_preview_restart_queue_free(void);
void ED_preview_restart_queue_add(struct ID *id, enum eIconSizes size);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index c65ef3e397d..651ae1de8be 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -160,11 +160,11 @@ void ED_region_visibility_change_update_animated(struct bContext *C,
void ED_region_info_draw(struct ARegion *region,
const char *text,
float fill_color[4],
- const bool full_redraw);
+ bool full_redraw);
void ED_region_info_draw_multiline(ARegion *region,
const char *text_array[],
float fill_color[4],
- const bool full_redraw);
+ bool full_redraw);
void ED_region_image_metadata_panel_draw(struct ImBuf *ibuf, struct uiLayout *layout);
void ED_region_grid_draw(struct ARegion *region, float zoomx, float zoomy, float x0, float y0);
float ED_region_blend_alpha(struct ARegion *region);
@@ -238,7 +238,7 @@ 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_newspace(struct bContext *C, ScrArea *area, int type, 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);
@@ -316,7 +316,7 @@ 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);
+ bool refresh_toolsystem);
/**
* Called in wm_event_system.c. sets state vars in screen, cursors.
* event type is mouse move.
@@ -360,7 +360,7 @@ bScreen *ED_screen_state_maximized_create(struct bContext *C);
struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *area,
- const short state);
+ short state);
/**
* Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
* by \a display_type.
@@ -397,7 +397,7 @@ Scene *ED_screen_scene_find_with_window(const struct bScreen *screen,
struct wmWindow **r_window);
ScrArea *ED_screen_area_find_with_spacedata(const bScreen *screen,
const struct SpaceLink *sl,
- const bool only_visible);
+ bool only_visible);
struct wmWindow *ED_screen_window_find(const struct bScreen *screen,
const struct wmWindowManager *wm);
/**
@@ -473,9 +473,8 @@ struct WorkSpaceLayout *ED_workspace_layout_duplicate(struct Main *bmain,
bool ED_workspace_layout_delete(struct WorkSpace *workspace,
struct WorkSpaceLayout *layout_old,
struct bContext *C) ATTR_NONNULL();
-bool ED_workspace_layout_cycle(struct WorkSpace *workspace,
- const short direction,
- struct bContext *C) ATTR_NONNULL();
+bool ED_workspace_layout_cycle(struct WorkSpace *workspace, short direction, struct bContext *C)
+ ATTR_NONNULL();
void ED_workspace_status_text(struct bContext *C, const char *str);
@@ -644,12 +643,9 @@ void ED_screen_user_menu_register(void);
/* Cache display helpers */
void ED_region_cache_draw_background(struct ARegion *region);
-void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y);
-void ED_region_cache_draw_cached_segments(struct ARegion *region,
- const int num_segments,
- const int *points,
- const int sfra,
- const int efra);
+void ED_region_cache_draw_curfra_label(int framenr, float x, float y);
+void ED_region_cache_draw_cached_segments(
+ struct ARegion *region, int num_segments, const int *points, int sfra, int efra);
/* area_utils.c */
@@ -664,19 +660,15 @@ void ED_region_generic_tools_region_message_subscribe(
int ED_region_generic_tools_region_snap_size(const struct ARegion *region, int size, int axis);
/* area_query.c */
-bool ED_region_overlap_isect_x(const ARegion *region, const int event_x);
-bool ED_region_overlap_isect_y(const ARegion *region, const int event_y);
+bool ED_region_overlap_isect_x(const ARegion *region, int event_x);
+bool ED_region_overlap_isect_y(const ARegion *region, int event_y);
bool ED_region_overlap_isect_xy(const ARegion *region, const int event_xy[2]);
bool ED_region_overlap_isect_any_xy(const ScrArea *area, const int event_xy[2]);
-bool ED_region_overlap_isect_x_with_margin(const ARegion *region,
- const int event_x,
- const int margin);
-bool ED_region_overlap_isect_y_with_margin(const ARegion *region,
- const int event_y,
- const int margin);
+bool ED_region_overlap_isect_x_with_margin(const ARegion *region, int event_x, int margin);
+bool ED_region_overlap_isect_y_with_margin(const ARegion *region, int event_y, int margin);
bool ED_region_overlap_isect_xy_with_margin(const ARegion *region,
const int event_xy[2],
- const int margin);
+ int margin);
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]);
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 0cdd8873cb2..7c1124d705f 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -60,7 +60,7 @@ 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);
+void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, int new_id);
int ED_sculpt_face_sets_active_update_and_get(struct bContext *C,
struct Object *ob,
diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h
index 4656099799b..295268c7719 100644
--- a/source/blender/editors/include/ED_select_utils.h
+++ b/source/blender/editors/include/ED_select_utils.h
@@ -64,27 +64,25 @@ enum {
* 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);
+int ED_select_op_action(eSelectOp sel_op, bool is_select, 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);
+int ED_select_op_action_deselected(eSelectOp sel_op, bool is_select, bool is_inside);
-int ED_select_similar_compare_float(const float delta, const float thresh, const int compare);
+int ED_select_similar_compare_float(float delta, float thresh, int compare);
bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree,
- const float length,
- const float thresh,
- const int compare);
+ float length,
+ float thresh,
+ 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);
+eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index f4a69737da1..fb76b36baef 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -86,7 +86,7 @@ void *ED_region_draw_cb_activate(struct ARegionType *art,
int type);
void ED_region_draw_cb_draw(const struct bContext *C, struct ARegion *region, int type);
void ED_region_surface_draw_cb_draw(struct ARegionType *art, int type);
-void ED_region_draw_cb_exit(struct ARegionType *art, void *handle);
+bool ED_region_draw_cb_exit(struct ARegionType *art, void *handle);
void ED_region_draw_cb_remove_by_type(struct ARegionType *art,
void *draw_fn,
void (*free)(void *));
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index f0d6072fdbc..573f9b4939b 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -54,7 +54,8 @@ typedef enum {
TFM_TILT,
TFM_TRACKBALL,
TFM_PUSHPULL,
- TFM_CREASE,
+ TFM_EDGE_CREASE,
+ TFM_VERT_CREASE,
TFM_MIRROR,
TFM_BONESIZE,
TFM_BONE_ENVELOPE,
@@ -104,16 +105,16 @@ void BIF_removeTransformOrientationIndex(struct bContext *C, int index);
bool BIF_createTransformOrientation(struct bContext *C,
struct ReportList *reports,
const char *name,
- const bool use_view,
- const bool activate,
- const bool overwrite);
+ bool use_view,
+ bool activate,
+ bool overwrite);
void BIF_selectTransformOrientation(struct bContext *C, struct TransformOrientation *target);
void ED_getTransformOrientationMatrix(struct ViewLayer *view_layer,
const struct View3D *v3d,
struct Object *ob,
struct Object *obedit,
- const short around,
+ short around,
float r_orientation_mat[3][3]);
int BIF_countTransformOrientation(const struct bContext *C);
@@ -161,8 +162,8 @@ short ED_transform_calc_orientation_from_type_ex(const struct Scene *scene,
const struct RegionView3D *rv3d,
struct Object *ob,
struct Object *obedit,
- const short orientation_index,
- const int pivot_point,
+ short orientation_index,
+ int pivot_point,
float r_mat[3][3]);
/* transform gizmos */
@@ -188,7 +189,7 @@ void ED_widgetgroup_gizmo2d_rotate_callbacks_set(struct wmGizmoGroupType *gzgt);
struct TransformBounds {
float center[3]; /* Center for transform widget. */
- float min[3], max[3]; /* Boundbox of selection for transform widget. */
+ float min[3], max[3]; /* Bounding-box of selection for transform widget. */
/* Normalized axis */
float axis[3][3];
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 6f25a63188d..fd65d8f3663 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -138,7 +138,7 @@ short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
- const unsigned short snap_to,
+ unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
@@ -166,7 +166,7 @@ short ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
struct Depsgraph *depsgraph,
const ARegion *region,
const View3D *v3d,
- const unsigned short snap_to,
+ unsigned short snap_to,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
diff --git a/source/blender/editors/include/ED_transverts.h b/source/blender/editors/include/ED_transverts.h
index 28955da6ef1..cbcf28d53d5 100644
--- a/source/blender/editors/include/ED_transverts.h
+++ b/source/blender/editors/include/ED_transverts.h
@@ -42,7 +42,7 @@ typedef struct TransVertStore {
int mode;
} TransVertStore;
-void ED_transverts_create_from_obedit(TransVertStore *tvs, struct Object *obedit, const int mode);
+void ED_transverts_create_from_obedit(TransVertStore *tvs, struct Object *obedit, int mode);
void ED_transverts_update_obedit(TransVertStore *tvs, struct Object *obedit);
void ED_transverts_free(TransVertStore *tvs);
bool ED_transverts_check_obedit(Object *obedit);
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 69378d436ab..4e794838b2f 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -33,6 +33,7 @@ extern "C" {
struct GPUBatch;
struct Main;
struct bContext;
+struct IDRemapper;
/* ed_util.c */
@@ -60,10 +61,13 @@ bool ED_editors_flush_edits(struct Main *bmain);
*
* \param new_id: may be NULL to unlink \a old_id.
*/
+void ED_spacedata_id_remap_single(struct ScrArea *area,
+ struct SpaceLink *sl,
+ struct ID *old_id,
+ struct ID *new_id);
void ED_spacedata_id_remap(struct ScrArea *area,
struct SpaceLink *sl,
- struct ID *old_id,
- struct ID *new_id);
+ const struct IDRemapper *mappings);
void ED_operatortypes_edutils(void);
@@ -102,13 +106,13 @@ void ED_slider_destroy(struct bContext *C, struct tSlider *slider);
*/
void ED_slider_status_string_get(const struct tSlider *slider,
char *status_string,
- const size_t size_of_status_string);
+ size_t size_of_status_string);
float ED_slider_factor_get(struct tSlider *slider);
void ED_slider_factor_set(struct tSlider *slider, float factor);
bool ED_slider_allow_overshoot_get(struct tSlider *slider);
-void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value);
+void ED_slider_allow_overshoot_set(struct tSlider *slider, bool value);
/* ************** XXX OLD CRUFT WARNING ************* */
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index d5303904842..0af98fc367f 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -100,93 +100,87 @@ bool ED_uvedit_test(struct Object *obedit);
bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, struct BMFace *efa);
bool uvedit_face_select_test_ex(const struct ToolSettings *ts,
struct BMFace *efa,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool uvedit_edge_select_test_ex(const struct ToolSettings *ts,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool uvedit_uv_select_test_ex(const struct ToolSettings *ts,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa);
-bool uvedit_face_select_test(const struct Scene *scene,
- struct BMFace *efa,
- const int cd_loop_uv_offset);
-bool uvedit_edge_select_test(const struct Scene *scene,
- struct BMLoop *l,
- const int cd_loop_uv_offset);
-bool uvedit_uv_select_test(const struct Scene *scene,
- struct BMLoop *l,
- const int cd_loop_uv_offset);
+bool uvedit_face_select_test(const struct Scene *scene, struct BMFace *efa, int cd_loop_uv_offset);
+bool uvedit_edge_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset);
+bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset);
/* uv face */
void uvedit_face_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_face_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_face_select_enable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_face_select_disable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMFace *efa,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
/* uv edge */
void uvedit_edge_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const uint cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ uint cd_loop_uv_offset);
void uvedit_edge_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_edge_select_enable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_edge_select_disable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
/* uv vert */
void uvedit_uv_select_set_with_sticky(const struct SpaceImage *sima,
const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const uint cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ uint cd_loop_uv_offset);
void uvedit_uv_select_set(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool select,
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_uv_select_enable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset);
+ bool do_history,
+ int cd_loop_uv_offset);
void uvedit_uv_select_disable(const struct Scene *scene,
struct BMEditMesh *em,
struct BMLoop *l,
- const int cd_loop_uv_offset);
+ int cd_loop_uv_offset);
bool ED_uvedit_nearest_uv(const struct Scene *scene,
struct Object *obedit,
@@ -195,7 +189,7 @@ bool ED_uvedit_nearest_uv(const struct Scene *scene,
float r_uv[2]);
bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
float *dist_sq,
float r_uv[2]);
@@ -228,7 +222,7 @@ struct BMLoop *ED_uvedit_active_edge_loop_get(struct BMesh *bm);
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);
+ bool select);
/* uvedit_unwrap_ops.c */
@@ -278,7 +272,7 @@ bool uv_coords_isect_udim(const struct Image *image,
const float coords[2]);
void ED_uvedit_pack_islands_multi(const struct Scene *scene,
Object **objects,
- const uint objects_len,
+ uint objects_len,
const struct UVMapUDIM_Params *udim_params,
const struct UVPackIsland_Params *params);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 6c986d8efe1..0398c209c68 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -114,17 +114,17 @@ bool ED_view3d_has_workbench_in_texture_color(const struct Scene *scene,
*/
void ED_view3d_cursor3d_position(struct bContext *C,
const int mval[2],
- const bool use_depth,
+ bool use_depth,
float r_cursor_co[3]);
void ED_view3d_cursor3d_position_rotation(struct bContext *C,
const int mval[2],
- const bool use_depth,
+ bool use_depth,
enum eV3DCursorOrient orientation,
float r_cursor_co[3],
float r_cursor_quat[4]);
void ED_view3d_cursor3d_update(struct bContext *C,
const int mval[2],
- const bool use_depth,
+ bool use_depth,
enum eV3DCursorOrient orientation);
struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d);
@@ -137,7 +137,7 @@ struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D
* \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);
+void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], float dist);
/**
* Set the view transformation from a 4x4 matrix.
*
@@ -171,7 +171,7 @@ void ED_view3d_to_object(const struct Depsgraph *depsgraph,
struct Object *ob,
const float ofs[3],
const float quat[4],
- const float dist);
+ float dist);
bool ED_view3d_camera_to_view_selected(struct Main *bmain,
struct Depsgraph *depsgraph,
@@ -213,7 +213,7 @@ bool ED_view3d_depth_read_cached_normal(const struct ARegion *region,
float r_normal[3]);
bool ED_view3d_depth_unproject_v3(const struct ARegion *region,
const int mval[2],
- const double depth,
+ double depth,
float r_location_world[3]);
/* Projection */
@@ -280,7 +280,7 @@ typedef enum {
/* view3d_snap.c */
bool ED_view3d_snap_selected_to_location(struct bContext *C,
const float snap_target_global[3],
- const int pivot_point);
+ int pivot_point);
/* view3d_cursor_snap.c */
#define USE_SNAP_DETECT_FROM_KEYMAP_HACK
@@ -343,8 +343,8 @@ void ED_view3d_cursor_snap_deactive(V3DSnapCursorState *state);
void ED_view3d_cursor_snap_prevpoint_set(V3DSnapCursorState *state, const float prev_point[3]);
V3DSnapCursorData *ED_view3d_cursor_snap_data_get(V3DSnapCursorState *state,
const struct bContext *C,
- const int x,
- const int y);
+ int x,
+ int y);
struct SnapObjectContext *ED_view3d_cursor_snap_context_ensure(struct Scene *scene);
void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d,
const float loc_prev[3],
@@ -352,7 +352,7 @@ void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d,
const float normal[3],
const uchar color_line[4],
const uchar color_point[4],
- const short snap_elem_type);
+ short snap_elem_type);
/* view3d_iterators.c */
@@ -362,12 +362,12 @@ void meshobject_foreachScreenVert(
struct ViewContext *vc,
void (*func)(void *userData, struct MVert *eve, const float screen_co[2], int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void mesh_foreachScreenVert(
struct ViewContext *vc,
void (*func)(void *userData, struct BMVert *eve, const float screen_co[2], int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void mesh_foreachScreenEdge(struct ViewContext *vc,
void (*func)(void *userData,
struct BMEdge *eed,
@@ -375,7 +375,7 @@ void mesh_foreachScreenEdge(struct ViewContext *vc,
const float screen_co_b[2],
int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
/**
* A version of #mesh_foreachScreenEdge that clips the segment when
@@ -388,13 +388,13 @@ void mesh_foreachScreenEdge_clip_bb_segment(struct ViewContext *vc,
const float screen_co_b[2],
int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void mesh_foreachScreenFace(
struct ViewContext *vc,
void (*func)(void *userData, struct BMFace *efa, const float screen_co[2], int index),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void nurbs_foreachScreenVert(struct ViewContext *vc,
void (*func)(void *userData,
struct Nurb *nu,
@@ -404,7 +404,7 @@ void nurbs_foreachScreenVert(struct ViewContext *vc,
bool handle_visible,
const float screen_co[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
/**
* #ED_view3d_init_mats_rv3d must be called first.
*/
@@ -413,13 +413,13 @@ void mball_foreachScreenElem(struct ViewContext *vc,
struct MetaElem *ml,
const float screen_co[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
void lattice_foreachScreenVert(struct ViewContext *vc,
void (*func)(void *userData,
struct BPoint *bp,
const float screen_co[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
/**
* #ED_view3d_init_mats_rv3d must be called first.
*/
@@ -429,7 +429,7 @@ void armature_foreachScreenBone(struct ViewContext *vc,
const float screen_co_a[2],
const float screen_co_b[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
/**
* ED_view3d_init_mats_rv3d must be called first.
@@ -440,7 +440,7 @@ void pose_foreachScreenBone(struct ViewContext *vc,
const float screen_co_a[2],
const float screen_co_b[2]),
void *userData,
- const eV3DProjTest clip_flag);
+ eV3DProjTest clip_flag);
/* *** end iterators *** */
/* view3d_project.c */
@@ -465,58 +465,58 @@ eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, struct Base
/* *** short *** */
eV3DProjStatus ED_view3d_project_short_ex(const struct ARegion *region,
float perspmat[4][4],
- const bool is_local,
+ bool is_local,
const float co[3],
short r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* --- short --- */
eV3DProjStatus ED_view3d_project_short_global(const struct ARegion *region,
const float co[3],
short r_co[2],
- const eV3DProjTest flag);
+ 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],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* *** int *** */
eV3DProjStatus ED_view3d_project_int_ex(const struct ARegion *region,
float perspmat[4][4],
- const bool is_local,
+ bool is_local,
const float co[3],
int r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* --- int --- */
eV3DProjStatus ED_view3d_project_int_global(const struct ARegion *region,
const float co[3],
int r_co[2],
- const eV3DProjTest flag);
+ 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],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* *** float *** */
eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *region,
float perspmat[4][4],
- const bool is_local,
+ bool is_local,
const float co[3],
float r_co[2],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
/* --- float --- */
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region,
const float co[3],
float r_co[2],
- const eV3DProjTest flag);
+ 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],
- const eV3DProjTest flag);
+ eV3DProjTest flag);
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]);
@@ -550,7 +550,7 @@ bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph,
const float mval[2],
float r_ray_start[3],
float r_ray_normal[3],
- const bool do_clip_planes);
+ 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`.
@@ -620,7 +620,7 @@ void ED_view3d_win_to_3d_int(const struct View3D *v3d,
bool ED_view3d_win_to_3d_on_plane(const struct ARegion *region,
const float plane[4],
const float mval[2],
- const bool do_clip,
+ bool do_clip,
float r_out[3]);
/**
* A wrapper for #ED_view3d_win_to_3d_on_plane that projects onto \a plane_fallback
@@ -632,13 +632,13 @@ bool ED_view3d_win_to_3d_on_plane(const struct ARegion *region,
bool ED_view3d_win_to_3d_on_plane_with_fallback(const struct ARegion *region,
const float plane[4],
const float mval[2],
- const bool do_clip,
+ bool do_clip,
const float plane_fallback[4],
float r_out[3]);
bool ED_view3d_win_to_3d_on_plane_int(const struct ARegion *region,
const float plane[4],
const int mval[2],
- const bool do_clip,
+ bool do_clip,
float r_out[3]);
/**
* Calculate a 3d difference vector from 2d window offset.
@@ -651,7 +651,7 @@ bool ED_view3d_win_to_3d_on_plane_int(const struct ARegion *region,
void ED_view3d_win_to_delta(const struct ARegion *region,
const float mval[2],
float out[3],
- const float zfac);
+ float zfac);
/**
* Calculate a 3d origin from 2d window coordinates.
* \note Orthographic views have a less obvious origin,
@@ -697,7 +697,7 @@ bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph,
const float mval[2],
float r_ray_start[3],
float r_ray_end[3],
- const bool do_clip_planes);
+ bool do_clip_planes);
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d,
const struct Object *ob,
float r_pmat[4][4]);
@@ -729,7 +729,7 @@ bool ED_view3d_clip_range_get(struct Depsgraph *depsgraph,
const struct RegionView3D *rv3d,
float *r_clipsta,
float *r_clipend,
- const bool use_ortho_factor);
+ bool use_ortho_factor);
bool ED_view3d_viewplane_get(struct Depsgraph *depsgraph,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
@@ -743,7 +743,7 @@ bool ED_view3d_viewplane_get(struct Depsgraph *depsgraph,
/**
* 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_polygon_offset(const struct RegionView3D *rv3d, float dist);
void ED_view3d_calc_camera_border(const struct Scene *scene,
struct Depsgraph *depsgraph,
@@ -751,7 +751,7 @@ void ED_view3d_calc_camera_border(const struct Scene *scene,
const struct View3D *v3d,
const struct RegionView3D *rv3d,
struct rctf *r_viewborder,
- const bool no_shift);
+ bool no_shift);
void ED_view3d_calc_camera_border_size(const struct Scene *scene,
struct Depsgraph *depsgraph,
const struct ARegion *region,
@@ -766,7 +766,7 @@ bool ED_view3d_calc_render_border(const struct Scene *scene,
void ED_view3d_clipping_calc_from_boundbox(float clip[4][4],
const struct BoundBox *clipbb,
- const bool is_flip);
+ bool is_flip);
void ED_view3d_clipping_calc(struct BoundBox *bb,
float planes[4][4],
const struct ARegion *region,
@@ -796,12 +796,10 @@ void ED_view3d_clipping_local(struct RegionView3D *rv3d, const float mat[4][4]);
*
* \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);
+bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], 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);
+float ED_view3d_radius_to_dist_persp(float angle, float radius);
+float ED_view3d_radius_to_dist_ortho(float lens, float radius);
/**
* Return a new #RegionView3D.dist value to fit the \a radius.
*
@@ -830,9 +828,9 @@ float ED_view3d_radius_to_dist_ortho(const float lens, const float radius);
float ED_view3d_radius_to_dist(const struct View3D *v3d,
const struct ARegion *region,
const struct Depsgraph *depsgraph,
- const char persp,
- const bool use_aspect,
- const float radius);
+ char persp,
+ bool use_aspect,
+ float radius);
/**
* Back-buffer select and draw support.
@@ -842,7 +840,7 @@ 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);
+int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, float dist);
void ED_view3d_select_id_validate(struct ViewContext *vc);
@@ -859,7 +857,7 @@ bool ED_view3d_autodist(struct Depsgraph *depsgraph,
struct View3D *v3d,
const int mval[2],
float mouse_worldloc[3],
- const bool alphaoverride,
+ bool alphaoverride,
const float fallback_depth_pt[3]);
/**
@@ -919,7 +917,7 @@ int view3d_opengl_select_ex(struct ViewContext *vc,
const struct rcti *input,
eV3DSelectMode select_mode,
eV3DSelectObjectFilter select_filter,
- const bool do_material_slot_selection);
+ bool do_material_slot_selection);
int view3d_opengl_select(struct ViewContext *vc,
unsigned int *buffer,
unsigned int bufsize,
@@ -1004,7 +1002,7 @@ void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixSto
void ED_draw_object_facemap(struct Depsgraph *depsgraph,
struct Object *ob,
const float col[4],
- const int facemap);
+ int facemap);
struct RenderEngineType *ED_view3d_engine_type(const struct Scene *scene, int drawtype);
@@ -1046,9 +1044,9 @@ void ED_view3d_update_viewmat(struct Depsgraph *depsgraph,
const float winmat[4][4],
const struct rcti *rect,
bool offscreen);
-bool ED_view3d_quat_from_axis_view(const char view, const char view_axis_roll, float r_quat[4]);
+bool ED_view3d_quat_from_axis_view(char view, char view_axis_roll, float r_quat[4]);
bool ED_view3d_quat_to_axis_view(const float viewquat[4],
- const float epsilon,
+ float epsilon,
char *r_view,
char *r_view_axis_rotation);
@@ -1079,7 +1077,7 @@ bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionVi
void ED_view3d_persp_switch_from_camera(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d,
- const char persp);
+ char persp);
/**
* Action to take when rotating the view,
* handle auto-perspective and logic for switching out of views.
@@ -1105,7 +1103,7 @@ bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionVi
void ED_view3d_camera_lock_init_ex(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d,
- const bool calc_dist);
+ bool calc_dist);
void ED_view3d_camera_lock_init(const struct Depsgraph *depsgraph,
struct View3D *v3d,
struct RegionView3D *rv3d);
@@ -1123,8 +1121,8 @@ bool ED_view3d_camera_lock_sync(const struct Depsgraph *depsgraph,
bool ED_view3d_camera_autokey(const struct Scene *scene,
struct ID *id_key,
struct bContext *C,
- const bool do_rotate,
- const bool do_translate);
+ bool do_rotate,
+ bool do_translate);
/**
* Call after modifying a locked view.
*
@@ -1134,8 +1132,8 @@ bool ED_view3d_camera_autokey(const struct Scene *scene,
bool ED_view3d_camera_lock_autokey(struct View3D *v3d,
struct RegionView3D *rv3d,
struct bContext *C,
- const bool do_rotate,
- const bool do_translate);
+ bool do_rotate,
+ bool do_translate);
void ED_view3d_lock_clear(struct View3D *v3d);
@@ -1154,15 +1152,13 @@ void ED_view3d_lock_clear(struct View3D *v3d);
* \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);
+float ED_view3d_offset_distance(const float mat[4][4], const float ofs[3], 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);
+void ED_view3d_distance_set(struct RegionView3D *rv3d, float dist);
/**
* Change the distance & offset to match the depth of \a dist_co along the view axis.
*
@@ -1172,7 +1168,7 @@ void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist);
*/
bool ED_view3d_distance_set_from_location(struct RegionView3D *rv3d,
const float dist_co[3],
- const float dist_min);
+ float dist_min);
/**
* Could move this elsewhere, but tied into #ED_view3d_grid_scale
@@ -1223,8 +1219,8 @@ void ED_view3d_draw_bgpic_test(const struct Scene *scene,
struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
- const bool do_foreground,
- const bool do_camera_frame);
+ bool do_foreground,
+ bool do_camera_frame);
/* view3d_gizmo_preselect_type.c */
@@ -1247,12 +1243,10 @@ void ED_view3d_buttons_region_layout_ex(const struct bContext *C,
* 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);
+void ED_view3d_local_collections_reset(struct bContext *C, bool reset_all);
#ifdef WITH_XR_OPENXR
-void ED_view3d_xr_mirror_update(const struct ScrArea *area,
- const struct View3D *v3d,
- const bool enable);
+void ED_view3d_xr_mirror_update(const struct ScrArea *area, const struct View3D *v3d, bool enable);
void ED_view3d_xr_shading_update(struct wmWindowManager *wm,
const View3D *v3d,
const struct Scene *scene);
diff --git a/source/blender/editors/include/ED_view3d_offscreen.h b/source/blender/editors/include/ED_view3d_offscreen.h
index 1da0a282697..ae2329c457b 100644
--- a/source/blender/editors/include/ED_view3d_offscreen.h
+++ b/source/blender/editors/include/ED_view3d_offscreen.h
@@ -53,8 +53,8 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph,
bool is_image_render,
bool draw_background,
const char *viewname,
- const bool do_color_management,
- const bool restore_rv3d_mats,
+ bool do_color_management,
+ bool restore_rv3d_mats,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
/**
@@ -76,7 +76,7 @@ void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph,
bool is_image_render,
bool draw_background,
const char *viewname,
- const bool do_color_management,
+ bool do_color_management,
struct GPUOffScreen *ofs,
struct GPUViewport *viewport);
@@ -96,7 +96,7 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph,
eImBufFlags imbuf_flag,
int alpha_mode,
const char *viewname,
- const bool restore_rv3d_mats,
+ bool restore_rv3d_mats,
struct GPUOffScreen *ofs,
char err_out[256]);
/**
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index ba83b259267..3796fa51499 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -494,9 +494,9 @@ void UI_draw_widget_scroll(struct uiWidgetColors *wcol,
float UI_text_clip_middle_ex(const struct uiFontStyle *fstyle,
char *str,
float okwidth,
- const float minwidth,
- const size_t max_len,
- const char rpart_sep);
+ float minwidth,
+ size_t max_len,
+ char rpart_sep);
/**
* Callbacks
@@ -531,11 +531,8 @@ typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C,
* 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).
*/
-typedef void (*uiButSearchUpdateFn)(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items,
- const bool is_first);
+typedef void (*uiButSearchUpdateFn)(
+ const struct bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
typedef bool (*uiButSearchContextMenuFn)(struct bContext *C,
void *arg,
void *active,
@@ -621,7 +618,7 @@ bool UI_but_is_tool(const uiBut *but);
bool UI_but_is_utf8(const uiBut *but);
#define UI_but_is_decorator(but) ((but)->type == UI_BTYPE_DECORATOR)
-bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title);
+bool UI_block_is_empty_ex(const uiBlock *block, bool skip_title);
bool UI_block_is_empty(const uiBlock *block);
bool UI_block_can_add_separator(const uiBlock *block);
@@ -662,7 +659,7 @@ int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportLi
* 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);
+void UI_popup_menu_retval_set(const uiBlock *block, int retval, bool enable);
/**
* Setting the button makes the popup open from the button instead of the cursor.
*/
@@ -866,7 +863,7 @@ 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);
+void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale);
/**
* \param asset: May be passed from a temporary variable, drag data only stores a copy of this.
*/
@@ -879,14 +876,14 @@ void UI_but_drag_set_asset(uiBut *but,
struct ImBuf *imb,
float scale);
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_path(uiBut *but, const char *path, 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 *but, const char *path, int icon, struct ImBuf *imb, float scale, bool use_free);
uiBut *UI_but_active_drop_name_button(const struct bContext *C);
/**
@@ -918,7 +915,7 @@ bool UI_but_active_only_ex(const struct bContext *C,
struct ARegion *region,
uiBlock *block,
uiBut *but,
- const bool remove_on_failure);
+ bool remove_on_failure);
bool UI_but_active_only(const struct bContext *C,
struct ARegion *region,
uiBlock *block,
@@ -982,21 +979,6 @@ uiBut *uiDefButF(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefButI(uiBlock *block,
int type,
int retval,
@@ -1154,35 +1136,6 @@ uiBut *uiDefIconBut(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconButF(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconButI(uiBlock *block,
int type,
int retval,
@@ -1241,20 +1194,6 @@ uiBut *uiDefIconButBitS(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconButBitC(uiBlock *block,
int type,
int bit,
@@ -1356,22 +1295,6 @@ uiBut *uiDefIconTextButF(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconTextButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconTextButI(uiBlock *block,
int type,
int retval,
@@ -1387,84 +1310,6 @@ uiBut *uiDefIconTextButI(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconTextButBitI(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- int *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButS(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButBitS(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButBitC(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconTextButR(uiBlock *block,
int type,
int retval,
@@ -1525,7 +1370,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block,
/* for passing inputs to ButO buttons */
struct PointerRNA *UI_but_operator_ptr_get(uiBut *but);
-void UI_but_unit_type_set(uiBut *but, const int unit_type);
+void UI_but_unit_type_set(uiBut *but, int unit_type);
int UI_but_unit_type_get(const uiBut *but);
typedef enum uiStringInfoType {
@@ -1793,7 +1638,7 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
void *user_data,
struct PropertyRNA *prop_activate_init,
eButLabelAlign label_align,
- const bool compact);
+ bool compact);
/**
* Public function exported for functions that use #UI_BTYPE_SEARCH_MENU.
@@ -1813,7 +1658,7 @@ bool UI_search_item_add(uiSearchItems *items,
void *poin,
int iconid,
int state,
- const uint8_t name_prefix_offset);
+ uint8_t name_prefix_offset);
/**
* \note The item-pointer (referred to below) is a per search item user pointer
@@ -1834,7 +1679,7 @@ void UI_but_func_search_set(uiBut *but,
uiButSearchCreateFn search_create_fn,
uiButSearchUpdateFn search_update_fn,
void *arg,
- const bool free_arg,
+ bool free_arg,
uiFreeArgFunc search_arg_free_fn,
uiButHandleFunc search_exec_fn,
void *active);
@@ -1845,7 +1690,7 @@ void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn)
* 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);
+void UI_but_func_search_set_results_are_suggestions(uiBut *but, bool value);
/**
* Height in pixels, it's using hard-coded values still.
@@ -2070,7 +1915,7 @@ void UI_region_handlers_add(struct ListBase *handlers);
void UI_popup_handlers_add(struct bContext *C,
struct ListBase *handlers,
uiPopupBlockHandle *popup,
- const char flag);
+ char flag);
void UI_popup_handlers_remove(struct ListBase *handlers, uiPopupBlockHandle *popup);
void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers);
@@ -2196,6 +2041,7 @@ uiLayout *UI_block_layout(uiBlock *block,
const struct uiStyle *style);
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y);
+bool UI_block_layout_needs_resolving(const uiBlock *block);
/**
* Used for property search when the layout process needs to be cancelled in order to avoid
* computing the locations for buttons, but the layout items created while adding the buttons
@@ -2319,7 +2165,7 @@ void uiTemplateID(uiLayout *layout,
const char *openop,
const char *unlinkop,
int filter,
- const bool live_icon,
+ bool live_icon,
const char *text);
void uiTemplateIDBrowse(uiLayout *layout,
struct bContext *C,
@@ -2340,7 +2186,7 @@ void uiTemplateIDPreview(uiLayout *layout,
int rows,
int cols,
int filter,
- const bool hide_buttons);
+ bool hide_buttons);
/**
* Version of #uiTemplateID using tabs.
*/
@@ -2384,8 +2230,8 @@ void uiTemplateSearchPreview(uiLayout *layout,
const char *searchpropname,
const char *newop,
const char *unlinkop,
- const int rows,
- const int cols);
+ int rows,
+ int cols);
/**
* This is creating/editing RNA-Paths
*
@@ -2544,11 +2390,49 @@ void uiTemplateComponentMenu(uiLayout *layout,
const char *propname,
const char *name);
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float color[4]);
+
+/**
+ * Draw the main CacheFile properties and operators (file path, scale, etc.), that is those which
+ * do not have their own dedicated template functions.
+ */
void uiTemplateCacheFile(uiLayout *layout,
const struct bContext *C,
struct PointerRNA *ptr,
const char *propname);
+/**
+ * Lookup the CacheFile PointerRNA of the given pointer and return it in the output parameter.
+ * Returns true if `ptr` has a RNACacheFile, false otherwise. If false, the output parameter is not
+ * initialized.
+ */
+bool uiTemplateCacheFilePointer(struct PointerRNA *ptr,
+ const char *propname,
+ struct PointerRNA *r_file_ptr);
+
+/**
+ * Draw the velocity related properties of the CacheFile.
+ */
+void uiTemplateCacheFileVelocity(uiLayout *layout, struct PointerRNA *fileptr);
+
+/**
+ * Draw the render procedural related properties of the CacheFile.
+ */
+void uiTemplateCacheFileProcedural(uiLayout *layout,
+ const struct bContext *C,
+ struct PointerRNA *fileptr);
+
+/**
+ * Draw the time related properties of the CacheFile.
+ */
+void uiTemplateCacheFileTimeSettings(uiLayout *layout, struct PointerRNA *fileptr);
+
+/**
+ * Draw the override layers related properties of the CacheFile.
+ */
+void uiTemplateCacheFileLayers(uiLayout *layout,
+ const struct bContext *C,
+ struct PointerRNA *fileptr);
+
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
enum uiTemplateListFlags {
@@ -2661,7 +2545,7 @@ void uiTemplateAssetView(struct uiLayout *layout,
struct PointerRNA *active_dataptr,
const char *active_propname,
const struct AssetFilterSettings *filter_settings,
- const int display_flags,
+ int display_flags,
const char *activate_opname,
struct PointerRNA *r_activate_op_properties,
const char *drag_opname,
@@ -2870,8 +2754,7 @@ typedef struct uiPropertySplitWrapper {
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);
+void uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert);
/**
* Helper to add a label and creates a property split layout if needed.
*/
@@ -2982,7 +2865,7 @@ const char *UI_layout_introspect(uiLayout *layout);
* 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);
+uiLayout *uiItemsAlertBox(uiBlock *block, int size, eAlertIcon icon);
/* UI Operators */
typedef struct uiDragColorHandle {
@@ -3007,6 +2890,13 @@ 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);
@@ -3074,15 +2964,17 @@ void UI_fontstyle_set(const struct uiFontStyle *fs);
void UI_fontstyle_draw_ex(const struct uiFontStyle *fs,
const struct rcti *rect,
const char *str,
+ size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params,
- size_t len,
int *r_xofs,
int *r_yofs,
struct ResultBLF *r_info);
+
void UI_fontstyle_draw(const struct uiFontStyle *fs,
const struct rcti *rect,
const char *str,
+ size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params);
/**
@@ -3124,7 +3016,7 @@ int UI_fontstyle_string_width(const struct uiFontStyle *fs,
*/
int UI_fontstyle_string_width_with_block_aspect(const struct uiFontStyle *fs,
const char *str,
- const float aspect) ATTR_WARN_UNUSED_RESULT
+ float aspect) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
int UI_fontstyle_height_max(const struct uiFontStyle *fs);
diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh
index d18ec009108..8d1ca54b7a1 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -31,8 +31,8 @@ namespace blender::nodes::geometry_nodes_eval_log {
struct GeometryAttributeInfo;
}
-struct uiBlock;
struct StructRNA;
+struct uiBlock;
struct uiSearchItems;
namespace blender::ui {
@@ -59,10 +59,10 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path);
void attribute_search_add_items(
StringRefNull str,
- const bool is_output,
+ bool is_output,
Span<const nodes::geometry_nodes_eval_log::GeometryAttributeInfo *> infos,
uiSearchItems *items,
- const bool is_first);
+ bool is_first);
} // namespace blender::ui
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index 242b8504ae1..1009ae5cd3f 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -82,13 +82,27 @@ int UI_icon_get_height(int icon_id);
bool UI_icon_get_theme_color(int icon_id, unsigned char color[4]);
/**
+ * Render a #PreviewImage for the data block.
+ *
* 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);
+ enum eIconSizes size,
+ bool use_job);
+
+/**
+ * Render the data block into the provided #PreviewImage.
+ */
+void UI_icon_render_id_ex(const struct bContext *C,
+ struct Scene *scene,
+ struct ID *id_to_render,
+ const enum eIconSizes size,
+ const bool use_job,
+ struct PreviewImage *r_preview_image);
+
+
/**
* Render size for preview images and icons
*/
@@ -108,7 +122,7 @@ void UI_icon_draw_ex(float x,
float alpha,
float desaturate,
const uchar mono_color[4],
- const bool mono_border);
+ bool mono_border);
void UI_icons_free(void);
void UI_icons_free_drawinfo(void *drawinfo);
@@ -121,13 +135,10 @@ int UI_iconfile_get_index(const char *filename);
struct PreviewImage *UI_icon_to_preview(int icon_id);
-int UI_icon_from_rnaptr(const struct bContext *C,
- struct PointerRNA *ptr,
- int rnaicon,
- const bool big);
-int UI_icon_from_idcode(const int idcode);
+int UI_icon_from_rnaptr(const struct bContext *C, struct PointerRNA *ptr, int rnaicon, bool big);
+int UI_icon_from_idcode(int idcode);
int UI_icon_from_library(const struct ID *id);
-int UI_icon_from_object_mode(const int mode);
+int UI_icon_from_object_mode(int mode);
int UI_icon_color_from_collection(const struct Collection *collection);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 98e141c65b5..40e4d8cee9c 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -502,7 +502,7 @@ int UI_ThemeMenuShadowWidth(void);
*/
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);
+void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3], char axis);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index 8208f8daf5d..8dee88defb3 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -40,8 +40,8 @@ struct uiBlock;
struct uiBut;
struct uiButTreeRow;
struct uiLayout;
-struct wmEvent;
struct wmDrag;
+struct wmEvent;
namespace blender::ui {
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 37246c2fe8f..a3f39e1286e 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -175,7 +175,7 @@ void UI_view2d_view_ortho(const struct View2D *v2d);
* \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);
+void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, bool xaxis);
/**
* Restore view matrices after drawing.
*/
@@ -435,7 +435,7 @@ void ED_keymap_view2d(struct wmKeyConfig *keyconf);
void UI_view2d_smooth_view(struct bContext *C,
struct ARegion *region,
const struct rctf *cur,
- const int smooth_viewtx);
+ int smooth_viewtx);
#define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC)
#define UI_TIME_SCRUB_MARGIN_Y (23 * UI_DPI_FAC)
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index bc3075f9de8..95c9f7cc8b2 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -24,8 +24,8 @@ set(INC
../../blentranslation
../../depsgraph
../../draw
- ../../gpu
../../functions
+ ../../gpu
../../imbuf
../../makesdna
../../makesrna
@@ -71,8 +71,8 @@ set(SRC
interface_regions.c
interface_style.c
interface_template_asset_view.cc
- interface_template_list.cc
interface_template_attribute_search.cc
+ interface_template_list.cc
interface_template_search_menu.cc
interface_template_search_operator.c
interface_templates.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index df508b87ce4..636281ba373 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -661,8 +661,43 @@ static float ui_but_get_float_precision(uiBut *but)
return but->a2;
}
+static float ui_but_get_float_step_size(uiBut *but)
+{
+ if (but->type == UI_BTYPE_NUM) {
+ return ((uiButNumber *)but)->step_size;
+ }
+
+ return but->a1;
+}
+
+static bool ui_but_hide_fraction(uiBut *but, double value)
+{
+ /* Hide the fraction if both the value and the step are exact integers. */
+ if (floor(value) == value) {
+ const float step = ui_but_get_float_step_size(but) * UI_PRECISION_FLOAT_SCALE;
+
+ if (floorf(step) == step) {
+ /* Don't hide if it has any unit except frame count. */
+ switch (UI_but_unit_type_get(but)) {
+ case PROP_UNIT_NONE:
+ case PROP_UNIT_TIME:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ return false;
+}
+
static int ui_but_calc_float_precision(uiBut *but, double value)
{
+ if (ui_but_hide_fraction(but, value)) {
+ return 0;
+ }
+
int prec = (int)ui_but_get_float_precision(but);
/* first check for various special cases:
@@ -2813,8 +2848,14 @@ void ui_but_string_get_ex(uiBut *but,
}
if (ui_but_is_float(but)) {
- int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) :
- float_precision;
+ int prec = float_precision;
+
+ if (float_precision == -1) {
+ prec = ui_but_calc_float_precision(but, value);
+ }
+ else if (!use_exp_float && ui_but_hide_fraction(but, value)) {
+ prec = 0;
+ }
if (ui_but_is_unit(but)) {
ui_get_but_string_unit(but, str, maxlen, value, false, prec);
@@ -4859,7 +4900,7 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname)
BLI_strncpy(autoname, autocpl->truncate, autocpl->maxlen);
}
else {
- if (autoname != autocpl->startname) { /* don't copy a string over its self */
+ if (autoname != autocpl->startname) { /* don't copy a string over itself */
BLI_strncpy(autoname, autocpl->startname, autocpl->maxlen);
}
}
@@ -4943,38 +4984,6 @@ uiBut *uiDefButF(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefButI(uiBlock *block,
int type,
int retval,
@@ -5295,68 +5304,6 @@ static uiBut *uiDefIconButBit(uiBlock *block,
tip);
}
-uiBut *uiDefIconButF(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconBut(block,
- type | UI_BUT_POIN_FLOAT,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconButI(uiBlock *block,
int type,
int retval,
@@ -5481,36 +5428,6 @@ uiBut *uiDefIconButBitS(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconBut(block,
- type | UI_BUT_POIN_CHAR,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconButBitC(uiBlock *block,
int type,
int bit,
@@ -5640,44 +5557,6 @@ uiBut *uiDefIconTextBut(uiBlock *block,
but->drawflag |= UI_BUT_ICON_LEFT;
return but;
}
-static uiBut *uiDefIconTextButBit(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- void *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- const int bitIdx = findBitIndex(bit);
- if (bitIdx == -1) {
- return NULL;
- }
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_BIT | bitIdx,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-
uiBut *uiDefIconTextButF(uiBlock *block,
int type,
int retval,
@@ -5710,40 +5589,6 @@ uiBut *uiDefIconTextButF(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconTextButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconTextButI(uiBlock *block,
int type,
int retval,
@@ -5776,172 +5621,6 @@ uiBut *uiDefIconTextButI(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconTextButBitI(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- int *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_INT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButS(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_SHORT,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButBitS(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_SHORT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_CHAR,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButBitC(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_CHAR,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconTextButR(uiBlock *block,
int type,
int retval,
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 285c82b0fb3..f7492e56b62 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -57,6 +57,7 @@
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
#include "UI_interface.h"
@@ -324,17 +325,17 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region),
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(&state,
- (float)rect->xmin,
- (float)rect->ymin,
- ibuf->x,
- ibuf->y,
- GPU_RGBA8,
- false,
- ibuf->rect,
- 1.0f,
- 1.0f,
- col);
+ immDrawPixelsTexTiled(&state,
+ (float)rect->xmin,
+ (float)rect->ymin,
+ ibuf->x,
+ ibuf->y,
+ GPU_RGBA8,
+ false,
+ ibuf->rect,
+ 1.0f,
+ 1.0f,
+ col);
GPU_blend(GPU_BLEND_NONE);
@@ -1384,10 +1385,16 @@ void ui_draw_but_UNITVEC(uiBut *but,
GPU_matrix_scale_1f(size);
GPUBatch *sphere = GPU_batch_preset_sphere(2);
+ struct SimpleLightingData simple_lighting_data;
+ copy_v4_fl4(simple_lighting_data.color, diffuse[0], diffuse[1], diffuse[2], 1.0f);
+ copy_v3_v3(simple_lighting_data.light, light);
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(struct SimpleLightingData), &simple_lighting_data, __func__);
+
GPU_batch_program_set_builtin(sphere, GPU_SHADER_SIMPLE_LIGHTING);
- GPU_batch_uniform_4f(sphere, "color", diffuse[0], diffuse[1], diffuse[2], 1.0f);
- GPU_batch_uniform_3fv(sphere, "light", light);
+ GPU_batch_uniformbuf_bind(sphere, "simple_lighting_data", ubo);
GPU_batch_draw(sphere);
+ GPU_uniformbuf_free(ubo);
/* Restore. */
GPU_face_culling(GPU_CULL_NONE);
@@ -2128,17 +2135,17 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region),
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(&state,
- rect.xmin,
- rect.ymin + 1,
- drawibuf->x,
- drawibuf->y,
- GPU_RGBA8,
- true,
- drawibuf->rect,
- 1.0f,
- 1.0f,
- NULL);
+ immDrawPixelsTexTiled(&state,
+ rect.xmin,
+ rect.ymin + 1,
+ drawibuf->x,
+ drawibuf->y,
+ GPU_RGBA8,
+ true,
+ drawibuf->rect,
+ 1.0f,
+ 1.0f,
+ NULL);
/* draw cross for pixel position */
GPU_matrix_translate_2f(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1]);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 27fa2e5a22f..fd03cc5e12c 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -146,8 +146,8 @@ void eyedropper_draw_cursor_text_region(const int x, const int y, const char *na
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
- const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
+ const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->xy);
uiBut *but = ui_but_find_mouse_over(region, event);
@@ -163,13 +163,13 @@ void datadropper_win_area_find(
bScreen *screen = CTX_wm_screen(C);
*r_win = CTX_wm_window(C);
- *r_area = BKE_screen_find_area_xy(screen, -1, mval[0], mval[1]);
+ *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mval);
if (*r_area == NULL) {
wmWindowManager *wm = CTX_wm_manager(C);
*r_win = WM_window_find_under_cursor(wm, NULL, *r_win, mval, r_mval);
if (*r_win) {
screen = WM_window_get_active_screen(*r_win);
- *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval[0], r_mval[1]);
+ *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval);
}
}
else if (mval != r_mval) {
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 0ac6ea4021b..05840175fab 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -42,6 +42,8 @@
#include "BKE_node.h"
#include "BKE_screen.h"
+#include "NOD_composite.h"
+
#include "RNA_access.h"
#include "UI_interface.h"
@@ -263,32 +265,32 @@ static bool eyedropper_cryptomatte_sample_fl(
}
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
- if (!sa || !ELEM(sa->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my});
+ if (!area || !ELEM(area->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
return false;
}
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
if (!region) {
return false;
}
int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
float fpos[2] = {-1.0f, -1.0};
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_get_position(sima, region, mval, fpos);
break;
}
case SPACE_NODE: {
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
ED_space_node_get_position(bmain, snode, region, mval, fpos);
break;
}
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_space_clip_get_position(sc, region, mval, fpos);
break;
}
@@ -337,7 +339,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
if (area) {
if (area->spacetype == SPACE_IMAGE) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceImage *sima = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
@@ -348,7 +350,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
else if (area->spacetype == SPACE_NODE) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceNode *snode = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
@@ -359,7 +361,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
else if (area->spacetype == SPACE_CLIP) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceClip *sc = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 261aa997d06..cf53ef0ec75 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -162,7 +162,7 @@ static void datadropper_id_sample_pt(
if (area) {
if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
if (region) {
const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
Base *base;
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index 4172c474f4a..8c6b0ac9cfe 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -157,7 +157,7 @@ static void depthdropper_depth_sample_pt(
{
/* we could use some clever */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my});
Scene *scene = CTX_data_scene(C);
ScrArea *area_prev = CTX_wm_area(C);
@@ -167,7 +167,7 @@ static void depthdropper_depth_sample_pt(
if (area) {
if (area->spacetype == SPACE_VIEW3D) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
if (region) {
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
View3D *v3d = area->spacedata.first;
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
index ccf0e727da8..6fe930b74d2 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -107,7 +107,7 @@ static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *eve
char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop);
/* ... and destination */
- char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL);
+ char *dst_path = RNA_path_from_ID_to_property(&ddr->ptr, ddr->prop);
/* Now create driver(s) */
if (target_path && dst_path) {
diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h
index 17bb78a7861..ec448ef9b9f 100644
--- a/source/blender/editors/interface/interface_eyedropper_intern.h
+++ b/source/blender/editors/interface/interface_eyedropper_intern.h
@@ -25,7 +25,7 @@
/* 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);
+void eyedropper_draw_cursor_text_region(int x, int y, const char *name);
/**
* Utility to retrieve a button representing a RNA property that is currently under the cursor.
*
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index f947572f41b..905fd452b6c 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -1787,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;
@@ -1821,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);
}
}
@@ -3515,8 +3495,17 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
ui_but_update(but);
- /* Popup blocks don't support moving after creation, so don't change the view for them. */
- if (!data->searchbox) {
+ /* Make sure the edited button is in view. */
+ if (data->searchbox) {
+ /* Popup blocks don't support moving after creation, so don't change the view for them. */
+ }
+ else if (UI_block_layout_needs_resolving(but->block)) {
+ /* Layout isn't resolved yet (may happen when activating while drawing through
+ * #UI_but_active_only()), so can't move it into view yet. This causes
+ * #ui_but_update_view_for_active() to run after the layout is resolved. */
+ but->changed = true;
+ }
+ else {
UI_but_ensure_in_view(C, data->region, but);
}
@@ -3773,7 +3762,12 @@ static void ui_do_but_textedit(
case EVT_VKEY:
case EVT_XKEY:
case EVT_CKEY:
- if (IS_EVENT_MOD(event, ctrl, oskey)) {
+#if defined(__APPLE__)
+ if ((event->oskey && !IS_EVENT_MOD(event, shift, alt, ctrl)) ||
+ (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey))) {
+#else
+ if (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey)) {
+#endif
if (event->type == EVT_VKEY) {
changed = ui_textedit_copypaste(but, data, UI_TEXTEDIT_PASTE);
}
@@ -5490,7 +5484,7 @@ static int ui_do_but_NUM(
log10f(number_but->step_size));
}
else {
- value_step = (double)number_but->step_size * UI_PRECISION_FLOAT_SCALE;
+ value_step = (double)(number_but->step_size * UI_PRECISION_FLOAT_SCALE);
}
BLI_assert(value_step > 0.0f);
const double value_test = (but->drawflag & UI_BUT_ACTIVE_LEFT) ?
@@ -7938,7 +7932,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
const bool do_copy = event->type == EVT_CKEY && is_press_ctrl_but_no_shift;
const bool do_paste = event->type == EVT_VKEY && is_press_ctrl_but_no_shift;
- /* Specific handling for listrows, we try to find their overlapping tex button. */
+ /* Specific handling for list-rows, we try to find their overlapping text button. */
if ((do_copy || do_paste) && but->type == UI_BTYPE_LISTROW) {
uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_OVER);
if (labelbut) {
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index ca5d08ba40e..c0d6b8a1a6c 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -31,6 +31,7 @@
#include "GPU_batch_presets.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
#include "GPU_texture.h"
@@ -1478,78 +1479,6 @@ PreviewImage *UI_icon_to_preview(int icon_id)
return NULL;
}
-/**
- * Version of #icon_draw_rect() that uses the GPU for scaling. This is only used for
- * #ICON_TYPE_IMBUF because it's a back-ported fix for performance issues, see T92922. Only
- * File/Asset Browser use #ICON_TYPE_IMBUF right now, which makes implications more predictable.
- *
- * TODO(Julian): This code is mostly duplicated. #icon_draw_rect() should be ported to use the GPU
- * instead (D13144).
- */
-static void icon_draw_rect_fast(float x,
- float y,
- int w,
- int h,
- float UNUSED(aspect),
- int rw,
- int rh,
- uint *rect,
- float alpha,
- const float desaturate)
-{
- int draw_w = w;
- int draw_h = h;
- int draw_x = x;
- /* We need to round y, to avoid the icon jittering in some cases. */
- int draw_y = round_fl_to_int(y);
-
- /* sanity check */
- if (w <= 0 || h <= 0 || w > 2000 || h > 2000) {
- printf("%s: icons are %i x %i pixels?\n", __func__, w, h);
- BLI_assert_msg(0, "invalid icon size");
- return;
- }
- /* modulate color */
- const float col[4] = {alpha, alpha, alpha, alpha};
-
- float scale_x = 1.0f;
- float scale_y = 1.0f;
- /* rect contains image in 'rendersize', we only scale if needed */
- if (rw != w || rh != h) {
- /* preserve aspect ratio and center */
- if (rw > rh) {
- draw_w = w;
- draw_h = (int)(((float)rh / (float)rw) * (float)w);
- draw_y += (h - draw_h) / 2;
- }
- else if (rw < rh) {
- draw_w = (int)(((float)rw / (float)rh) * (float)h);
- draw_h = h;
- draw_x += (w - draw_w) / 2;
- }
- scale_x = draw_w / (float)rw;
- scale_y = draw_h / (float)rh;
- /* If the image is squared, the `draw_*` initialization values are good. */
- }
-
- /* draw */
- eGPUBuiltinShader shader;
- if (desaturate != 0.0f) {
- shader = GPU_SHADER_2D_IMAGE_DESATURATE_COLOR;
- }
- else {
- shader = GPU_SHADER_2D_IMAGE_COLOR;
- }
- IMMDrawPixelsTexState state = immDrawPixelsTexSetup(shader);
-
- if (shader == GPU_SHADER_2D_IMAGE_DESATURATE_COLOR) {
- immUniform1f("factor", desaturate);
- }
-
- immDrawPixelsTexScaled(
- &state, draw_x, draw_y, rw, rh, GPU_RGBA8, true, rect, scale_x, scale_y, 1.0f, 1.0f, col);
-}
-
static void icon_draw_rect(float x,
float y,
int w,
@@ -1561,7 +1490,6 @@ static void icon_draw_rect(float x,
float alpha,
const float desaturate)
{
- ImBuf *ima = NULL;
int draw_w = w;
int draw_h = h;
int draw_x = x;
@@ -1577,6 +1505,8 @@ static void icon_draw_rect(float x,
/* modulate color */
const float col[4] = {alpha, alpha, alpha, alpha};
+ float scale_x = 1.0f;
+ float scale_y = 1.0f;
/* rect contains image in 'rendersize', we only scale if needed */
if (rw != w || rh != h) {
/* preserve aspect ratio and center */
@@ -1590,13 +1520,9 @@ static void icon_draw_rect(float x,
draw_h = h;
draw_x += (w - draw_w) / 2;
}
+ scale_x = draw_w / (float)rw;
+ scale_y = draw_h / (float)rh;
/* If the image is squared, the `draw_*` initialization values are good. */
-
- /* first allocate imbuf for scaling and copy preview into it */
- ima = IMB_allocImBuf(rw, rh, 32, IB_rect);
- memcpy(ima->rect, rect, rw * rh * sizeof(uint));
- IMB_scaleImBuf(ima, draw_w, draw_h); /* scale it */
- rect = ima->rect;
}
/* draw */
@@ -1613,12 +1539,8 @@ static void icon_draw_rect(float x,
immUniform1f("factor", desaturate);
}
- immDrawPixelsTex(
- &state, draw_x, draw_y, draw_w, draw_h, GPU_RGBA8, false, rect, 1.0f, 1.0f, col);
-
- if (ima) {
- IMB_freeImBuf(ima);
- }
+ immDrawPixelsTexScaledFullSize(
+ &state, draw_x, draw_y, rw, rh, GPU_RGBA8, true, rect, scale_x, scale_y, 1.0f, 1.0f, col);
}
/* High enough to make a difference, low enough so that
@@ -1661,18 +1583,21 @@ static void icon_draw_cache_texture_flush_ex(GPUTexture *texture,
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR);
GPU_shader_bind(shader);
- const int img_binding = GPU_shader_get_texture_binding(shader, "image");
- const int data_loc = GPU_shader_get_uniform(shader, "calls_data");
+ const int data_loc = GPU_shader_get_uniform_block(shader, "multi_rect_data");
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(struct MultiRectCallData), texture_draw_calls->drawcall_cache, __func__);
+ GPU_uniformbuf_bind(ubo, data_loc);
+ const int img_binding = GPU_shader_get_texture_binding(shader, "image");
GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding, false);
- GPU_shader_uniform_vector(
- shader, data_loc, 4, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache);
GPUBatch *quad = GPU_batch_preset_quad();
GPU_batch_set_shader(quad, shader);
GPU_batch_draw_instanced(quad, texture_draw_calls->calls);
GPU_texture_unbind(texture);
+ GPU_uniformbuf_unbind(ubo);
+ GPU_uniformbuf_free(ubo);
texture_draw_calls->calls = 0;
}
@@ -1874,9 +1799,7 @@ static void icon_draw_size(float x,
ImBuf *ibuf = icon->obj;
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
- /* These icons are only used by the File/Asset Browser currently. Without this `_fast()`
- * version, there may be performance issues, see T92922. */
- icon_draw_rect_fast(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate);
+ icon_draw_rect(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate);
GPU_blend(GPU_BLEND_ALPHA);
}
else if (di->type == ICON_TYPE_VECTOR) {
@@ -2026,6 +1949,16 @@ static void ui_id_preview_image_render_size(
}
}
+void UI_icon_render_id_ex(const bContext *C,
+ Scene *scene,
+ ID *id_to_render,
+ const enum eIconSizes size,
+ const bool use_job,
+ PreviewImage *r_preview_image)
+{
+ ui_id_preview_image_render_size(C, scene, id_to_render, r_preview_image, size, use_job);
+}
+
void UI_icon_render_id(
const bContext *C, Scene *scene, ID *id, const enum eIconSizes size, const bool use_job)
{
@@ -2034,19 +1967,21 @@ void UI_icon_render_id(
return;
}
+ ID *id_to_render = id;
+
/* 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;
+ id_to_render = ob->data;
}
}
- if (!ED_preview_id_is_supported(id)) {
+ if (!ED_preview_id_is_supported(id_to_render)) {
return;
}
- ui_id_preview_image_render_size(C, scene, id, pi, size, use_job);
+ UI_icon_render_id_ex(C, scene, id_to_render, size, use_job, pi);
}
static void ui_id_icon_render(const bContext *C, ID *id, bool use_jobs)
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index dc8744aaae9..2d1138b46a7 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -671,7 +671,7 @@ extern void ui_but_v3_get(uiBut *but, float vec[3]);
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);
+ const rcti *rect, float mx, float my, float *r_val_rad, float *r_val_dist);
/**
* Cursor in HSV circle, in float units -1 to 1, to map on radius.
*/
@@ -688,11 +688,11 @@ extern void ui_hsvcube_pos_from_vals(
*/
extern void ui_but_string_get_ex(uiBut *but,
char *str,
- const size_t maxlen,
- const int float_precision,
- const bool use_exp_float,
+ size_t maxlen,
+ int float_precision,
+ 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();
+extern void ui_but_string_get(uiBut *but, char *str, 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).
@@ -722,7 +722,7 @@ extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but)
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);
+void ui_def_but_icon(uiBut *but, int icon, int flag);
/**
* Avoid using this where possible since it's better not to ask for an icon in the first place.
*/
@@ -905,7 +905,7 @@ 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);
+void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, bool reset);
int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *region, uiBut *but, char *str);
bool ui_searchbox_event(struct bContext *C,
struct ARegion *region,
@@ -1000,9 +1000,9 @@ extern int ui_handler_panel_region(struct bContext *C,
extern void ui_draw_aligned_panel(const struct uiStyle *style,
const uiBlock *block,
const rcti *rect,
- const bool show_pin,
- const bool show_background,
- const bool region_search_filter_active);
+ bool show_pin,
+ bool show_background,
+ bool region_search_filter_active);
void ui_panel_tag_search_filter_match(struct Panel *panel);
/* interface_draw.c */
@@ -1013,10 +1013,7 @@ extern void ui_draw_dropshadow(
/**
* Draws in resolution of 48x4 colors.
*/
-void ui_draw_gradient(const rcti *rect,
- const float hsv[3],
- const eButGradientType type,
- const float alpha);
+void ui_draw_gradient(const rcti *rect, const float hsv[3], eButGradientType type, float alpha);
/* based on UI_draw_roundbox_gl_mode,
* check on making a version which allows us to skip some sides */
@@ -1040,7 +1037,7 @@ void ui_draw_but_COLORBAND(uiBut *but, const struct uiWidgetColors *wcol, const
void ui_draw_but_UNITVEC(uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect,
- const float radius);
+ float radius);
void ui_draw_but_CURVE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
@@ -1118,7 +1115,7 @@ extern void ui_but_active_free(const struct bContext *C, uiBut *but);
*/
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);
+extern void ui_but_text_password_hide(char password_str[128], uiBut *but, bool restore);
/**
* Finds the pressed button in an aligned row (typically an expanded enum).
*
@@ -1131,7 +1128,7 @@ 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_add_shortcut(uiBut *but, const char *shortcut_str, bool do_strip);
void ui_but_clipboard_free(void);
bool ui_but_rna_equals(const uiBut *a, const uiBut *b);
bool ui_but_rna_equals_ex(const uiBut *but,
@@ -1272,8 +1269,8 @@ 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);
+void ui_icon_ensure_deferred(const struct bContext *C, int icon_id, bool big);
+int ui_id_icon_get(const struct bContext *C, struct ID *id, bool big);
/* interface_icons_event.c */
@@ -1365,7 +1362,7 @@ bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
* \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_interactive(const uiBut *but, 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;
int ui_but_icon(const uiBut *but);
@@ -1388,7 +1385,7 @@ uiBut *ui_list_find_from_row(const struct ARegion *region,
uiBut *ui_list_row_find_mouse_over(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_list_row_find_from_index(const struct ARegion *region,
- const int index,
+ int index,
uiBut *listbox) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2);
@@ -1400,7 +1397,7 @@ typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata);
*/
uiBut *ui_but_find_mouse_over_ex(const struct ARegion *region,
const int xy[2],
- const bool labeledit,
+ bool labeledit,
const uiButFindPollFn find_poll,
const void *find_custom_data)
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
@@ -1512,11 +1509,8 @@ typedef struct uiRNACollectionSearch {
/* Block has to be stored for freeing butstore (uiBut.block doesn't work with undo). */
uiBlock *butstore_block;
} uiRNACollectionSearch;
-void ui_rna_collection_search_update_fn(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items,
- const bool is_first);
+void ui_rna_collection_search_update_fn(
+ const struct bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
/* interface_ops.c */
@@ -1534,6 +1528,9 @@ uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_bl
uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
const uiTreeViewItemHandle *new_item_handle);
+/* interface_templates.c */
+struct uiListType *UI_UL_cache_file_layers(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index cbdb284c66b..98fcb36b778 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -5661,6 +5661,11 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
}
}
+bool UI_block_layout_needs_resolving(const uiBlock *block)
+{
+ return !BLI_listbase_is_empty(&block->layouts);
+}
+
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
{
uiBlock *block = layout->root->block;
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 0000c850a10..f7424066ad8 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"
@@ -985,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.
*
@@ -995,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;
@@ -1025,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;
}
@@ -1685,9 +1753,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev
bScreen *screen = CTX_wm_screen(C);
const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
ARegion *region_prev = CTX_wm_region(C);
- ARegion *region = screen ? BKE_screen_find_region_xy(
- screen, RGN_TYPE_ANY, event->xy[0], event->xy[1]) :
- NULL;
+ ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : NULL;
if (region == NULL) {
region = region_prev;
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index bc1d3387ad7..135cef5fe53 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -1146,6 +1146,7 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
UI_fontstyle_draw(fontstyle,
&title_rect,
panel->drawname,
+ sizeof(panel->drawname),
title_color,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_LEFT,
diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index f4c99fb3c16..e27dd2a7981 100644
--- a/source/blender/editors/interface/interface_region_search.cc
+++ b/source/blender/editors/interface/interface_region_search.cc
@@ -725,7 +725,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
region->type = &type;
/* create searchbox data */
- uiSearchboxData *data = (uiSearchboxData *)MEM_callocN(sizeof(uiSearchboxData), __func__);
+ uiSearchboxData *data = MEM_cnew<uiSearchboxData>(__func__);
/* set font, get bb */
data->fstyle = style->widget; /* copy struct */
@@ -1021,7 +1021,7 @@ void ui_but_search_refresh(uiButSearch *search_but)
return;
}
- uiSearchItems *items = (uiSearchItems *)MEM_callocN(sizeof(uiSearchItems), __func__);
+ uiSearchItems *items = MEM_cnew<uiSearchItems>(__func__);
/* setup search struct */
items->maxitem = 10;
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index e146443faaa..fe58a6a05ae 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -74,6 +74,8 @@
#define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y)
#define UI_TIP_MAXWIDTH 600
+#define UI_TIP_STR_MAX 1024
+
typedef struct uiTooltipFormat {
enum {
UI_TIP_STYLE_NORMAL = 0,
@@ -214,7 +216,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
/* draw header and active data (is done here to be able to change color) */
rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]);
UI_fontstyle_set(&data->fstyle);
- UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params);
+ UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
/* offset to the end of the last line */
if (field->text_suffix) {
@@ -224,7 +226,8 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
bbox.ymax -= yofs;
rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]);
- UI_fontstyle_draw(&data->fstyle, &bbox, field->text_suffix, drawcol, &fs_params);
+ UI_fontstyle_draw(
+ &data->fstyle, &bbox, field->text_suffix, UI_TIP_STR_MAX, drawcol, &fs_params);
/* undo offset */
bbox.xmin -= xofs;
@@ -243,7 +246,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
/* XXX, needed because we don't have mono in 'U.uifonts' */
BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi);
rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
- UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, drawcol, &fs_params);
+ UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
}
else {
BLI_assert(field->format.style == UI_TIP_STYLE_NORMAL);
@@ -255,7 +258,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region
/* draw remaining data */
rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
UI_fontstyle_set(&data->fstyle);
- UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params);
+ UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params);
}
bbox.ymax -= data->lineh * field->geom.lines;
@@ -1215,12 +1218,12 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
BLI_assert(ELEM(field->format.style, UI_TIP_STYLE_NORMAL, UI_TIP_STYLE_HEADER));
font_id = data->fstyle.uifont_id;
}
- w = BLF_width_ex(font_id, field->text, BLF_DRAW_STR_DUMMY_MAX, &info);
+ w = BLF_width_ex(font_id, field->text, UI_TIP_STR_MAX, &info);
/* check for suffix (enum label) */
if (field->text_suffix && field->text_suffix[0]) {
x_pos = info.width;
- w = max_ii(w, x_pos + BLF_width(font_id, field->text_suffix, BLF_DRAW_STR_DUMMY_MAX));
+ w = max_ii(w, x_pos + BLF_width(font_id, field->text_suffix, UI_TIP_STR_MAX));
}
fontw = max_ii(fontw, w);
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 643fa128d08..44942d508ca 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -140,9 +140,9 @@ static uiFont *uifont_to_blfont(int id)
void UI_fontstyle_draw_ex(const uiFontStyle *fs,
const rcti *rect,
const char *str,
+ const size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params,
- size_t len,
int *r_xofs,
int *r_yofs,
struct ResultBLF *r_info)
@@ -173,20 +173,20 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
BLF_enable(fs->uifont_id, font_flag);
if (fs_params->word_wrap == 1) {
- /* draw from boundbox top */
+ /* Draw from bound-box top. */
yofs = BLI_rcti_size_y(rect) - BLF_height_max(fs->uifont_id);
}
else {
- /* draw from boundbox center */
+ /* Draw from bound-box center. */
const float height = BLF_ascender(fs->uifont_id) + BLF_descender(fs->uifont_id);
yofs = ceil(0.5f * (BLI_rcti_size_y(rect) - height));
}
if (fs_params->align == UI_STYLE_TEXT_CENTER) {
- xofs = floor(0.5f * (BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, len)));
+ xofs = floor(0.5f * (BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, str_len)));
}
else if (fs_params->align == UI_STYLE_TEXT_RIGHT) {
- xofs = BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, len);
+ xofs = BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, str_len);
}
yofs = MAX2(0, yofs);
@@ -196,7 +196,7 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
BLF_position(fs->uifont_id, rect->xmin + xofs, rect->ymin + yofs, 0.0f);
BLF_color4ubv(fs->uifont_id, col);
- BLF_draw_ex(fs->uifont_id, str, len, r_info);
+ BLF_draw_ex(fs->uifont_id, str, str_len, r_info);
BLF_disable(fs->uifont_id, font_flag);
@@ -211,12 +211,11 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
void UI_fontstyle_draw(const uiFontStyle *fs,
const rcti *rect,
const char *str,
+ const size_t str_len,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params)
{
- int xofs, yofs;
-
- UI_fontstyle_draw_ex(fs, rect, str, col, fs_params, BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs, NULL);
+ UI_fontstyle_draw_ex(fs, rect, str, str_len, col, fs_params, NULL, NULL, NULL);
}
void UI_fontstyle_draw_rotated(const uiFontStyle *fs,
@@ -427,11 +426,11 @@ void uiStyleInit(void)
}
if (U.font_path_ui[0]) {
- BLI_strncpy(font_first->filename, U.font_path_ui, sizeof(font_first->filename));
+ BLI_strncpy(font_first->filepath, U.font_path_ui, sizeof(font_first->filepath));
font_first->uifont_id = UIFONT_CUSTOM1;
}
else {
- BLI_strncpy(font_first->filename, "default", sizeof(font_first->filename));
+ BLI_strncpy(font_first->filepath, "default", sizeof(font_first->filepath));
font_first->uifont_id = UIFONT_DEFAULT;
}
@@ -442,7 +441,7 @@ void uiStyleInit(void)
font->blf_id = BLF_load_default(unique);
}
else {
- font->blf_id = BLF_load(font->filename);
+ font->blf_id = BLF_load(font->filepath);
if (font->blf_id == -1) {
font->blf_id = BLF_load_default(unique);
}
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index 13e539b5095..817599605a9 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -1322,6 +1322,7 @@ PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list,
void ED_uilisttypes_ui()
{
WM_uilisttype_add(UI_UL_asset_view());
+ WM_uilisttype_add(UI_UL_cache_file_layers());
}
/** \} */
diff --git a/source/blender/editors/interface/interface_template_search_menu.cc b/source/blender/editors/interface/interface_template_search_menu.cc
index 7a079e01e61..0ce3a0d8af1 100644
--- a/source/blender/editors/interface/interface_template_search_menu.cc
+++ b/source/blender/editors/interface/interface_template_search_menu.cc
@@ -465,6 +465,9 @@ static MenuSearch_Data *menu_items_from_ui_create(
const char *idname_array[] = {
/* While we could include this, it's just showing filenames to load. */
"TOPBAR_MT_file_open_recent",
+ /* Showing undo history is not helpful since users may accidentally undo
+ * an action they intend to run. */
+ "TOPBAR_MT_undo_history",
};
for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
MenuType *mt = WM_menutype_find(idname_array[i], false);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index b8026cbb40c..8330f8c0db7 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2672,7 +2672,7 @@ static void constraint_ops_extra_draw(bContext *C, uiLayout *layout, void *con_v
static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con)
{
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
short proxy_protected, xco = 0, yco = 0;
// int rb_col; // UNUSED
@@ -6395,21 +6395,154 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float color[4])
/** \name Cache File Template
* \{ */
-void uiTemplateCacheFile(uiLayout *layout,
- const bContext *C,
- PointerRNA *ptr,
- const char *propname)
+void uiTemplateCacheFileVelocity(uiLayout *layout, PointerRNA *fileptr)
{
- if (!ptr->data) {
- return;
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiItemR(layout, fileptr, "velocity_name", 0, NULL, ICON_NONE);
+ uiItemR(layout, fileptr, "velocity_unit", 0, NULL, ICON_NONE);
+}
+
+void uiTemplateCacheFileProcedural(uiLayout *layout, const bContext *C, PointerRNA *fileptr)
+{
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiLayout *row, *sub;
+
+ /* Only enable render procedural option if the active engine supports it. */
+ const struct RenderEngineType *engine_type = CTX_data_engine_type(C);
+
+ Scene *scene = CTX_data_scene(C);
+ const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type,
+ scene);
+
+ if (!engine_supports_procedural) {
+ row = uiLayoutRow(layout, false);
+ /* For Cycles, verify that experimental features are enabled. */
+ if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
+ uiItemL(
+ row,
+ TIP_(
+ "The Cycles Alembic Procedural is only available with the experimental feature set"),
+ ICON_INFO);
+ }
+ else {
+ uiItemL(
+ row, TIP_("The active render engine does not have an Alembic Procedural"), ICON_INFO);
+ }
+ }
+
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetActive(row, engine_supports_procedural);
+ uiItemR(row, fileptr, "use_render_procedural", 0, NULL, ICON_NONE);
+
+ const bool use_render_procedural = RNA_boolean_get(fileptr, "use_render_procedural");
+ const bool use_prefetch = RNA_boolean_get(fileptr, "use_prefetch");
+
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row, use_render_procedural);
+ uiItemR(row, fileptr, "use_prefetch", 0, NULL, ICON_NONE);
+
+ sub = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural);
+ uiItemR(sub, fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE);
+}
+
+void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr)
+{
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiLayout *row, *sub, *subsub;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, fileptr, "is_sequence", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame"));
+ sub = uiLayoutRow(row, true);
+ uiLayoutSetPropDecorate(sub, false);
+ uiItemR(sub, fileptr, "override_frame", 0, "", ICON_NONE);
+ subsub = uiLayoutRow(sub, true);
+ uiLayoutSetActive(subsub, RNA_boolean_get(fileptr, "override_frame"));
+ uiItemR(subsub, fileptr, "frame", 0, "", ICON_NONE);
+ uiItemDecoratorR(row, fileptr, "frame", 0);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, fileptr, "frame_offset", 0, NULL, ICON_NONE);
+ uiLayoutSetActive(row, !RNA_boolean_get(fileptr, "is_sequence"));
+}
+
+static void cache_file_layer_item(uiList *UNUSED(ui_list),
+ bContext *UNUSED(C),
+ uiLayout *layout,
+ PointerRNA *UNUSED(dataptr),
+ PointerRNA *itemptr,
+ int UNUSED(icon),
+ PointerRNA *UNUSED(active_dataptr),
+ const char *UNUSED(active_propname),
+ int UNUSED(index),
+ int UNUSED(flt_flag))
+{
+ uiLayout *row = uiLayoutRow(layout, true);
+ uiItemR(row, itemptr, "hide_layer", UI_ITEM_R_NO_BG, "", ICON_NONE);
+ uiItemR(row, itemptr, "filepath", UI_ITEM_R_NO_BG, "", ICON_NONE);
+}
+
+uiListType *UI_UL_cache_file_layers()
+{
+ uiListType *list_type = (uiListType *)MEM_callocN(sizeof(*list_type), __func__);
+
+ BLI_strncpy(list_type->idname, "UI_UL_cache_file_layers", sizeof(list_type->idname));
+ list_type->draw_item = cache_file_layer_item;
+
+ return list_type;
+}
+
+void uiTemplateCacheFileLayers(uiLayout *layout, const bContext *C, PointerRNA *fileptr)
+{
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayout *col = uiLayoutColumn(row, true);
+
+ uiTemplateList(col,
+ (bContext *)C,
+ "UI_UL_cache_file_layers",
+ "cache_file_layers",
+ fileptr,
+ "layers",
+ fileptr,
+ "active_index",
+ "",
+ 1,
+ 5,
+ UILST_LAYOUT_DEFAULT,
+ 1,
+ UI_TEMPLATE_LIST_FLAG_NONE);
+
+ col = uiLayoutColumn(row, true);
+ uiItemO(col, "", ICON_ADD, "cachefile.layer_add");
+ uiItemO(col, "", ICON_REMOVE, "cachefile.layer_remove");
+
+ CacheFile *file = fileptr->data;
+ if (BLI_listbase_count(&file->layers) > 1) {
+ uiItemS_ex(col, 1.0f);
+ uiItemO(col, "", ICON_TRIA_UP, "cachefile.layer_move");
+ uiItemO(col, "", ICON_TRIA_DOWN, "cachefile.layer_move");
}
+}
+bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRNA *r_file_ptr)
+{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
if (!prop) {
printf(
"%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
- return;
+ return false;
}
if (RNA_property_type(prop) != PROP_POINTER) {
@@ -6417,10 +6550,27 @@ void uiTemplateCacheFile(uiLayout *layout,
__func__,
RNA_struct_identifier(ptr->type),
propname);
+ return false;
+ }
+
+ *r_file_ptr = RNA_property_pointer_get(ptr, prop);
+ return true;
+}
+
+void uiTemplateCacheFile(uiLayout *layout,
+ const bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ if (!ptr->data) {
+ return;
+ }
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
return;
}
- PointerRNA fileptr = RNA_property_pointer_get(ptr, prop);
CacheFile *file = fileptr.data;
uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
@@ -6442,7 +6592,7 @@ void uiTemplateCacheFile(uiLayout *layout,
SpaceProperties *sbuts = CTX_wm_space_properties(C);
- uiLayout *row, *sub, *subsub;
+ uiLayout *row, *sub;
uiLayoutSetPropSep(layout, true);
@@ -6451,68 +6601,11 @@ void uiTemplateCacheFile(uiLayout *layout,
sub = uiLayoutRow(row, true);
uiItemO(sub, "", ICON_FILE_REFRESH, "cachefile.reload");
- row = uiLayoutRow(layout, false);
- uiItemR(row, &fileptr, "is_sequence", 0, NULL, ICON_NONE);
-
- /* Only enable render procedural option if the active engine supports it. */
- const struct RenderEngineType *engine_type = CTX_data_engine_type(C);
-
- Scene *scene = CTX_data_scene(C);
- const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type,
- scene);
-
- if (!engine_supports_procedural) {
- row = uiLayoutRow(layout, false);
- /* For Cycles, verify that experimental features are enabled. */
- if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
- uiItemL(
- row,
- TIP_(
- "The Cycles Alembic Procedural is only available with the experimental feature set"),
- ICON_INFO);
- }
- else {
- uiItemL(
- row, TIP_("The active render engine does not have an Alembic Procedural"), ICON_INFO);
- }
- }
-
- row = uiLayoutRow(layout, false);
- uiLayoutSetActive(row, engine_supports_procedural);
- uiItemR(row, &fileptr, "use_render_procedural", 0, NULL, ICON_NONE);
-
- const bool use_render_procedural = RNA_boolean_get(&fileptr, "use_render_procedural");
- const bool use_prefetch = RNA_boolean_get(&fileptr, "use_prefetch");
-
- row = uiLayoutRow(layout, false);
- uiLayoutSetEnabled(row, use_render_procedural);
- uiItemR(row, &fileptr, "use_prefetch", 0, NULL, ICON_NONE);
-
- sub = uiLayoutRow(layout, false);
- uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural);
- uiItemR(sub, &fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE);
-
- row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame"));
- sub = uiLayoutRow(row, true);
- uiLayoutSetPropDecorate(sub, false);
- uiItemR(sub, &fileptr, "override_frame", 0, "", ICON_NONE);
- subsub = uiLayoutRow(sub, true);
- uiLayoutSetActive(subsub, RNA_boolean_get(&fileptr, "override_frame"));
- uiItemR(subsub, &fileptr, "frame", 0, "", ICON_NONE);
- uiItemDecoratorR(row, &fileptr, "frame", 0);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, &fileptr, "frame_offset", 0, NULL, ICON_NONE);
- uiLayoutSetActive(row, !RNA_boolean_get(&fileptr, "is_sequence"));
-
if (sbuts->mainb == BCONTEXT_CONSTRAINT) {
row = uiLayoutRow(layout, false);
uiItemR(row, &fileptr, "scale", 0, IFACE_("Manual Scale"), ICON_NONE);
}
- uiItemR(layout, &fileptr, "velocity_name", 0, NULL, ICON_NONE);
- uiItemR(layout, &fileptr, "velocity_unit", 0, NULL, ICON_NONE);
-
/* TODO: unused for now, so no need to expose. */
#if 0
row = uiLayoutRow(layout, false);
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
index 500834f4434..81b24c75020 100644
--- a/source/blender/editors/interface/interface_view.cc
+++ b/source/blender/editors/interface/interface_view.cc
@@ -60,7 +60,7 @@ AbstractTreeView *UI_block_add_view(uiBlock &block,
StringRef idname,
std::unique_ptr<AbstractTreeView> tree_view)
{
- ViewLink *view_link = OBJECT_GUARDED_NEW(ViewLink);
+ ViewLink *view_link = MEM_new<ViewLink>(__func__);
BLI_addtail(&block.views, view_link);
view_link->view = std::move(tree_view);
@@ -72,7 +72,7 @@ AbstractTreeView *UI_block_add_view(uiBlock &block,
void ui_block_free_views(uiBlock *block)
{
LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) {
- OBJECT_GUARDED_DELETE(link, ViewLink);
+ MEM_delete(link);
}
}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index ad8c0842657..b44496731f7 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -2130,11 +2130,11 @@ static void widget_draw_text(const uiFontStyle *fstyle,
UI_fontstyle_draw_ex(fstyle,
rect,
drawstr + but->ofs,
+ drawlen,
wcol->text,
&(struct uiFontStyleDraw_Params){
.align = align,
},
- drawlen,
&font_xofs,
&font_yofs,
NULL);
@@ -2194,6 +2194,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
UI_fontstyle_draw(fstyle,
rect,
drawstr_right,
+ UI_MAX_DRAW_STR,
col,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_RIGHT,
@@ -5417,11 +5418,11 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
UI_fontstyle_draw_ex(fstyle,
rect,
drawstr,
+ sizeof(drawstr),
wt->wcol.text,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_LEFT,
},
- BLF_DRAW_STR_DUMMY_MAX,
&xofs,
&yofs,
&info);
@@ -5468,6 +5469,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
UI_fontstyle_draw(fstyle,
rect,
hint_drawstr,
+ sizeof(hint_drawstr),
wt->wcol.text,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_RIGHT,
@@ -5523,6 +5525,7 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
UI_fontstyle_draw(fstyle,
&trect,
drawstr,
+ sizeof(drawstr),
text_col,
&(struct uiFontStyleDraw_Params){
.align = text_align,
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 44b5f85050f..cb1c3cedf8e 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../../io/collada
../../io/gpencil
../../io/usd
+ ../../io/wavefront_obj
../../makesdna
../../makesrna
../../windowmanager
@@ -43,6 +44,7 @@ set(SRC
io_gpencil_export.c
io_gpencil_import.c
io_gpencil_utils.c
+ io_obj.c
io_ops.c
io_usd.c
@@ -50,6 +52,7 @@ set(SRC
io_cache.h
io_collada.h
io_gpencil.h
+ io_obj.h
io_ops.h
io_usd.h
)
@@ -57,6 +60,7 @@ set(SRC
set(LIB
bf_blenkernel
bf_blenlib
+ bf_wavefront_obj
)
if(WITH_OPENCOLLADA)
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index bf20c1f6438..4f71a804986 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -26,6 +26,7 @@
#include "DNA_cachefile_types.h"
#include "DNA_space_types.h"
+#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
@@ -36,6 +37,7 @@
#include "BKE_report.h"
#include "RNA_access.h"
+#include "RNA_define.h"
#include "DEG_depsgraph.h"
@@ -46,6 +48,12 @@
#include "io_cache.h"
+static void reload_cachefile(bContext *C, CacheFile *cache_file)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ BKE_cachefile_reload(depsgraph, cache_file);
+}
+
static void cachefile_init(bContext *C, wmOperator *op)
{
PropertyPointerRNA *pprop;
@@ -146,8 +154,7 @@ static int cachefile_reload_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- BKE_cachefile_reload(depsgraph, cache_file);
+ reload_cachefile(C, cache_file);
return OPERATOR_FINISHED;
}
@@ -164,3 +171,160 @@ void CACHEFILE_OT_reload(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/* ***************************** Add Layer Operator **************************** */
+
+static int cachefile_layer_open_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ char filepath[FILE_MAX];
+ Main *bmain = CTX_data_main(C);
+
+ BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
+ BLI_path_extension_replace(filepath, sizeof(filepath), ".abc");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ /* There is no more CacheFile set when returning from the file selector, so store it here. */
+ op->customdata = CTX_data_edit_cachefile(C);
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+
+ UNUSED_VARS(event);
+}
+
+static int cachefile_layer_add_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ CacheFile *cache_file = op->customdata;
+
+ if (!cache_file) {
+ return OPERATOR_CANCELLED;
+ }
+
+ char filename[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filename);
+
+ CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filename);
+
+ if (!layer) {
+ WM_report(RPT_ERROR, "Could not add a layer to the cache file");
+ return OPERATOR_CANCELLED;
+ }
+
+ reload_cachefile(C, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void CACHEFILE_OT_layer_add(wmOperatorType *ot)
+{
+ ot->name = "Add layer";
+ ot->description = "Add an override layer to the archive";
+ ot->idname = "CACHEFILE_OT_layer_add";
+
+ /* api callbacks */
+ ot->invoke = cachefile_layer_open_invoke;
+ ot->exec = cachefile_layer_add_exec;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER,
+ FILE_BLENDER,
+ FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_DEFAULT);
+}
+
+/* ***************************** Remove Layer Operator **************************** */
+
+static int cachefile_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ CacheFile *cache_file = CTX_data_edit_cachefile(C);
+
+ if (!cache_file) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file);
+ BKE_cachefile_remove_layer(cache_file, layer);
+
+ reload_cachefile(C, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void CACHEFILE_OT_layer_remove(wmOperatorType *ot)
+{
+ ot->name = "Add layer";
+ ot->description = "Remove an override layer to the archive";
+ ot->idname = "CACHEFILE_OT_layer_remove";
+
+ /* api callbacks */
+ ot->exec = cachefile_layer_remove_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ***************************** Move Layer Operator **************************** */
+
+static int cachefile_layer_move_exec(bContext *C, wmOperator *op)
+{
+ CacheFile *cache_file = CTX_data_edit_cachefile(C);
+
+ if (!cache_file) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file);
+
+ if (!layer) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (BLI_listbase_link_move(&cache_file->layers, layer, dir)) {
+ cache_file->active_layer = BLI_findindex(&cache_file->layers, layer) + 1;
+ /* Only reload if something moved, might be expensive. */
+ reload_cachefile(C, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CACHEFILE_OT_layer_move(wmOperatorType *ot)
+{
+ static const EnumPropertyItem layer_slot_move[] = {
+ {-1, "UP", 0, "Up", ""},
+ {1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ ot->name = "Move layer";
+ ot->description =
+ "Move layer in the list, layers further down the list will overwrite data from the layers "
+ "higher up";
+ ot->idname = "CACHEFILE_OT_layer_move";
+
+ /* api callbacks */
+ ot->exec = cachefile_layer_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna,
+ "direction",
+ layer_slot_move,
+ 0,
+ "Direction",
+ "Direction to move the active vertex group towards");
+}
diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h
index be6e31842af..297e065434f 100644
--- a/source/blender/editors/io/io_cache.h
+++ b/source/blender/editors/io/io_cache.h
@@ -27,3 +27,7 @@ struct wmOperatorType;
void CACHEFILE_OT_open(struct wmOperatorType *ot);
void CACHEFILE_OT_reload(struct wmOperatorType *ot);
+
+void CACHEFILE_OT_layer_add(struct wmOperatorType *ot);
+void CACHEFILE_OT_layer_remove(struct wmOperatorType *ot);
+void CACHEFILE_OT_layer_move(struct wmOperatorType *ot);
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
new file mode 100644
index 00000000000..2bc2a832d20
--- /dev/null
+++ b/source/blender/editors/io/io_obj.c
@@ -0,0 +1,369 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup editor/io
+ */
+
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "IO_wavefront_obj.h"
+#include "io_obj.h"
+
+static const EnumPropertyItem io_obj_transform_axis_forward[] = {
+ {OBJ_AXIS_X_FORWARD, "X_FORWARD", 0, "X", "Positive X axis"},
+ {OBJ_AXIS_Y_FORWARD, "Y_FORWARD", 0, "Y", "Positive Y axis"},
+ {OBJ_AXIS_Z_FORWARD, "Z_FORWARD", 0, "Z", "Positive Z axis"},
+ {OBJ_AXIS_NEGATIVE_X_FORWARD, "NEGATIVE_X_FORWARD", 0, "-X", "Negative X axis"},
+ {OBJ_AXIS_NEGATIVE_Y_FORWARD, "NEGATIVE_Y_FORWARD", 0, "-Y", "Negative Y axis"},
+ {OBJ_AXIS_NEGATIVE_Z_FORWARD, "NEGATIVE_Z_FORWARD", 0, "-Z (Default)", "Negative Z axis"},
+ {0, NULL, 0, NULL, NULL}};
+
+static const EnumPropertyItem io_obj_transform_axis_up[] = {
+ {OBJ_AXIS_X_UP, "X_UP", 0, "X", "Positive X axis"},
+ {OBJ_AXIS_Y_UP, "Y_UP", 0, "Y (Default)", "Positive Y axis"},
+ {OBJ_AXIS_Z_UP, "Z_UP", 0, "Z", "Positive Z axis"},
+ {OBJ_AXIS_NEGATIVE_X_UP, "NEGATIVE_X_UP", 0, "-X", "Negative X axis"},
+ {OBJ_AXIS_NEGATIVE_Y_UP, "NEGATIVE_Y_UP", 0, "-Y", "Negative Y axis"},
+ {OBJ_AXIS_NEGATIVE_Z_UP, "NEGATIVE_Z_UP", 0, "-Z", "Negative Z axis"},
+ {0, NULL, 0, NULL, NULL}};
+
+static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
+ {DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
+ {DAG_EVAL_VIEWPORT,
+ "DAG_EVAL_VIEWPORT",
+ 0,
+ "Viewport (Default)",
+ "Export objects as they appear in the viewport"},
+ {0, NULL, 0, NULL, NULL}};
+
+static int wm_obj_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ Main *bmain = CTX_data_main(C);
+ char filepath[FILE_MAX];
+
+ if (BKE_main_blendfile_path(bmain)[0] == '\0') {
+ BLI_strncpy(filepath, "untitled", sizeof(filepath));
+ }
+ else {
+ BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
+ }
+
+ BLI_path_extension_replace(filepath, sizeof(filepath), ".obj");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ WM_event_add_fileselect(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_obj_export_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+ struct OBJExportParams export_params;
+ RNA_string_get(op->ptr, "filepath", export_params.filepath);
+ export_params.blen_filepath = CTX_data_main(C)->filepath;
+ export_params.export_animation = RNA_boolean_get(op->ptr, "export_animation");
+ export_params.start_frame = RNA_int_get(op->ptr, "start_frame");
+ export_params.end_frame = RNA_int_get(op->ptr, "end_frame");
+
+ export_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
+ export_params.up_axis = RNA_enum_get(op->ptr, "up_axis");
+ export_params.scaling_factor = RNA_float_get(op->ptr, "scaling_factor");
+ export_params.export_eval_mode = RNA_enum_get(op->ptr, "export_eval_mode");
+
+ export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects");
+ export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv");
+ export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals");
+ export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
+ export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
+ export_params.export_curves_as_nurbs = RNA_boolean_get(op->ptr, "export_curves_as_nurbs");
+
+ export_params.export_object_groups = RNA_boolean_get(op->ptr, "export_object_groups");
+ export_params.export_material_groups = RNA_boolean_get(op->ptr, "export_material_groups");
+ export_params.export_vertex_groups = RNA_boolean_get(op->ptr, "export_vertex_groups");
+ export_params.export_smooth_groups = RNA_boolean_get(op->ptr, "export_smooth_groups");
+ export_params.smooth_groups_bitflags = RNA_boolean_get(op->ptr, "smooth_group_bitflags");
+
+ OBJ_export(C, &export_params);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
+{
+
+ const bool export_animation = RNA_boolean_get(imfptr, "export_animation");
+ const bool export_smooth_groups = RNA_boolean_get(imfptr, "export_smooth_groups");
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
+ /* Animation options. */
+ uiLayout *box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Animation"), ICON_ANIM);
+ uiLayout *col = uiLayoutColumn(box, false);
+ uiLayout *sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "export_animation", 0, NULL, ICON_NONE);
+ sub = uiLayoutColumn(sub, true);
+ uiItemR(sub, imfptr, "start_frame", 0, IFACE_("Frame Start"), ICON_NONE);
+ uiItemR(sub, imfptr, "end_frame", 0, IFACE_("End"), ICON_NONE);
+ uiLayoutSetEnabled(sub, export_animation);
+
+ /* Object Transform options. */
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Object Properties"), ICON_OBJECT_DATA);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "forward_axis", 0, IFACE_("Axis Forward"), ICON_NONE);
+ uiItemR(sub, imfptr, "up_axis", 0, IFACE_("Up"), ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "scaling_factor", 0, NULL, ICON_NONE);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Objects"));
+ uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_eval_mode", 0, IFACE_("Properties"), ICON_NONE);
+
+ /* Options for what to write. */
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Geometry Export"), ICON_EXPORT);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
+ uiItemR(sub, imfptr, "export_uv", 0, IFACE_("UV Coordinates"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_normals", 0, IFACE_("Normals"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Materials"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Grouping"), ICON_GROUP);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
+ uiItemR(sub, imfptr, "export_object_groups", 0, IFACE_("Object Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_material_groups", 0, IFACE_("Material Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_vertex_groups", 0, IFACE_("Vertex Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_smooth_groups", 0, IFACE_("Smooth Groups"), ICON_NONE);
+ sub = uiLayoutColumn(sub, false);
+ uiLayoutSetEnabled(sub, export_smooth_groups);
+ uiItemR(sub, imfptr, "smooth_group_bitflags", 0, IFACE_("Smooth Group Bitflags"), ICON_NONE);
+}
+
+static void wm_obj_export_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ ui_obj_export_settings(op->layout, &ptr);
+}
+
+/**
+ * Return true if any property in the UI is changed.
+ */
+static bool wm_obj_export_check(bContext *C, wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ Scene *scene = CTX_data_scene(C);
+ bool changed = false;
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (!BLI_path_extension_check(filepath, ".obj")) {
+ BLI_path_extension_ensure(filepath, FILE_MAX, ".obj");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ changed = true;
+ }
+
+ {
+ int start = RNA_int_get(op->ptr, "start_frame");
+ int end = RNA_int_get(op->ptr, "end_frame");
+ /* Set the defaults. */
+ if (start == INT_MIN) {
+ start = SFRA;
+ changed = true;
+ }
+ if (end == INT_MAX) {
+ end = EFRA;
+ changed = true;
+ }
+ /* Fix user errors. */
+ if (end < start) {
+ end = start;
+ changed = true;
+ }
+ RNA_int_set(op->ptr, "start_frame", start);
+ RNA_int_set(op->ptr, "end_frame", end);
+ }
+
+ /* Both forward and up axes cannot be the same (or same except opposite sign). */
+ if (RNA_enum_get(op->ptr, "forward_axis") % TOTAL_AXES ==
+ (RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES)) {
+ /* TODO(@ankitm): Show a warning here. */
+ RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES + 1);
+ changed = true;
+ }
+ return changed;
+}
+
+void WM_OT_obj_export(struct wmOperatorType *ot)
+{
+ ot->name = "Export Wavefront OBJ";
+ ot->description = "Save the scene to a Wavefront OBJ file";
+ ot->idname = "WM_OT_obj_export";
+
+ ot->invoke = wm_obj_export_invoke;
+ ot->exec = wm_obj_export_exec;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_obj_export_draw;
+ ot->check = wm_obj_export_check;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
+ FILE_BLENDER,
+ FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_ALPHA);
+
+ /* Animation options. */
+ RNA_def_boolean(ot->srna,
+ "export_animation",
+ false,
+ "Export Animation",
+ "Export multiple frames instead of the current frame only");
+ RNA_def_int(ot->srna,
+ "start_frame",
+ INT_MIN, /* wm_obj_export_check uses this to set SFRA. */
+ INT_MIN,
+ INT_MAX,
+ "Start Frame",
+ "The first frame to be exported",
+ INT_MIN,
+ INT_MAX);
+ RNA_def_int(ot->srna,
+ "end_frame",
+ INT_MAX, /* wm_obj_export_check uses this to set EFRA. */
+ INT_MIN,
+ INT_MAX,
+ "End Frame",
+ "The last frame to be exported",
+ INT_MIN,
+ INT_MAX);
+ /* Object transform options. */
+ RNA_def_enum(ot->srna,
+ "forward_axis",
+ io_obj_transform_axis_forward,
+ OBJ_AXIS_NEGATIVE_Z_FORWARD,
+ "Forward Axis",
+ "");
+ RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", "");
+ RNA_def_float(ot->srna,
+ "scaling_factor",
+ 1.0f,
+ 0.001f,
+ 10000.0f,
+ "Scale",
+ "Upscale the object by this factor",
+ 0.01,
+ 1000.0f);
+ /* File Writer options. */
+ RNA_def_enum(ot->srna,
+ "export_eval_mode",
+ io_obj_export_evaluation_mode,
+ DAG_EVAL_VIEWPORT,
+ "Object Properties",
+ "Determines properties like object visibility, modifiers etc., where they differ "
+ "for Render and Viewport");
+ RNA_def_boolean(ot->srna,
+ "export_selected_objects",
+ false,
+ "Export Selected Objects",
+ "Export only selected objects instead of all supported objects");
+ RNA_def_boolean(ot->srna, "export_uv", true, "Export UVs", "");
+ RNA_def_boolean(ot->srna,
+ "export_normals",
+ true,
+ "Export Normals",
+ "Export per-face normals if the face is flat-shaded, per-face-per-loop "
+ "normals if smooth-shaded");
+ RNA_def_boolean(ot->srna,
+ "export_materials",
+ true,
+ "Export Materials",
+ "Export MTL library. There must be a Principled-BSDF node for image textures to "
+ "be exported to the MTL file");
+ RNA_def_boolean(ot->srna,
+ "export_triangulated_mesh",
+ false,
+ "Export Triangulated Mesh",
+ "All ngons with four or more vertices will be triangulated. Meshes in "
+ "the scene will not be affected. Behaves like Triangulate Modifier with "
+ "ngon-method: \"Beauty\", quad-method: \"Shortest Diagonal\", min vertices: 4");
+ RNA_def_boolean(ot->srna,
+ "export_curves_as_nurbs",
+ false,
+ "Export Curves as NURBS",
+ "Export curves in parametric form instead of exporting as mesh");
+
+ RNA_def_boolean(ot->srna,
+ "export_object_groups",
+ false,
+ "Export Object Groups",
+ "Append mesh name to object name, separated by a '_'");
+ RNA_def_boolean(ot->srna,
+ "export_material_groups",
+ false,
+ "Export Material Groups",
+ "Append mesh name and material name to object name, separated by a '_'");
+ RNA_def_boolean(
+ ot->srna,
+ "export_vertex_groups",
+ false,
+ "Export Vertex Groups",
+ "Export the name of the vertex group of a face. It is approximated "
+ "by choosing the vertex group with the most members among the vertices of a face");
+ RNA_def_boolean(
+ ot->srna,
+ "export_smooth_groups",
+ false,
+ "Export Smooth Groups",
+ "Every smooth-shaded face is assigned group \"1\" and every flat-shaded face \"off\"");
+ RNA_def_boolean(
+ ot->srna, "smooth_group_bitflags", false, "Generate Bitflags for Smooth Groups", "");
+}
diff --git a/source/blender/editors/io/io_obj.h b/source/blender/editors/io/io_obj.h
new file mode 100644
index 00000000000..5a0e6971edd
--- /dev/null
+++ b/source/blender/editors/io/io_obj.h
@@ -0,0 +1,25 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup editor/io
+ */
+
+#pragma once
+
+struct wmOperatorType;
+
+void WM_OT_obj_export(struct wmOperatorType *ot);
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index b2788ee49a2..d9bbd7d8692 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -39,6 +39,7 @@
#include "io_cache.h"
#include "io_gpencil.h"
+#include "io_obj.h"
void ED_operatortypes_io(void)
{
@@ -68,4 +69,10 @@ void ED_operatortypes_io(void)
WM_operatortype_append(CACHEFILE_OT_open);
WM_operatortype_append(CACHEFILE_OT_reload);
+
+ WM_operatortype_append(CACHEFILE_OT_layer_add);
+ WM_operatortype_append(CACHEFILE_OT_layer_remove);
+ WM_operatortype_append(CACHEFILE_OT_layer_move);
+
+ WM_operatortype_append(WM_OT_obj_export);
}
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 9504a8783a0..0e207df7f94 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -722,8 +722,8 @@ void ED_mask_draw_region(
/* find window pixel coordinates of origin */
UI_view2d_view_to_region(&region->v2d, 0.0f, 0.0f, &x, &y);
- /* w = BLI_rctf_size_x(&v2d->tot); */
- /* h = BLI_rctf_size_y(&v2d->tot); */
+ // w = BLI_rctf_size_x(&v2d->tot);
+ // h = BLI_rctf_size_y(&v2d->tot);
zoomx = (float)(BLI_rcti_size_x(&region->winrct) + 1) / BLI_rctf_size_x(&region->v2d.cur);
zoomy = (float)(BLI_rcti_size_y(&region->winrct) + 1) / BLI_rctf_size_y(&region->v2d.cur);
@@ -768,7 +768,8 @@ void ED_mask_draw_region(
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
- immDrawPixelsTex(&state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
+ immDrawPixelsTexTiled(
+ &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
GPU_matrix_pop();
@@ -835,7 +836,7 @@ void ED_mask_draw_frames(
mask_layer_shape = mask_layer_shape->next) {
int frame = mask_layer_shape->frame;
- /* draw_keyframe(i, CFRA, sfra, framelen, 1); */
+ // draw_keyframe(i, CFRA, sfra, framelen, 1);
int height = (frame == cfra) ? 22 : 10;
int x = (frame - sfra) * framelen;
immVertex2i(pos, x, region_bottom);
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index 41ff14dcd5f..19a3b3966a1 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -95,8 +95,8 @@ 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);
-void ED_mask_spline_select_set(struct MaskSpline *spline, const bool do_select);
-void ED_mask_layer_select_set(struct MaskLayer *mask_layer, const bool do_select);
+void ED_mask_spline_select_set(struct MaskSpline *spline, bool do_select);
+void ED_mask_layer_select_set(struct MaskLayer *mask_layer, bool do_select);
void ED_mask_select_toggle_all(struct Mask *mask, int action);
void ED_mask_select_flush_all(struct Mask *mask);
@@ -126,8 +126,8 @@ bool ED_mask_find_nearest_diff_point(const struct bContext *C,
int threshold,
bool feather,
float tangent[2],
- const bool use_deform,
- const bool use_project,
+ bool use_deform,
+ bool use_project,
struct MaskLayer **r_mask_layer,
struct MaskSpline **r_spline,
struct MaskSplinePoint **r_point,
@@ -136,7 +136,7 @@ bool ED_mask_find_nearest_diff_point(const struct bContext *C,
bool ED_mask_feather_find_nearest(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
- const float threshold,
+ float threshold,
struct MaskLayer **r_mask_layer,
struct MaskSpline **r_spline,
struct MaskSplinePoint **r_point,
@@ -145,7 +145,7 @@ bool ED_mask_feather_find_nearest(const struct bContext *C,
struct MaskSplinePoint *ED_mask_point_find_nearest(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
- const float threshold,
+ float threshold,
struct MaskLayer **r_mask_layer,
struct MaskSpline **r_spline,
eMaskWhichHandle *r_which_handle,
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 18fe9cf7ad3..81dc34f894f 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -57,7 +57,7 @@
#define USE_NET_ISLAND_CONNECT
/**
- * Compare selected with its self.
+ * Compare selected with itself.
*/
static int bm_face_isect_self(BMFace *f, void *UNUSED(user_data))
{
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 3772a37ac44..cae781327d5 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2605,6 +2605,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
/**
* Calculate the center and maximum excursion of mesh.
+ * (Considers all meshes in multi-object edit mode)
*/
static void calc_ortho_extent(KnifeTool_OpData *kcd)
{
@@ -2613,6 +2614,7 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
BMIter iter;
BMVert *v;
float min[3], max[3];
+ float ws[3];
INIT_MINMAX(min, max);
for (uint b = 0; b < kcd->objects_len; b++) {
@@ -2620,11 +2622,17 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
em = BKE_editmesh_from_object(ob);
if (kcd->cagecos[b]) {
- minmax_v3v3_v3_array(min, max, kcd->cagecos[b], em->bm->totvert);
+ for (int i = 0; i < em->bm->totvert; i++) {
+ copy_v3_v3(ws, kcd->cagecos[b][i]);
+ mul_m4_v3(ob->obmat, ws);
+ minmax_v3v3_v3(min, max, ws);
+ }
}
else {
BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- minmax_v3v3_v3(min, max, v->co);
+ copy_v3_v3(ws, v->co);
+ mul_m4_v3(ob->obmat, ws);
+ minmax_v3v3_v3(min, max, ws);
}
}
}
@@ -3009,6 +3017,12 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val;
val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe)) {
+ /* If we intersect any of the vertices, don't attempt to intersect the edge. */
+ if (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) ||
+ BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2)) {
+ continue;
+ }
+
knife_project_v2(kcd, kfe->v1->cageco, se1);
knife_project_v2(kcd, kfe->v2->cageco, se2);
int isect_kind = 1;
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 8cfcc96517c..a1a7dfac282 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -388,8 +388,7 @@ static int face_set_extract_modal(bContext *C, wmOperator *op, const wmEvent *ev
* that the mouse clicked in a viewport region and its coordinates can be used to ray-cast
* the PBVH and update the active Face Set ID. */
bScreen *screen = CTX_wm_screen(C);
- ARegion *region = BKE_screen_find_main_region_at_xy(
- screen, SPACE_VIEW3D, event->xy[0], event->xy[1]);
+ ARegion *region = BKE_screen_find_main_region_at_xy(screen, SPACE_VIEW3D, event->xy);
if (!region) {
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 30a453a32ee..e48b5d8255e 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -377,7 +377,7 @@ static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode)
}
}
-/* mesh shortest path select, uses prev-selected edge */
+/* Mesh shortest path select, uses previously-selected edge. */
/* since you want to create paths with multiple selects, it doesn't have extend option */
static void mouse_mesh_shortest_path_edge(Scene *scene,
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index f2311eb926d..949b12f9a65 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -1334,6 +1334,33 @@ static const EnumPropertyItem *select_similar_type_itemf(bContext *C,
return prop_similar_types;
}
+static bool edbm_select_similar_poll_property(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ /* Only show threshold when it is used. */
+ if (STREQ(prop_id, "threshold")) {
+ if (!ELEM(type,
+ SIMVERT_NORMAL,
+ SIMEDGE_BEVEL,
+ SIMEDGE_CREASE,
+ SIMEDGE_DIR,
+ SIMEDGE_LENGTH,
+ SIMEDGE_FACE_ANGLE,
+ SIMFACE_AREA,
+ SIMFACE_PERIMETER,
+ SIMFACE_NORMAL,
+ SIMFACE_COPLANAR)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
void MESH_OT_select_similar(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1347,6 +1374,7 @@ void MESH_OT_select_similar(wmOperatorType *ot)
ot->invoke = WM_menu_invoke;
ot->exec = edbm_select_similar_exec;
ot->poll = ED_operator_editmesh;
+ ot->poll_property = edbm_select_similar_poll_property;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index f22d4bbe580..59c357aa416 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -104,7 +104,7 @@ typedef struct UndoMesh {
int selectmode;
/** \note
- * this isn't a prefect solution, if you edit keys and change shapes this works well
+ * This isn't a perfect solution, if you edit keys and change shapes this works well
* (fixing T32442), but editing shape keys, going into object mode, removing or changing their
* order, then go back into editmode and undo will give issues - where the old index will be
* out of sync with the new object index.
@@ -690,12 +690,12 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key *
em_tmp = BKE_editmesh_create(bm);
*em = *em_tmp;
- /* Calculate face normals and tessellation at once since it's multi-threaded.
- * The vertex normals are stored in the undo-mesh, so this doesn't need to be updated. */
- BKE_editmesh_looptri_calc_ex(em,
- &(const struct BMeshCalcTessellation_Params){
- .face_normals = true,
- });
+ /* Normals should not be stored in the undo mesh, so recalculate them. The edit
+ * mesh is expected to have valid normals and there is no tracked dirty state. */
+ BLI_assert(BKE_mesh_vertex_normals_are_dirty(&um->me));
+
+ /* Calculate face normals and tessellation at once since it's multi-threaded. */
+ BKE_editmesh_looptri_and_normals_calc(em);
em->selectmode = um->selectmode;
bm->selectmode = um->selectmode;
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 013d5e5a661..f3db8f1f0d2 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -334,9 +334,6 @@ void EDBM_mesh_clear(BMEditMesh *em)
/* clear bmesh */
BM_mesh_clear(em->bm);
- /* Free evaluated meshes & cache. */
- BKE_editmesh_free_derived_caches(em);
-
/* free tessellation data */
em->tottri = 0;
MEM_SAFE_FREE(em->looptris);
@@ -1404,8 +1401,6 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
BM_lnorspace_invalidate(em->bm, false);
em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET;
}
- /* Don't keep stale evaluated mesh data around, see: T38872. */
- BKE_editmesh_free_derived_caches(em);
#ifdef DEBUG
{
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index d7d1dc7dcae..0f58752f323 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -1019,11 +1019,6 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
/* Tag edges as sharp according to smooth threshold if needed,
* to preserve autosmooth shading. */
if (me->flag & ME_AUTOSMOOTH) {
- float(*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__);
-
- BKE_mesh_calc_normals_poly(
- me->mvert, me->totvert, me->mloop, me->totloop, me->mpoly, me->totpoly, polynors);
-
BKE_edges_sharp_from_angle_set(me->mvert,
me->totvert,
me->medge,
@@ -1031,11 +1026,9 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
me->mloop,
me->totloop,
me->mpoly,
- polynors,
+ BKE_mesh_poly_normals_ensure(me),
me->totpoly,
me->smoothresh);
-
- MEM_freeN(polynors);
}
CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop);
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index bba142133a6..575e6d66ccd 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -48,7 +48,7 @@ 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,
const char *select_slot,
- const bool select_replace,
+ bool select_replace,
const char *fmt,
...);
/**
@@ -74,7 +74,7 @@ bool EDBM_op_init(
bool EDBM_op_finish(struct BMEditMesh *em,
struct BMOperator *bmop,
struct wmOperator *op,
- const bool do_report);
+ bool do_report);
void EDBM_stats_update(struct BMEditMesh *em);
@@ -110,8 +110,8 @@ struct BMElem *EDBM_elem_from_index_any_multi(struct ViewLayer *view_layer,
*/
bool edbm_extrude_edges_indiv(struct BMEditMesh *em,
struct wmOperator *op,
- const char hflag,
- const bool use_normal_flip);
+ char hflag,
+ bool use_normal_flip);
/* *** editmesh_add.c *** */
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index ebe8b758aa2..c9615698c46 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -1363,8 +1363,7 @@ typedef struct VertPickData {
static void ed_mesh_pick_vert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
VertPickData *data = userData;
if ((data->mvert[index].flag & ME_HIDE) == 0) {
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 9354171a1e4..06e21f91d04 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1742,15 +1742,16 @@ void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
ot->prop = prop;
ED_object_add_generic_props(ot, false);
- RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the collection to add",
- INT32_MIN,
- INT32_MAX);
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the collection to add",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
object_add_drop_xy_props(ot);
}
@@ -3526,6 +3527,8 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
}
basen->object->visibility_flag &= ~OB_HIDE_VIEWPORT;
+ /* Do immediately, as #copy_object_set_idnew() below operates on visible objects. */
+ BKE_base_eval_flags(basen);
/* object_add_duplicate_internal() doesn't deselect other objects, unlike object_add_common() or
* BKE_view_layer_base_deselect_all(). */
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 1b6b0c78037..b903d664c9b 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -108,8 +108,10 @@ typedef struct {
ListBase data;
/** Clear the images before baking */
bool bake_clear;
- /** Bake-filter, aka margin */
- int bake_filter;
+ /** Margin size in pixels. */
+ int bake_margin;
+ /** margin type */
+ char bake_margin_type;
/** mode of baking (displacement, normals, AO) */
short mode;
/** Use low-resolution mesh when baking displacement maps */
@@ -372,7 +374,8 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
/* copy data stored in job descriptor */
bkr.scene = scene;
- bkr.bake_filter = scene->r.bake_filter;
+ bkr.bake_margin = scene->r.bake_margin;
+ bkr.bake_margin_type = scene->r.bake_margin_type;
bkr.mode = scene->r.bake_mode;
bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
bkr.bias = scene->r.bake_biasdist;
@@ -416,7 +419,8 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
/* backup scene settings, so their changing in UI would take no effect on baker */
bkj->scene = scene;
- bkj->bake_filter = scene->r.bake_filter;
+ bkj->bake_margin = scene->r.bake_margin;
+ bkj->bake_margin_type = scene->r.bake_margin_type;
bkj->mode = scene->r.bake_mode;
bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH;
bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR;
@@ -477,7 +481,8 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
/* copy data stored in job descriptor */
bkr.scene = bkj->scene;
- bkr.bake_filter = bkj->bake_filter;
+ bkr.bake_margin = bkj->bake_margin;
+ bkr.bake_margin_type = bkj->bake_margin_type;
bkr.mode = bkj->mode;
bkr.use_lores_mesh = bkj->use_lores_mesh;
bkr.user_scale = bkj->user_scale;
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 0de34e21462..d56d0edd5a2 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -89,6 +89,7 @@ typedef struct BakeAPIRender {
eScenePassType pass_type;
int pass_filter;
int margin;
+ eBakeMarginType margin_type;
bool is_clear;
bool is_selected_to_active;
@@ -184,8 +185,11 @@ static bool write_internal_bake_pixels(Image *image,
const int width,
const int height,
const int margin,
+ const char margin_type,
const bool is_clear,
- const bool is_noncolor)
+ const bool is_noncolor,
+ Mesh const *mesh,
+ char const *uv_layer)
{
ImBuf *ibuf;
void *lock;
@@ -281,7 +285,7 @@ static bool write_internal_bake_pixels(Image *image,
/* margins */
if (margin > 0) {
- RE_bake_margin(ibuf, mask_buffer, margin);
+ RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh, uv_layer);
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
@@ -327,8 +331,11 @@ static bool write_external_bake_pixels(const char *filepath,
const int width,
const int height,
const int margin,
+ const int margin_type,
ImageFormatData *im_format,
- const bool is_noncolor)
+ const bool is_noncolor,
+ Mesh const *mesh,
+ char const *uv_layer)
{
ImBuf *ibuf = NULL;
bool ok = false;
@@ -385,7 +392,7 @@ static bool write_external_bake_pixels(const char *filepath,
mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask");
RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer);
- RE_bake_margin(ibuf, mask_buffer, margin);
+ RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh, uv_layer);
if (mask_buffer) {
MEM_freeN(mask_buffer);
@@ -770,6 +777,7 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr,
ReportList *reports)
{
bool all_ok = true;
+ const Mesh *me = (Mesh *)ob->data;
for (int i = 0; i < targets->num_images; i++) {
BakeImage *bk_image = &targets->images[i];
@@ -780,8 +788,11 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr,
bk_image->width,
bk_image->height,
bkr->margin,
+ bkr->margin_type,
bkr->is_clear,
- targets->is_noncolor);
+ targets->is_noncolor,
+ me,
+ bkr->uv_layer);
/* might be read by UI to set active image for display */
bake_update_image(bkr->area, bk_image->image);
@@ -895,8 +906,11 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr,
bk_image->width,
bk_image->height,
bkr->margin,
+ bkr->margin_type,
&bake->im_format,
- targets->is_noncolor);
+ targets->is_noncolor,
+ me,
+ bkr->uv_layer);
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name);
@@ -1625,6 +1639,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->pass_type = RNA_enum_get(op->ptr, "type");
bkr->pass_filter = RNA_enum_get(op->ptr, "pass_filter");
bkr->margin = RNA_int_get(op->ptr, "margin");
+ bkr->margin_type = RNA_enum_get(op->ptr, "margin_type");
bkr->save_mode = (eBakeSaveMode)RNA_enum_get(op->ptr, "save_mode");
bkr->target = (eBakeTarget)RNA_enum_get(op->ptr, "target");
@@ -1818,6 +1833,11 @@ static void bake_set_props(wmOperator *op, Scene *scene)
RNA_property_int_set(op->ptr, prop, bake->margin);
}
+ prop = RNA_struct_find_property(op->ptr, "margin_type");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_enum_set(op->ptr, prop, bake->margin_type);
+ }
+
prop = RNA_struct_find_property(op->ptr, "use_selected_to_active");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0);
@@ -2008,6 +2028,12 @@ void OBJECT_OT_bake(wmOperatorType *ot)
"Extends the baked result as a post process filter",
0,
64);
+ RNA_def_enum(ot->srna,
+ "margin_type",
+ rna_enum_bake_margin_type_items,
+ R_BAKE_EXTEND,
+ "Margin Type",
+ "Which algorithm to use to generate the margin");
RNA_def_boolean(ot->srna,
"use_selected_to_active",
false,
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 5c3a8fc2277..91a512ae8e9 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -89,7 +89,7 @@ ListBase *ED_object_constraint_active_list(Object *ob)
if (ob->mode & OB_MODE_POSE) {
bPoseChannel *pchan;
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan) {
return &pchan->constraints;
}
@@ -2215,7 +2215,7 @@ static bool get_new_constraint_target(
bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add)
{
Object *obact = ED_object_active_context(C);
- bPoseChannel *pchanact = BKE_pose_channel_active(obact);
+ bPoseChannel *pchanact = BKE_pose_channel_active_if_layer_visible(obact);
bool only_curve = false, only_mesh = false, only_ob = false;
bool found = false;
@@ -2370,7 +2370,7 @@ static int constraint_add_exec(
pchan = NULL;
}
else {
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
/* ensure not to confuse object/pose adding */
if (pchan == NULL) {
@@ -2650,7 +2650,7 @@ void POSE_OT_constraint_add_with_targets(wmOperatorType *ot)
static int pose_ik_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
bConstraint *con = NULL;
uiPopupMenu *pup;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index f06744068d5..38d0a044cb4 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -1638,10 +1638,10 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
/** \name Object Mode Set Operator
* \{ */
-static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
+static const EnumPropertyItem *object_mode_set_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
const EnumPropertyItem *input = rna_enum_object_mode_items;
EnumPropertyItem *item = NULL;
@@ -1790,7 +1790,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(
ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", "");
- RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf);
+ RNA_def_enum_funcs(ot->prop, object_mode_set_itemf);
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index e3c2932e17a..5a6c25caacc 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -533,6 +533,10 @@ static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op,
Object *ob,
int type)
{
+ if (ob == NULL) {
+ return NULL;
+ }
+
char modifier_name[MAX_NAME];
GpencilModifierData *md;
RNA_string_get(op->ptr, "modifier", modifier_name);
@@ -968,6 +972,9 @@ static int dash_segment_add_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
const int new_active_index = dmd->segment_active_index + 1;
DashGpencilModifierSegment *new_segments = MEM_malloc_arrayN(
dmd->segments_len + 1, sizeof(DashGpencilModifierSegment), __func__);
@@ -1032,6 +1039,10 @@ static int dash_segment_remove_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
if (dmd->segment_active_index < 0 || dmd->segment_active_index >= dmd->segments_len) {
return OPERATOR_CANCELLED;
}
@@ -1108,6 +1119,10 @@ static int dash_segment_move_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
if (dmd->segments_len < 2) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 5065a2c00f0..51967ff35c7 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -582,7 +582,7 @@ static int add_hook_object(const bContext *C,
BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget));
- pchan_act = BKE_pose_channel_active(ob);
+ pchan_act = BKE_pose_channel_active_if_layer_visible(ob);
if (LIKELY(pchan_act)) {
invert_m4_m4(pose_mat, pchan_act->pose_mat);
mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]);
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 9a1b4b48464..d517d68f1fc 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -176,8 +176,8 @@ void COLLECTION_OT_objects_remove_active(struct wmOperatorType *ot);
bool edit_modifier_poll_generic(struct bContext *C,
struct StructRNA *rna_type,
int obtype_flag,
- const bool is_editmode_allowed,
- const bool is_liboverride_allowed);
+ bool is_editmode_allowed,
+ bool is_liboverride_allowed);
void edit_modifier_properties(struct wmOperatorType *ot);
bool edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 811f20e82be..a6eb35d49b9 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -583,8 +583,8 @@ bool ED_object_parent_set(ReportList *reports,
}
case PAR_BONE:
case PAR_BONE_RELATIVE:
- pchan = BKE_pose_channel_active(par);
- pchan_eval = BKE_pose_channel_active(parent_eval);
+ pchan = BKE_pose_channel_active_if_layer_visible(par);
+ pchan_eval = BKE_pose_channel_active_if_layer_visible(parent_eval);
if (pchan == NULL) {
BKE_report(reports, RPT_ERROR, "No active bone");
@@ -2355,7 +2355,8 @@ static bool make_override_library_poll(bContext *C)
/* Object must be directly linked to be overridable. */
return (ED_operator_objectmode(C) && obact != NULL &&
(ID_IS_LINKED(obact) || (obact->instance_collection != NULL &&
- ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection))));
+ ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection) &&
+ !ID_IS_OVERRIDE_LIBRARY(obact))));
}
static const EnumPropertyItem *make_override_collections_of_linked_object_itemf(
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index 719ffd36f03..e4103db8e21 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -168,8 +168,6 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
new_mesh = mesh_fixed_poles;
}
- BKE_mesh_calc_normals(new_mesh);
-
if (mesh->flag & ME_REMESH_REPROJECT_VOLUME || mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK ||
mesh->flag & ME_REMESH_REPROJECT_SCULPT_FACE_SETS) {
BKE_mesh_runtime_clear_geometry(mesh);
@@ -463,8 +461,8 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev
Object *active_object = CTX_data_active_object(C);
Mesh *mesh = (Mesh *)active_object->data;
- VoxelSizeEditCustomData *cd = (VoxelSizeEditCustomData *)MEM_callocN(
- sizeof(VoxelSizeEditCustomData), "Voxel Size Edit OP Custom Data");
+ VoxelSizeEditCustomData *cd = MEM_cnew<VoxelSizeEditCustomData>(
+ "Voxel Size Edit OP Custom Data");
/* Initial operator Custom Data setup. */
cd->draw_handle = ED_region_draw_cb_activate(
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index fd649854d8f..a871ddea48c 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -43,13 +43,16 @@
#include "DNA_object_types.h"
#include "BKE_context.h"
+#include "BKE_crazyspace.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_object.h"
+#include "BKE_report.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "BLI_sys_types.h" /* for intptr_t support */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 4c4727f51ee..c9114c7a925 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -811,8 +811,8 @@ static int apply_objects_internal(bContext *C,
/* adjust data */
BKE_mesh_transform(me, mat, true);
- /* update normals */
- BKE_mesh_calc_normals(me);
+ /* If normal layers exist, they are now dirty. */
+ BKE_mesh_normals_tag_dirty(me);
}
else if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;
@@ -1408,6 +1408,19 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
sub_v3_v3(mpt, offset_local);
mul_v3_m4v3(&pt->x, diff_mat, mpt);
}
+
+ /* Apply transform to edit-curve. */
+ if (gps->editcurve != NULL) {
+ for (i = 0; i < gps->editcurve->tot_curve_points; i++) {
+ BezTriple *bezt = &gps->editcurve->curve_points[i].bezt;
+ for (int j = 0; j < 3; j++) {
+ float mpt[3];
+ mul_v3_m4v3(mpt, inverse_diff_mat, bezt->vec[j]);
+ sub_v3_v3(mpt, offset_local);
+ mul_v3_m4v3(bezt->vec[j], diff_mat, mpt);
+ }
+ }
+ }
}
}
}
diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c
index 5f85f6ea0eb..df44d840ad3 100644
--- a/source/blender/editors/object/object_utils.c
+++ b/source/blender/editors/object/object_utils.c
@@ -115,7 +115,7 @@ bool ED_object_calc_active_center_for_posemode(Object *ob,
const bool select_only,
float r_center[3])
{
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) {
copy_v3_v3(r_center, pchan->pose_head);
return true;
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 80e3f934c80..3214180309b 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -373,7 +373,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
/* Show progress bar. */
*(job->do_update) = true;
- /* Set frame to start point (also inits modifier data) */
+ /* Set frame to start point (also initializes modifier data). */
frame = surface->start_frame;
orig_frame = input_scene->r.cfra;
input_scene->r.cfra = (int)frame;
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index f1e6f02cb39..1407ca598a7 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1441,7 +1441,7 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
PTCacheEdit *edit = psys->edit;
Mesh *mesh = edit->psmd_eval->mesh_final;
float *vec, *nor;
- int i, totface /*, totvert*/;
+ int i, totface;
if (!mesh) {
return;
@@ -1454,7 +1454,7 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
BLI_kdtree_3d_free(edit->emitter_field);
totface = mesh->totface;
- // totvert = dm->getNumVerts(dm); /* UNUSED */
+ // int totvert = dm->getNumVerts(dm); /* UNUSED */
edit->emitter_cosnos = MEM_callocN(sizeof(float[6]) * totface, "emitter cosnos");
@@ -1463,26 +1463,28 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
vec = edit->emitter_cosnos;
nor = vec + 3;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+
for (i = 0; i < totface; i++, vec += 6, nor += 6) {
MFace *mface = &mesh->mface[i];
MVert *mvert;
mvert = &mesh->mvert[mface->v1];
copy_v3_v3(vec, mvert->co);
- copy_v3fl_v3s(nor, mvert->no);
+ copy_v3_v3(nor, vert_normals[mface->v1]);
mvert = &mesh->mvert[mface->v2];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v2]);
mvert = &mesh->mvert[mface->v3];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v3]);
if (mface->v4) {
mvert = &mesh->mvert[mface->v4];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v4]);
mul_v3_fl(vec, 0.25);
}
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 367d72b0ad7..987b9e49057 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -743,8 +743,10 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
invert_m4_m4(from_imat, from_mat);
invert_m4_m4(to_imat, to_mat);
- if (target_psmd->mesh_final->runtime.deformed_only) {
- /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
+ const bool use_dm_final_indices = (target_psys->part->use_modifier_stack &&
+ !target_psmd->mesh_final->runtime.deformed_only);
+
+ if (use_dm_final_indices || !target_psmd->mesh_original) {
mesh = target_psmd->mesh_final;
}
else {
@@ -755,6 +757,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
return false;
}
/* don't modify the original vertices */
+ /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
mesh = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE);
/* BMESH_ONLY, deform dm may not have tessface */
@@ -825,7 +828,13 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
tpa->foffset = 0.0f;
tpa->num = nearest.index;
- tpa->num_dmcache = psys_particle_dm_face_lookup(target_mesh, mesh, tpa->num, tpa->fuv, NULL);
+ if (use_dm_final_indices) {
+ tpa->num_dmcache = DMCACHE_ISCHILD;
+ }
+ else {
+ tpa->num_dmcache = psys_particle_dm_face_lookup(
+ target_psmd->mesh_final, target_psmd->mesh_original, tpa->num, tpa->fuv, NULL);
+ }
}
else {
me = &medge[nearest.index];
@@ -930,7 +939,9 @@ static bool connect_hair(Depsgraph *depsgraph, Scene *scene, Object *ob, Particl
ob->obmat,
psys->flag & PSYS_GLOBAL_HAIR,
false);
- psys->flag &= ~PSYS_GLOBAL_HAIR;
+ if (ok) {
+ psys->flag &= ~PSYS_GLOBAL_HAIR;
+ }
return ok;
}
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 46afa390997..1f867c6f1f7 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../../imbuf
../../makesdna
../../makesrna
+ ../../nodes
../../render
../../sequencer
../../windowmanager
@@ -36,15 +37,15 @@ set(INC
)
set(SRC
- render_internal.c
- render_opengl.c
- render_ops.c
- render_preview.c
- render_shading.c
- render_update.c
- render_view.c
+ render_internal.cc
+ render_opengl.cc
+ render_ops.cc
+ render_preview.cc
+ render_shading.cc
+ render_update.cc
+ render_view.cc
- render_intern.h
+ render_intern.hh
)
set(LIB
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.hh
index d374717664b..d374717664b 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.hh
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.cc
index 0ed303d8f6d..8e9a052381c 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.cc
@@ -21,9 +21,9 @@
* \ingroup edrend
*/
-#include <math.h>
-#include <stddef.h>
-#include <string.h>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -50,11 +50,14 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "NOD_composite.h"
+
#include "DEG_depsgraph.h"
#include "WM_api.h"
@@ -77,12 +80,12 @@
#include "SEQ_relations.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/* Render Callbacks */
static int render_break(void *rjv);
-typedef struct RenderJob {
+struct RenderJob {
Main *main;
Scene *scene;
ViewLayer *single_layer;
@@ -109,7 +112,7 @@ typedef struct RenderJob {
ColorManagedDisplaySettings display_settings;
bool supports_glsl_draw;
bool interface_locked;
-} RenderJob;
+};
/* called inside thread! */
static bool image_buffer_calc_tile_rect(const RenderResult *rr,
@@ -121,15 +124,15 @@ static bool image_buffer_calc_tile_rect(const RenderResult *rr,
{
int tile_y, tile_height, tile_x, tile_width;
- /* When `renrect` argument is not NULL, we only refresh scan-lines. */
+ /* When `renrect` argument is not nullptr, we only refresh scan-lines. */
if (renrect) {
- /* if (tile_height == recty), rendering of layer is ready,
+ /* `if (tile_height == recty)`, rendering of layer is ready,
* we should not draw, other things happen... */
- if (rr->renlay == NULL || renrect->ymax >= rr->recty) {
+ if (rr->renlay == nullptr || renrect->ymax >= rr->recty) {
return false;
}
- /* tile_x here is first subrect x coord, tile_width defines subrect width */
+ /* `tile_x` here is first sub-rectangle x coord, tile_width defines sub-rectangle width. */
tile_x = renrect->xmin;
tile_width = renrect->xmax - tile_x;
if (tile_width < 2) {
@@ -189,7 +192,7 @@ static void image_buffer_rect_update(RenderJob *rj,
const char *viewname)
{
Scene *scene = rj->scene;
- const float *rectf = NULL;
+ const float *rectf = nullptr;
int linear_stride, linear_offset_x, linear_offset_y;
ColorManagedViewSettings *view_settings;
ColorManagedDisplaySettings *display_settings;
@@ -230,12 +233,12 @@ static void image_buffer_rect_update(RenderJob *rj,
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
return;
}
- if (rr->renlay == NULL) {
+ if (rr->renlay == nullptr) {
return;
}
rectf = RE_RenderLayerGetPass(rr->renlay, RE_PASSNAME_COMBINED, viewname);
}
- if (rectf == NULL) {
+ if (rectf == nullptr) {
return;
}
@@ -256,7 +259,7 @@ static void image_buffer_rect_update(RenderJob *rj,
IMB_partial_display_buffer_update(ibuf,
rectf,
- NULL,
+ nullptr,
linear_stride,
linear_offset_x,
linear_offset_y,
@@ -315,17 +318,17 @@ static int screen_render_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
ViewLayer *active_layer = CTX_data_view_layer(C);
- ViewLayer *single_layer = NULL;
+ ViewLayer *single_layer = nullptr;
Render *re;
Image *ima;
View3D *v3d = CTX_wm_view3d(C);
Main *mainp = CTX_data_main(C);
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
- struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
+ struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr;
/* Cannot do render if there is not this function. */
- if (re_type->render == NULL) {
+ if (re_type->render == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -342,11 +345,11 @@ static int screen_render_exec(bContext *C, wmOperator *op)
G.is_break = false;
- RE_draw_lock_cb(re, NULL, NULL);
- RE_test_break_cb(re, NULL, render_break);
+ RE_draw_lock_cb(re, nullptr, nullptr);
+ RE_test_break_cb(re, nullptr, render_break);
ima = BKE_image_ensure_viewer(mainp, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(mainp, ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(mainp, ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(scene, ima, true);
/* cleanup sequencer caches before starting user triggered render.
@@ -371,7 +374,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still);
}
- RE_SetReports(re, NULL);
+ RE_SetReports(re, nullptr);
/* No redraw needed, we leave state as we entered it. */
ED_update_for_newframe(mainp, CTX_data_depsgraph_pointer(C));
@@ -383,7 +386,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
static void render_freejob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
BKE_color_managed_view_settings_free(&rj->view_settings);
MEM_freeN(rj);
@@ -471,15 +474,15 @@ static void make_renderinfo_string(const RenderStats *rs,
static void image_renderinfo_cb(void *rjv, RenderStats *rs)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
RenderResult *rr;
rr = RE_AcquireResultRead(rj->re);
if (rr) {
/* malloc OK here, stats_draw is not in tile threads */
- if (rr->text == NULL) {
- rr->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext");
+ if (rr->text == nullptr) {
+ rr->text = static_cast<char *>(MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext"));
}
make_renderinfo_string(rs, rj->scene, rj->v3d_override, rr->error, rr->text);
@@ -493,7 +496,7 @@ static void image_renderinfo_cb(void *rjv, RenderStats *rs)
static void render_progress_update(void *rjv, float progress)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
if (rj->progress && *rj->progress != progress) {
*rj->progress = progress;
@@ -511,20 +514,22 @@ static void render_progress_update(void *rjv, float progress)
static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, ImageUser *iuser)
{
wmWindowManager *wm;
- ScrArea *first_area = NULL, *matched_area = NULL;
+ ScrArea *first_area = nullptr, *matched_area = nullptr;
/* image window, compo node users */
- for (wm = rj->main->wm.first; wm && matched_area == NULL; wm = wm->id.next) { /* only 1 wm */
+ for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm && matched_area == nullptr;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */
wmWindow *win;
- for (win = wm->windows.first; win && matched_area == NULL; win = win->next) {
+ for (win = static_cast<wmWindow *>(wm->windows.first); win && matched_area == nullptr;
+ win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
/* area->spacedata might be empty when toggling full-screen mode. */
- if (sima != NULL && sima->image == rj->image) {
- if (first_area == NULL) {
+ if (sima != nullptr && sima->image == rj->image) {
+ if (first_area == nullptr) {
first_area = area;
}
if (area == rj->area) {
@@ -537,12 +542,12 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
}
}
- if (matched_area == NULL) {
+ if (matched_area == nullptr) {
matched_area = first_area;
}
if (matched_area) {
- SpaceImage *sima = matched_area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(matched_area->spacedata.first);
RenderResult *main_rr = RE_AcquireResultRead(rj->re);
/* TODO(sergey): is there faster way to get the layer index? */
@@ -562,7 +567,7 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
Image *ima = rj->image;
ImBuf *ibuf;
void *lock;
@@ -584,7 +589,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
return;
}
- if (rr == NULL) {
+ if (rr == nullptr) {
return;
}
@@ -628,14 +633,14 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
static void current_scene_update(void *rjv, Scene *scene)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
rj->current_scene = scene;
rj->iuser.scene = scene;
}
static void render_startjob(void *rjv, short *stop, short *do_update, float *progress)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
rj->stop = stop;
rj->do_update = do_update;
@@ -663,7 +668,7 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro
rj->write_still);
}
- RE_SetReports(rj->re, NULL);
+ RE_SetReports(rj->re, nullptr);
}
static void render_image_restore_layer(RenderJob *rj)
@@ -671,15 +676,16 @@ static void render_image_restore_layer(RenderJob *rj)
wmWindowManager *wm;
/* image window, compo node users */
- for (wm = rj->main->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
+ for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */
wmWindow *win;
- for (win = wm->windows.first; win; win = win->next) {
+ for (win = static_cast<wmWindow *>(wm->windows.first); win; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area == rj->area) {
if (area->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
if (RE_HasSingleLayer(rj->re)) {
/* For single layer renders keep the active layer
@@ -705,11 +711,11 @@ static void render_image_restore_layer(RenderJob *rj)
static void render_endjob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
- /* this render may be used again by the sequencer without the active
+ /* This render may be used again by the sequencer without the active
* 'Render' where the callbacks would be re-assigned. assign dummy callbacks
- * to avoid referencing freed renderjobs bug T24508. */
+ * to avoid referencing freed render-jobs bug T24508. */
RE_InitRenderCB(rj->re);
if (rj->main != G_MAIN) {
@@ -731,7 +737,8 @@ static void render_endjob(void *rjv)
rj->scene->r.scemode &= ~R_NO_FRAME_UPDATE;
if (rj->single_layer) {
- nodeUpdateID(rj->scene->nodetree, &rj->scene->id);
+ BKE_ntree_update_tag_id_changed(rj->main, &rj->scene->id);
+ BKE_ntree_update_main(rj->main, nullptr);
WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene);
}
@@ -741,7 +748,7 @@ static void render_endjob(void *rjv)
/* XXX render stability hack */
G.is_rendering = false;
- WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, nullptr);
/* Partial render result will always update display buffer
* for first render layer only. This is nice because you'll
@@ -778,7 +785,7 @@ static void render_endjob(void *rjv)
* and using one from Global will unlock exactly the same manager as
* was locked before running the job.
*/
- WM_set_locked_interface(G_MAIN->wm.first, false);
+ WM_set_locked_interface(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
DEG_tag_on_visible_update(G_MAIN, false);
}
}
@@ -786,7 +793,7 @@ static void render_endjob(void *rjv)
/* called by render, check job 'stop' value or the global */
static int render_breakjob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
if (G.is_break) {
return 1;
@@ -813,7 +820,7 @@ static int render_break(void *UNUSED(rjv))
/* maybe need a way to get job send notifier? */
static void render_drawlock(void *rjv, bool lock)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
/* If interface is locked, renderer callback shall do nothing. */
if (!rj->interface_locked) {
@@ -875,11 +882,12 @@ static void clean_viewport_memory(Main *bmain, Scene *scene)
BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, true);
/* Go over all the visible objects. */
- for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); wm;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- for (base = view_layer->object_bases.first; base; base = base->next) {
+ for (base = static_cast<Base *>(view_layer->object_bases.first); base; base = base->next) {
clean_viewport_memory_base(base);
}
}
@@ -897,7 +905,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *active_layer = CTX_data_view_layer(C);
- ViewLayer *single_layer = NULL;
+ ViewLayer *single_layer = nullptr;
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
Render *re;
wmJob *wm_job;
@@ -906,13 +914,13 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport");
- View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL;
- struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
+ View3D *v3d = use_viewport ? CTX_wm_view3d(C) : nullptr;
+ struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr;
const char *name;
ScrArea *area;
/* Cannot do render if there is not this function. */
- if (re_type->render == NULL) {
+ if (re_type->render == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -968,7 +976,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
area = render_view_open(C, event->xy[0], event->xy[1], op->reports);
/* job custom data */
- rj = MEM_callocN(sizeof(RenderJob), "render job");
+ rj = MEM_cnew<RenderJob>("render job");
rj->main = bmain;
rj->scene = scene;
rj->current_scene = rj->scene;
@@ -992,7 +1000,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings);
if (area) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
rj->orig_layer = sima->iuser.layer;
}
@@ -1036,7 +1044,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
WM_JOB_TYPE_RENDER);
WM_jobs_customdata_set(wm_job, rj, render_freejob);
WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0);
- WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob);
+ WM_jobs_callbacks(wm_job, render_startjob, nullptr, nullptr, render_endjob);
if (RNA_struct_property_is_set(op->ptr, "layer")) {
WM_jobs_delay_start(wm_job, 0.2);
@@ -1044,7 +1052,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
/* get a render result image, and make sure it is empty */
ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(rj->main, ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(rj->main, ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(rj->scene, ima, true);
rj->image = ima;
@@ -1104,32 +1112,32 @@ void RENDER_OT_render(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna,
"animation",
- 0,
+ false,
"Animation",
"Render files from the animation range of this scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_boolean(
ot->srna,
"write_still",
- 0,
+ false,
"Write Image",
"Save rendered the image to the output path (used only when animation is disabled)");
prop = RNA_def_boolean(ot->srna,
"use_viewport",
- 0,
+ false,
"Use 3D Viewport",
"When inside a 3D viewport, use layers and camera of the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_string(ot->srna,
"layer",
- NULL,
+ nullptr,
RE_MAXNAME,
"Render Layer",
"Single render layer to re-render (used only when animation is disabled)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_string(ot->srna,
"scene",
- NULL,
+ nullptr,
MAX_ID_NAME - 2,
"Scene",
"Scene to render, current scene if not specified");
@@ -1145,7 +1153,7 @@ Scene *ED_render_job_get_scene(const bContext *C)
return rj->scene;
}
- return NULL;
+ return nullptr;
}
Scene *ED_render_job_get_current_scene(const bContext *C)
@@ -1155,7 +1163,7 @@ Scene *ED_render_job_get_current_scene(const bContext *C)
if (rj) {
return rj->current_scene;
}
- return NULL;
+ return nullptr;
}
/* Motion blur curve preset */
@@ -1186,7 +1194,7 @@ void RENDER_OT_shutter_curve_preset(wmOperatorType *ot)
{CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
{CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
{CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
ot->name = "Shutter Curve Preset";
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.cc
index 1e1a95f2965..8bd0244c899 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.cc
@@ -21,9 +21,9 @@
* \ingroup render
*/
-#include <math.h>
-#include <stddef.h>
-#include <string.h>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -82,7 +82,7 @@
#include "GPU_framebuffer.h"
#include "GPU_matrix.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/* Define this to get timing information. */
// #define DEBUG_TIME
@@ -92,10 +92,10 @@
#endif
/* TODO(sergey): Find better approximation of the scheduled frames.
- * For really highres renders it might fail still. */
+ * For really high-resolution renders it might fail still. */
#define MAX_SCHEDULED_FRAMES 8
-typedef struct OGLRender {
+struct OGLRender {
Main *bmain;
Render *re;
Scene *scene;
@@ -141,7 +141,7 @@ typedef struct OGLRender {
wmWindowManager *wm;
wmWindow *win;
- /** Use to check if running modal or not (invoke'd or exec'd). */
+ /** Use to check if running modal or not (invoked or executed). */
wmTimer *timer;
void **movie_ctx_arr;
@@ -159,7 +159,7 @@ typedef struct OGLRender {
#ifdef DEBUG_TIME
double time_start;
#endif
-} OGLRender;
+};
static bool screen_opengl_is_multiview(OGLRender *oglrender)
{
@@ -167,12 +167,12 @@ static bool screen_opengl_is_multiview(OGLRender *oglrender)
RegionView3D *rv3d = oglrender->rv3d;
RenderData *rd = &oglrender->scene->r;
- if ((rd == NULL) || ((v3d != NULL) && (rv3d == NULL))) {
+ if ((rd == nullptr) || ((v3d != nullptr) && (rv3d == nullptr))) {
return false;
}
return (rd->scemode & R_MULTIVIEW) &&
- ((v3d == NULL) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
+ ((v3d == nullptr) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
}
static void screen_opengl_views_setup(OGLRender *oglrender)
@@ -192,10 +192,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
if (!is_multiview) {
/* we only have one view when multiview is off */
- rv = rr->views.first;
+ rv = static_cast<RenderView *>(rr->views.first);
- if (rv == NULL) {
- rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ if (rv == nullptr) {
+ rv = MEM_cnew<RenderView>("new opengl render view");
BLI_addtail(&rr->views, rv);
}
@@ -224,9 +224,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
/* remove all the views that are not needed */
- rv = rr->views.last;
+ rv = static_cast<RenderView *>(rr->views.last);
while (rv) {
- srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
+ srv = static_cast<SceneRenderView *>(
+ BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name)));
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
rv = rv->prev;
}
@@ -253,15 +254,16 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
/* create all the views that are needed */
- for (srv = rd->views.first; srv; srv = srv->next) {
+ for (srv = static_cast<SceneRenderView *>(rd->views.first); srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) {
continue;
}
- rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name));
+ rv = static_cast<RenderView *>(
+ BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name)));
- if (rv == NULL) {
- rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ if (rv == nullptr) {
+ rv = MEM_cnew<RenderView>("new opengl render view");
BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
BLI_addtail(&rr->views, rv);
}
@@ -291,19 +293,19 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ARegion *region = oglrender->region;
View3D *v3d = oglrender->v3d;
RegionView3D *rv3d = oglrender->rv3d;
- Object *camera = NULL;
+ Object *camera = nullptr;
int sizex = oglrender->sizex;
int sizey = oglrender->sizey;
- const short view_context = (v3d != NULL);
+ const short view_context = (v3d != nullptr);
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
- float *rectf = NULL;
- uchar *rect = NULL;
+ float *rectf = nullptr;
+ uchar *rect = nullptr;
const char *viewname = RE_GetActiveRenderView(oglrender->re);
- ImBuf *ibuf_result = NULL;
+ ImBuf *ibuf_result = nullptr;
if (oglrender->is_sequencer) {
SpaceSeq *sseq = oglrender->sseq;
- struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : NULL;
+ struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : nullptr;
/* use pre-calculated ImBuf (avoids deadlock), see: */
ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];
@@ -318,7 +320,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
* TODO(sergey): In the case of output to float container (EXR)
* it actually makes sense to keep float buffer instead.
*/
- if (out->rect_float != NULL) {
+ if (out->rect_float != nullptr) {
IMB_rect_from_float(out);
imb_freerectfloatImBuf(out);
}
@@ -352,7 +354,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
G.f &= ~G_FLAG_RENDER_VIEWPORT;
- gp_rect = MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect");
+ gp_rect = static_cast<uchar *>(
+ MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect"));
GPU_offscreen_read_pixels(oglrender->ofs, GPU_DATA_UBYTE, gp_rect);
for (i = 0; i < sizex * sizey * 4; i += 4) {
@@ -372,7 +375,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (view_context) {
ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph,
scene,
- v3d->shading.type,
+ static_cast<eDrawType>(v3d->shading.type),
v3d,
region,
sizex,
@@ -392,7 +395,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
else {
ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
scene,
- NULL,
+ nullptr,
OB_SOLID,
scene->camera,
oglrender->sizex,
@@ -420,9 +423,9 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
}
}
- if (ibuf_result != NULL) {
+ if (ibuf_result != nullptr) {
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
- BKE_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4);
+ BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty, 4);
}
RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
IMB_freeImBuf(ibuf_result);
@@ -445,7 +448,7 @@ static void screen_opengl_render_write(OGLRender *oglrender)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
false,
- NULL);
+ nullptr);
/* write images as individual images or stereo */
BKE_render_result_stamp_info(scene, scene->camera, rr, false);
@@ -506,7 +509,8 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
}
rr = RE_AcquireResultRead(oglrender->re);
- for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
+ for (rv = static_cast<RenderView *>(rr->views.first), view_id = 0; rv;
+ rv = rv->next, view_id++) {
BLI_assert(view_id < oglrender->views_len);
RE_SetActiveRenderView(oglrender->re, rv->name);
oglrender->view_id = view_id;
@@ -530,7 +534,7 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt)
{
- if (adt == NULL || adt->action == NULL) {
+ if (adt == nullptr || adt->action == nullptr) {
return;
}
@@ -539,7 +543,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An
int frame_end = PEFRA;
LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
- if (fcu->driver != NULL || fcu->fpt != NULL) {
+ if (fcu->driver != nullptr || fcu->fpt != nullptr) {
/* Drivers have values for any point in time, so to get "the keyed frames" they are
* useless. Same for baked FCurves, they also have keys for every frame, which is not
* useful for rendering the keyed subset of the frames. */
@@ -568,7 +572,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An
static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender,
const bGPdata *gp)
{
- if (gp == NULL) {
+ if (gp == nullptr) {
return;
}
@@ -589,7 +593,7 @@ static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender
static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
{
ID **id_p = cb_data->id_pointer;
- if (*id_p == NULL) {
+ if (*id_p == nullptr) {
return IDWALK_RET_NOP;
}
ID *id = *id_p;
@@ -602,7 +606,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_STOP_RECURSION;
}
- OGLRender *oglrender = cb_data->user_data;
+ OGLRender *oglrender = static_cast<OGLRender *>(cb_data->user_data);
/* Whitelist of datablocks to follow pointers into. */
const ID_Type id_type = GS(id->name);
@@ -699,7 +703,7 @@ static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
/* Gather the frames from linked data-blocks (materials, shape-keys, etc.). */
BKE_library_foreach_ID_link(
- NULL, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
+ nullptr, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
}
CTX_DATA_END;
}
@@ -722,8 +726,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
- const eImageFormatDepth color_depth = (is_animation) ? scene->r.im_format.depth :
- R_IMF_CHAN_DEPTH_32;
+ const eImageFormatDepth color_depth = static_cast<eImageFormatDepth>(
+ (is_animation) ? (eImageFormatDepth)scene->r.im_format.depth : R_IMF_CHAN_DEPTH_32);
char err_out[256] = "unknown";
if (G.background) {
@@ -747,7 +751,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
is_view_context = false;
}
- if (!is_view_context && scene->camera == NULL) {
+ if (!is_view_context && scene->camera == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
return false;
}
@@ -777,7 +781,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
}
/* allocate opengl render */
- oglrender = MEM_callocN(sizeof(OGLRender), "OGLRender");
+ oglrender = MEM_new<OGLRender>("OGLRender");
op->customdata = oglrender;
oglrender->ofs = ofs;
@@ -801,7 +805,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->is_sequencer = is_sequencer;
if (is_sequencer) {
oglrender->sseq = CTX_wm_space_seq(C);
- ImBuf **ibufs_arr = MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__);
+ ImBuf **ibufs_arr = static_cast<ImBuf **>(
+ MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__));
oglrender->seq_data.ibufs_arr = ibufs_arr;
}
@@ -812,7 +817,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* so quad view renders camera */
ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->region);
- oglrender->rv3d = oglrender->region->regiondata;
+ oglrender->rv3d = static_cast<RegionView3D *>(oglrender->region->regiondata);
/* MUST be cleared on exit */
memset(&oglrender->scene->customdata_mask_modal,
@@ -832,13 +837,14 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* create image and image user */
oglrender->ima = BKE_image_ensure_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(oglrender->bmain, oglrender->ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(oglrender->bmain, oglrender->ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(oglrender->scene, oglrender->ima, true);
oglrender->iuser.scene = scene;
/* create render result */
- RE_InitState(oglrender->re, NULL, &scene->r, &scene->view_layers, NULL, sizex, sizey, NULL);
+ RE_InitState(
+ oglrender->re, nullptr, &scene->r, &scene->view_layers, nullptr, sizex, sizey, nullptr);
/* create render views */
screen_opengl_views_setup(oglrender);
@@ -848,8 +854,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->win = win;
oglrender->totvideos = 0;
- oglrender->mh = NULL;
- oglrender->movie_ctx_arr = NULL;
+ oglrender->mh = nullptr;
+ oglrender->movie_ctx_arr = nullptr;
if (is_animation) {
if (is_render_keyed_only) {
@@ -866,7 +872,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
BLI_spin_init(&oglrender->reports_lock);
}
else {
- oglrender->task_pool = NULL;
+ oglrender->task_pool = nullptr;
}
oglrender->num_scheduled_frames = 0;
BLI_mutex_init(&oglrender->task_mutex);
@@ -954,12 +960,12 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
CTX_wm_area_set(C, oglrender->prevsa);
CTX_wm_region_set(C, oglrender->prevar);
- MEM_freeN(oglrender);
+ MEM_delete(oglrender);
}
static void screen_opengl_render_cancel(bContext *C, wmOperator *op)
{
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
}
/* share between invoke and exec */
@@ -969,7 +975,7 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
OGLRender *oglrender;
Scene *scene;
- oglrender = op->customdata;
+ oglrender = static_cast<OGLRender *>(op->customdata);
scene = oglrender->scene;
oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
@@ -983,13 +989,14 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
&scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
- if (oglrender->mh == NULL) {
+ if (oglrender->mh == nullptr) {
BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported");
screen_opengl_render_end(C, oglrender);
return false;
}
- oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
+ oglrender->movie_ctx_arr = static_cast<void **>(
+ MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"));
for (i = 0; i < oglrender->totvideos; i++) {
Scene *scene_eval = DEG_get_evaluated_scene(oglrender->depsgraph);
@@ -1017,10 +1024,10 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
return true;
}
-typedef struct WriteTaskData {
+struct WriteTaskData {
RenderResult *rr;
Scene tmp_scene;
-} WriteTaskData;
+};
static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
{
@@ -1073,18 +1080,19 @@ static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
true,
- NULL);
+ nullptr);
BKE_render_result_stamp_info(scene, scene->camera, rr, false);
- ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name);
+ ok = RE_WriteRenderViewsImage(nullptr, rr, scene, true, name);
if (!ok) {
BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", name);
}
}
- if (reports.list.first != NULL) {
+ if (reports.list.first != nullptr) {
BLI_spin_lock(&oglrender->reports_lock);
- for (Report *report = reports.list.first; report != NULL; report = report->next) {
- BKE_report(oglrender->reports, report->type, report->message);
+ for (Report *report = static_cast<Report *>(reports.list.first); report != nullptr;
+ report = report->next) {
+ BKE_report(oglrender->reports, static_cast<eReportType>(report->type), report->message);
}
BLI_spin_unlock(&oglrender->reports_lock);
}
@@ -1105,27 +1113,27 @@ static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
return false;
}
Scene *scene = oglrender->scene;
- WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data");
+ WriteTaskData *task_data = MEM_new<WriteTaskData>("write task data");
task_data->rr = rr;
- task_data->tmp_scene = *scene;
+ memcpy(&task_data->tmp_scene, scene, sizeof(task_data->tmp_scene));
BLI_mutex_lock(&oglrender->task_mutex);
oglrender->num_scheduled_frames++;
if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
}
BLI_mutex_unlock(&oglrender->task_mutex);
- BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, NULL);
+ BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, nullptr);
return true;
}
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
- OGLRender *oglrender = op->customdata;
+ OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
Scene *scene = oglrender->scene;
Depsgraph *depsgraph = oglrender->depsgraph;
char name[FILE_MAX];
bool ok = false;
- const bool view_context = (oglrender->v3d != NULL);
+ const bool view_context = (oglrender->v3d != nullptr);
bool is_movie;
RenderResult *rr;
@@ -1148,7 +1156,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
true,
- NULL);
+ nullptr);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
BLI_spin_lock(&oglrender->reports_lock);
@@ -1177,7 +1185,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
BKE_scene_camera_switch_update(scene);
}
- if (oglrender->render_frames == NULL ||
+ if (oglrender->render_frames == nullptr ||
BLI_BITMAP_TEST_BOOL(oglrender->render_frames, CFRA - PSFRA)) {
/* render into offscreen buffer */
screen_opengl_render_apply(C, oglrender);
@@ -1185,10 +1193,12 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
/* save to disk */
rr = RE_AcquireResultRead(oglrender->re);
- RenderResult *new_rr = RE_DuplicateRenderResult(rr);
- RE_ReleaseResult(oglrender->re);
+ {
+ RenderResult *new_rr = RE_DuplicateRenderResult(rr);
+ RE_ReleaseResult(oglrender->re);
- ok = schedule_write_result(oglrender, new_rr);
+ ok = schedule_write_result(oglrender, new_rr);
+ }
finally: /* Step the frame and bail early if needed */
@@ -1197,16 +1207,16 @@ finally: /* Step the frame and bail early if needed */
/* stop at the end or on error */
if (CFRA >= PEFRA || !ok) {
- screen_opengl_render_end(C, op->customdata);
- return 0;
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
+ return false;
}
- return 1;
+ return true;
}
static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- OGLRender *oglrender = op->customdata;
+ OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
const bool anim = RNA_boolean_get(op->ptr, "animation");
bool ret;
@@ -1214,7 +1224,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
case EVT_ESCKEY:
/* cancel */
oglrender->pool_ok = false; /* Flag pool for cancel. */
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
case TIMER:
/* render frame? */
@@ -1231,8 +1241,8 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
if (anim == 0) {
- screen_opengl_render_apply(C, op->customdata);
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
}
@@ -1261,7 +1271,7 @@ static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEven
}
}
- oglrender = op->customdata;
+ oglrender = static_cast<OGLRender *>(op->customdata);
render_view_open(C, event->xy[0], event->xy[1], op->reports);
/* View may be changed above #USER_RENDER_DISPLAY_WINDOW. */
@@ -1284,8 +1294,8 @@ static int screen_opengl_render_exec(bContext *C, wmOperator *op)
if (!is_animation) { /* same as invoke */
/* render image */
- screen_opengl_render_apply(C, op->customdata);
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
}
@@ -1312,7 +1322,7 @@ static char *screen_opengl_render_description(struct bContext *UNUSED(C),
struct PointerRNA *ptr)
{
if (!RNA_boolean_get(ptr, "animation")) {
- return NULL;
+ return nullptr;
}
if (RNA_boolean_get(ptr, "render_keyed_only")) {
@@ -1344,32 +1354,32 @@ void RENDER_OT_opengl(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna,
"animation",
- 0,
+ false,
"Animation",
"Render files from the animation range of this scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"render_keyed_only",
- 0,
+ false,
"Render Keyframes Only",
"Render only those frames where selected objects have a key in their "
"animation data. Only used when rendering animation");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
- ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display");
+ ot->srna, "sequencer", false, "Sequencer", "Render using the sequencer's OpenGL display");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna,
"write_still",
- 0,
+ false,
"Write Image",
"Save rendered the image to the output path (used only when animation is disabled)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"view_context",
- 1,
+ true,
"View Context",
"Use the current 3D view for rendering, else use scene settings");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.cc
index e0aa02b354d..0f10d186e6e 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.cc
@@ -21,7 +21,7 @@
* \ingroup edrend
*/
-#include <stdlib.h>
+#include <cstdlib>
#include "BLI_utildefines.h"
@@ -29,11 +29,11 @@
#include "WM_api.h"
-#include "render_intern.h" /* own include */
+#include "render_intern.hh" /* own include */
/***************************** render ***********************************/
-void ED_operatortypes_render(void)
+void ED_operatortypes_render()
{
WM_operatortype_append(OBJECT_OT_material_slot_add);
WM_operatortype_append(OBJECT_OT_material_slot_remove);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.cc
index e1121aa4b1e..79c3b2f7ac6 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.cc
@@ -23,9 +23,9 @@
/* global includes */
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
#ifndef WIN32
# include <unistd.h>
@@ -116,7 +116,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect);
/** \name Local Structs
* \{ */
-typedef struct ShaderPreview {
+struct ShaderPreview {
/* from wmJob */
void *owner;
short *stop, *do_update;
@@ -137,31 +137,32 @@ typedef struct ShaderPreview {
int sizex, sizey;
uint *pr_rect;
- int pr_method;
+ ePreviewRenderMethod pr_method;
bool own_id_copy;
Main *bmain;
Main *pr_main;
-} ShaderPreview;
+};
-typedef struct IconPreviewSize {
+struct IconPreviewSize {
struct IconPreviewSize *next, *prev;
int sizex, sizey;
uint *rect;
-} IconPreviewSize;
+};
-typedef struct IconPreview {
+struct IconPreview {
Main *bmain;
- Depsgraph *depsgraph; /* May be NULL (see #WM_OT_previews_ensure). */
+ Depsgraph *depsgraph; /* May be nullptr (see #WM_OT_previews_ensure). */
Scene *scene;
void *owner;
- ID *id, *id_copy; /* May be NULL! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */
+ ID *id,
+ *id_copy; /* May be nullptr! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */
ListBase sizes;
- /* May be NULL, is used for rendering IDs that require some other object for it to be applied on
- * before the ID can be represented as an image, for example when rendering an Action. */
+ /* May be nullptr, is used for rendering IDs that require some other object for it to be applied
+ * on before the ID can be represented as an image, for example when rendering an Action. */
struct Object *active_object;
-} IconPreview;
+};
/** \} */
@@ -169,18 +170,18 @@ typedef struct IconPreview {
/** \name Preview for Buttons
* \{ */
-static Main *G_pr_main = NULL;
-static Main *G_pr_main_grease_pencil = NULL;
+static Main *G_pr_main = nullptr;
+static Main *G_pr_main_grease_pencil = nullptr;
#ifndef WITH_HEADLESS
static Main *load_main_from_memory(const void *blend, int blend_size)
{
const int fileflags = G.fileflags;
- Main *bmain = NULL;
+ Main *bmain = nullptr;
BlendFileData *bfd;
G.fileflags |= G_FILE_NO_UI;
- bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, NULL);
+ bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, nullptr);
if (bfd) {
bmain = bfd->main;
@@ -192,7 +193,7 @@ static Main *load_main_from_memory(const void *blend, int blend_size)
}
#endif
-void ED_preview_ensure_dbase(void)
+void ED_preview_ensure_dbase()
{
#ifndef WITH_HEADLESS
static bool base_initialized = false;
@@ -212,12 +213,12 @@ static bool check_engine_supports_preview(Scene *scene)
return (type->flag & RE_USE_PREVIEW) != 0;
}
-static bool preview_method_is_render(int pr_method)
+static bool preview_method_is_render(const ePreviewRenderMethod pr_method)
{
- return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER, PR_NODE_RENDER);
+ return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER);
}
-void ED_preview_free_dbase(void)
+void ED_preview_free_dbase()
{
if (G_pr_main) {
BKE_main_free(G_pr_main);
@@ -230,11 +231,11 @@ void ED_preview_free_dbase(void)
static Scene *preview_get_scene(Main *pr_main)
{
- if (pr_main == NULL) {
- return NULL;
+ if (pr_main == nullptr) {
+ return nullptr;
}
- return pr_main->scenes.first;
+ return static_cast<Scene *>(pr_main->scenes.first);
}
static const char *preview_collection_name(const ePreviewType pr_type)
@@ -276,10 +277,10 @@ static bool render_engine_supports_ray_visibility(const Scene *sce)
static void switch_preview_collection_visibilty(ViewLayer *view_layer, const ePreviewType pr_type)
{
/* Set appropriate layer as visible. */
- LayerCollection *lc = view_layer->layer_collections.first;
+ LayerCollection *lc = static_cast<LayerCollection *>(view_layer->layer_collections.first);
const char *collection_name = preview_collection_name(pr_type);
- for (lc = lc->layer_collections.first; lc; lc = lc->next) {
+ for (lc = static_cast<LayerCollection *>(lc->layer_collections.first); lc; lc = lc->next) {
if (STREQ(lc->collection->id.name + 2, collection_name)) {
lc->collection->flag &= ~COLLECTION_HIDE_RENDER;
}
@@ -308,7 +309,8 @@ static void switch_preview_floor_material(Main *pr_main,
}
const char *material_name = preview_floor_material_name(scene, pr_method);
- Material *mat = BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2);
+ Material *mat = static_cast<Material *>(
+ BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2));
if (mat) {
me->mat[0] = mat;
}
@@ -329,7 +331,8 @@ static void switch_preview_floor_visibility(Main *pr_main,
}
}
if (base->object->type == OB_MESH) {
- switch_preview_floor_material(pr_main, base->object->data, scene, pr_method);
+ switch_preview_floor_material(
+ pr_main, static_cast<Mesh *>(base->object->data), scene, pr_method);
}
}
}
@@ -348,16 +351,16 @@ static void set_preview_visibility(Main *pr_main,
static World *preview_get_localized_world(ShaderPreview *sp, World *world)
{
- if (world == NULL) {
- return NULL;
+ if (world == nullptr) {
+ return nullptr;
}
- if (sp->worldcopy != NULL) {
+ if (sp->worldcopy != nullptr) {
return sp->worldcopy;
}
- ID *id_copy = BKE_id_copy_ex(NULL,
+ ID *id_copy = BKE_id_copy_ex(nullptr,
&world->id,
- NULL,
+ nullptr,
LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE |
LIB_ID_COPY_NO_ANIMDATA);
sp->worldcopy = (World *)id_copy;
@@ -367,9 +370,9 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world)
static ID *duplicate_ids(ID *id, const bool allow_failure)
{
- if (id == NULL) {
+ if (id == nullptr) {
/* Non-ID preview render. */
- return NULL;
+ return nullptr;
}
switch (GS(id->name)) {
@@ -379,20 +382,23 @@ static ID *duplicate_ids(ID *id, const bool allow_failure)
case ID_LA:
case ID_WO: {
BLI_assert(BKE_previewimg_id_supports_jobs(id));
- ID *id_copy = BKE_id_copy_ex(
- NULL, id, NULL, LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
+ ID *id_copy = BKE_id_copy_ex(nullptr,
+ id,
+ nullptr,
+ LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE |
+ LIB_ID_COPY_NO_ANIMDATA);
return id_copy;
}
/* These support threading, but don't need duplicating. */
case ID_IM:
case ID_BR:
BLI_assert(BKE_previewimg_id_supports_jobs(id));
- return NULL;
+ return nullptr;
default:
if (!allow_failure) {
BLI_assert_msg(0, "ID type preview not supported.");
}
- return NULL;
+ return nullptr;
}
}
@@ -404,8 +410,8 @@ static const char *preview_world_name(const Scene *sce,
* material trick to show the floor in the reflections, but hide the floor for camera rays. For
* Eevee we use a transparent world that has a projected grid.
*
- * In the future when Eevee supports vulkan raytracing we can re-evaluate and perhaps remove this
- * approximation.
+ * In the future when Eevee supports VULKAN ray-tracing we can re-evaluate and perhaps remove
+ * this approximation.
*/
if (id_type == ID_MA && pr_method == PR_ICON_RENDER &&
!render_engine_supports_ray_visibility(sce)) {
@@ -419,13 +425,14 @@ static World *preview_get_world(Main *pr_main,
const ID_Type id_type,
const ePreviewRenderMethod pr_method)
{
- World *result = NULL;
+ World *result = nullptr;
const char *world_name = preview_world_name(sce, id_type, pr_method);
- result = BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2);
+ result = static_cast<World *>(
+ BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2));
/* No world found return first world. */
- if (result == NULL) {
- result = pr_main->worlds.first;
+ if (result == nullptr) {
+ result = static_cast<World *>(pr_main->worlds.first);
}
BLI_assert_msg(result, "Preview file has no world.");
@@ -454,7 +461,7 @@ static World *preview_prepare_world(Main *pr_main,
}
/* call this with a pointer to initialize preview scene */
-/* call this with NULL to restore assigned ID pointers in preview scene */
+/* call this with nullptr to restore assigned ID pointers in preview scene */
static Scene *preview_prepare_scene(
Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
{
@@ -465,7 +472,7 @@ static Scene *preview_prepare_scene(
sce = preview_get_scene(pr_main);
if (sce) {
- ViewLayer *view_layer = sce->view_layers.first;
+ ViewLayer *view_layer = static_cast<ViewLayer *>(sce->view_layers.first);
/* Only enable the combined renderpass */
view_layer->passflag = SCE_PASS_COMBINED;
@@ -491,7 +498,8 @@ static Scene *preview_prepare_scene(
sce->r.cfra = scene->r.cfra;
/* Setup the world. */
- sce->world = preview_prepare_world(pr_main, sce, scene->world, id_type, sp->pr_method);
+ sce->world = preview_prepare_world(
+ pr_main, sce, scene->world, static_cast<ID_Type>(id_type), sp->pr_method);
if (id_type == ID_TE) {
/* Texture is not actually rendered with engine, just set dummy value. */
@@ -499,13 +507,13 @@ static Scene *preview_prepare_scene(
}
if (id_type == ID_MA) {
- Material *mat = NULL, *origmat = (Material *)id;
+ Material *mat = nullptr, *origmat = (Material *)id;
if (origmat) {
/* work on a copy */
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
mat = sp->matcopy = (Material *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->materials, mat);
/* Use current scene world for lighting. */
@@ -523,20 +531,11 @@ static Scene *preview_prepare_scene(
}
/* For grease pencil, always use sphere for icon renders. */
- const ePreviewType preview_type = (sp->pr_method == PR_ICON_RENDER &&
- sp->pr_main == G_pr_main_grease_pencil) ?
- MA_SPHERE_A :
- mat->pr_type;
+ const ePreviewType preview_type = static_cast<ePreviewType>(
+ (sp->pr_method == PR_ICON_RENDER && sp->pr_main == G_pr_main_grease_pencil) ?
+ MA_SPHERE_A :
+ (ePreviewType)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;
@@ -564,30 +563,23 @@ static Scene *preview_prepare_scene(
}
}
else if (id_type == ID_TE) {
- Tex *tex = NULL, *origtex = (Tex *)id;
+ Tex *tex = nullptr, *origtex = (Tex *)id;
if (origtex) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
tex = sp->texcopy = (Tex *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->textures, tex);
}
-
- 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;
+ Light *la = nullptr, *origla = (Light *)id;
/* work on a copy */
if (origla) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
la = sp->lampcopy = (Light *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->lights, la);
}
@@ -608,39 +600,25 @@ 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;
+ World *wrld = nullptr, *origwrld = (World *)id;
if (origwrld) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
wrld = sp->worldcopy = (World *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->worlds, wrld);
}
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;
}
- return NULL;
+ return nullptr;
}
/* new UI convention: draw is in pixel space already. */
@@ -677,7 +655,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
/* test if something rendered ok */
re = RE_GetRender(name);
- if (re == NULL) {
+ if (re == nullptr) {
return false;
}
@@ -689,7 +667,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
}
else {
/* possible the job clears the views but we're still drawing T45496 */
- rv = NULL;
+ rv = nullptr;
}
if (rv && rv->rectf) {
@@ -700,8 +678,8 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
if (rres.rectx && rres.recty) {
- uchar *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int),
- "ed_preview_draw_rect");
+ uchar *rect_byte = static_cast<uchar *>(
+ MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"));
float fx = rect->xmin + offx;
float fy = rect->ymin;
@@ -709,12 +687,21 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0);
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(
- &state, fx, fy, rres.rectx, rres.recty, GPU_RGBA8, false, rect_byte, 1.0f, 1.0f, NULL);
+ immDrawPixelsTexTiled(&state,
+ fx,
+ fy,
+ rres.rectx,
+ rres.recty,
+ GPU_RGBA8,
+ false,
+ rect_byte,
+ 1.0f,
+ 1.0f,
+ nullptr);
MEM_freeN(rect_byte);
- ok = 1;
+ ok = true;
}
}
}
@@ -733,9 +720,9 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
ID *parent = (ID *)parentp;
MTex *slot = (MTex *)slotp;
SpaceProperties *sbuts = CTX_wm_space_properties(C);
- ShaderPreview *sp = WM_jobs_customdata(wm, area);
+ ShaderPreview *sp = static_cast<ShaderPreview *>(WM_jobs_customdata(wm, area));
rcti newrect;
- int ok;
+ bool ok;
int newx = BLI_rcti_size_x(rect);
int newy = BLI_rcti_size_y(rect);
@@ -759,10 +746,10 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
/* start a new preview render job if signaled through sbuts->preview,
* if no render result was found and no preview render job is running,
* or if the job is running and the size of preview changed */
- if ((sbuts != NULL && sbuts->preview) ||
+ if ((sbuts != nullptr && sbuts->preview) ||
(!ok && !WM_jobs_test(wm, area, WM_JOB_TYPE_RENDER_PREVIEW)) ||
(sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2))) {
- if (sbuts != NULL) {
+ if (sbuts != nullptr) {
sbuts->preview = 0;
}
ED_preview_shader_job(C, area, id, parent, slot, newx, newy, PR_BUTS_RENDER);
@@ -826,11 +813,11 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe
* viewport displays. */
CFRA = preview_data->cfra;
- ViewLayer *view_layer = scene->view_layers.first;
+ ViewLayer *view_layer = static_cast<ViewLayer *>(scene->view_layers.first);
Depsgraph *depsgraph = DEG_graph_new(
preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT);
- BLI_assert(preview_data->object != NULL);
+ BLI_assert(preview_data->object != nullptr);
BLI_addtail(&preview_data->pr_main->objects, preview_data->object);
BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object);
@@ -861,26 +848,23 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe
static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
{
Main *preview_main = BKE_main_new();
- const float pixelsize_old = U.pixelsize;
char err_out[256] = "unknown";
BLI_assert(preview->id_copy && (preview->id_copy != preview->id));
- struct ObjectPreviewData preview_data = {
- .pr_main = preview_main,
- /* Act on a copy. */
- .object = (Object *)preview->id_copy,
- .cfra = preview->scene->r.cfra,
- .sizex = preview_sized->sizex,
- .sizey = preview_sized->sizey,
- };
+ struct ObjectPreviewData preview_data = {};
+ preview_data.pr_main = preview_main;
+ /* Act on a copy. */
+ preview_data.object = (Object *)preview->id_copy;
+ preview_data.cfra = preview->scene->r.cfra;
+ preview_data.sizex = preview_sized->sizex;
+ preview_data.sizey = preview_sized->sizey;
+
Depsgraph *depsgraph;
Scene *scene = object_preview_scene_create(&preview_data, &depsgraph);
/* Ownership is now ours. */
- preview->id_copy = NULL;
-
- U.pixelsize = 2.0f;
+ preview->id_copy = nullptr;
View3DShading shading;
BKE_screen_view3d_shading_init(&shading);
@@ -898,13 +882,11 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview
IB_rect,
V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS,
R_ALPHAPREMUL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
err_out);
/* TODO: color-management? */
- U.pixelsize = pixelsize_old;
-
if (ibuf) {
icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
IMB_freeImBuf(ibuf);
@@ -923,15 +905,15 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview
static struct PoseBackup *action_preview_render_prepare(IconPreview *preview)
{
Object *object = preview->active_object;
- if (object == NULL) {
+ if (object == nullptr) {
WM_report(RPT_WARNING, "No active object, unable to apply the Action before rendering");
- return NULL;
+ return nullptr;
}
- if (object->pose == NULL) {
+ if (object->pose == nullptr) {
WM_reportf(RPT_WARNING,
"Object %s has no pose, unable to apply the Action before rendering",
object->id.name + 2);
- return NULL;
+ return nullptr;
}
/* Create a backup of the current pose. */
@@ -952,7 +934,7 @@ static struct PoseBackup *action_preview_render_prepare(IconPreview *preview)
static void action_preview_render_cleanup(IconPreview *preview, struct PoseBackup *pose_backup)
{
- if (pose_backup == NULL) {
+ if (pose_backup == nullptr) {
return;
}
ED_pose_backup_restore(pose_backup);
@@ -972,7 +954,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
/* Not all code paths that lead to this function actually provide a depsgraph.
* The "Refresh Asset Preview" button (ED_OT_lib_id_generate_preview) does,
* but WM_OT_previews_ensure does not. */
- BLI_assert(depsgraph != NULL);
+ BLI_assert(depsgraph != nullptr);
BLI_assert(preview->scene == DEG_get_input_scene(depsgraph));
/* Apply the pose before getting the evaluated scene, so that the new pose is evaluated. */
@@ -980,7 +962,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *camera_eval = scene_eval->camera;
- if (camera_eval == NULL) {
+ if (camera_eval == nullptr) {
printf("Scene has no camera, unable to render preview of %s without it.\n",
preview->id->name + 2);
return;
@@ -989,7 +971,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
/* This renders with the Workbench engine settings stored on the Scene. */
ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
scene_eval,
- NULL,
+ nullptr,
OB_SOLID,
camera_eval,
preview_sized->sizex,
@@ -997,8 +979,8 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
IB_rect,
V3D_OFSDRAW_NONE,
R_ADDSKY,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
err_out);
action_preview_render_cleanup(preview, pose_backup);
@@ -1024,7 +1006,7 @@ static void shader_preview_update(void *spv,
RenderResult *UNUSED(rr),
volatile struct rcti *UNUSED(rect))
{
- ShaderPreview *sp = spv;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
*(sp->do_update) = true;
}
@@ -1032,46 +1014,13 @@ static void shader_preview_update(void *spv,
/* called by renderer, checks job value */
static int shader_preview_break(void *spv)
{
- ShaderPreview *sp = spv;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
return *(sp->stop);
}
-/* 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. */
@@ -1083,13 +1032,14 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend
/* This is needed otherwise no RenderResult is created. */
sce->r.scemode &= ~R_BUTS_PREVIEW;
- RE_InitState(re, NULL, &sce->r, &sce->view_layers, NULL, width, height, NULL);
+ RE_InitState(re, nullptr, &sce->r, &sce->view_layers, nullptr, width, height, nullptr);
RE_SetScene(re, sce);
/* Create buffer in empty RenderView created in the init step. */
RenderResult *rr = RE_AcquireResultWrite(re);
RenderView *rv = (RenderView *)rr->views.first;
- rv->rectf = MEM_callocN(sizeof(float[4]) * width * height, "texture render result");
+ rv->rectf = static_cast<float *>(
+ MEM_callocN(sizeof(float[4]) * width * height, "texture render result"));
RE_ReleaseResult(re);
/* Get texture image pool (if any) */
@@ -1162,7 +1112,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
/* get the stuff from the builtin preview dbase */
sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
- if (sce == NULL) {
+ if (sce == nullptr) {
return;
}
@@ -1175,7 +1125,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
re = RE_GetRender(name);
/* full refreshed render from first tile */
- if (re == NULL) {
+ if (re == nullptr) {
re = RE_NewRender(name);
}
@@ -1187,21 +1137,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 */
@@ -1234,7 +1175,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
}
/* unassign the pointers, reset vars */
- preview_prepare_scene(sp->bmain, sp->scene, NULL, GS(id->name), sp);
+ preview_prepare_scene(sp->bmain, sp->scene, nullptr, GS(id->name), sp);
/* XXX bad exception, end-exec is not being called in render, because it uses local main. */
#if 0
@@ -1249,7 +1190,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
/* runs inside thread for material and icons */
static void shader_preview_startjob(void *customdata, short *stop, short *do_update)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
sp->stop = stop;
sp->do_update = do_update;
@@ -1280,17 +1221,17 @@ static void preview_id_copy_free(ID *id)
static void shader_preview_free(void *customdata)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
Main *pr_main = sp->pr_main;
- ID *main_id_copy = NULL;
- ID *sub_id_copy = NULL;
+ ID *main_id_copy = nullptr;
+ ID *sub_id_copy = nullptr;
if (sp->matcopy) {
main_id_copy = (ID *)sp->matcopy;
BLI_remlink(&pr_main->materials, sp->matcopy);
}
if (sp->texcopy) {
- BLI_assert(main_id_copy == NULL);
+ BLI_assert(main_id_copy == nullptr);
main_id_copy = (ID *)sp->texcopy;
BLI_remlink(&pr_main->textures, sp->texcopy);
}
@@ -1305,14 +1246,10 @@ static void shader_preview_free(void *customdata)
BLI_remlink(&pr_main->worlds, sp->worldcopy);
}
if (sp->lampcopy) {
- BLI_assert(main_id_copy == NULL);
+ BLI_assert(main_id_copy == nullptr);
main_id_copy = (ID *)sp->lampcopy;
BLI_remlink(&pr_main->lights, sp->lampcopy);
}
- 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);
@@ -1351,7 +1288,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
/* Use default color-spaces for brushes. */
- brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
+ brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr);
/* otherwise lets try to find it in other directories */
if (!(brush->icon_imbuf)) {
@@ -1362,7 +1299,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
if (path[0]) {
/* Use default color spaces. */
- brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
+ brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr);
}
}
@@ -1388,7 +1325,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
short ex, ey, dx, dy;
/* paranoia test */
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
+ if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
return;
}
@@ -1418,7 +1355,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
IMB_scalefastImBuf(ima, ex, ey);
/* if needed, convert to 32 bits */
- if (ima->rect == NULL) {
+ if (ima->rect == nullptr) {
IMB_rect_from_float(ima);
}
@@ -1446,13 +1383,13 @@ static void set_alpha(char *cp, int sizex, int sizey, char alpha)
static void icon_preview_startjob(void *customdata, short *stop, short *do_update)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
if (sp->pr_method == PR_ICON_DEFERRED) {
- PreviewImage *prv = sp->owner;
+ PreviewImage *prv = static_cast<PreviewImage *>(sp->owner);
ImBuf *thumb;
- char *deferred_data = PRV_DEFERRED_DATA(prv);
- int source = deferred_data[0];
+ char *deferred_data = static_cast<char *>(PRV_DEFERRED_DATA(prv));
+ ThumbSource source = static_cast<ThumbSource>(deferred_data[0]);
char *path = &deferred_data[1];
// printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path);
@@ -1471,15 +1408,15 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
ID *id = sp->id;
short idtype = GS(id->name);
- BLI_assert(id != NULL);
+ BLI_assert(id != nullptr);
if (idtype == ID_IM) {
Image *ima = (Image *)id;
- ImBuf *ibuf = NULL;
+ ImBuf *ibuf = nullptr;
ImageUser iuser;
BKE_imageuser_default(&iuser);
- if (ima == NULL) {
+ if (ima == nullptr) {
return;
}
@@ -1487,12 +1424,12 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
iuser.framenr = 1;
iuser.scene = sp->scene;
- /* elubie: this needs to be changed: here image is always loaded if not
+ /* NOTE(@elubie): this needs to be changed: here image is always loaded if not
* already there. Very expensive for large images. Need to find a way to
- * only get existing ibuf */
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ * only get existing `ibuf`. */
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
+ if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
return;
}
@@ -1500,7 +1437,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
*do_update = true;
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
}
else if (idtype == ID_BR) {
Brush *br = (Brush *)id;
@@ -1544,7 +1481,7 @@ static void common_preview_startjob(void *customdata,
short *do_update,
float *UNUSED(progress))
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
if (ELEM(sp->pr_method, PR_ICON_RENDER, PR_ICON_DEFERRED)) {
icon_preview_startjob(customdata, stop, do_update);
@@ -1560,17 +1497,17 @@ static void common_preview_startjob(void *customdata,
*/
static void other_id_types_preview_render(IconPreview *ip,
IconPreviewSize *cur_size,
- const int pr_method,
+ const ePreviewRenderMethod pr_method,
short *stop,
short *do_update,
float *progress)
{
- ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
+ ShaderPreview *sp = MEM_cnew<ShaderPreview>("Icon ShaderPreview");
/* These types don't use the ShaderPreview mess, they have their own types and functions. */
BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB));
- /* construct shader preview from image size and previewcustomdata */
+ /* Construct shader preview from image size and preview custom-data. */
sp->scene = ip->scene;
sp->owner = ip->owner;
sp->sizex = cur_size->sizex;
@@ -1581,7 +1518,7 @@ static void other_id_types_preview_render(IconPreview *ip,
sp->id_copy = ip->id_copy;
sp->bmain = ip->bmain;
sp->own_id_copy = false;
- Material *ma = NULL;
+ Material *ma = nullptr;
if (sp->pr_method == PR_ICON_RENDER) {
BLI_assert(ip->id);
@@ -1591,7 +1528,7 @@ static void other_id_types_preview_render(IconPreview *ip,
ma = (Material *)ip->id;
}
- if ((ma == NULL) || (ma->gp_style == NULL)) {
+ if ((ma == nullptr) || (ma->gp_style == nullptr)) {
sp->pr_main = G_pr_main;
}
else {
@@ -1629,10 +1566,12 @@ static void icon_preview_startjob_all_sizes(void *customdata,
IconPreview *ip = (IconPreview *)customdata;
IconPreviewSize *cur_size;
- for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) {
- PreviewImage *prv = ip->owner;
+ for (cur_size = static_cast<IconPreviewSize *>(ip->sizes.first); cur_size;
+ cur_size = cur_size->next) {
+ PreviewImage *prv = static_cast<PreviewImage *>(ip->owner);
/* Is this a render job or a deferred loading job? */
- const int pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED : PR_ICON_RENDER;
+ const ePreviewRenderMethod pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED :
+ PR_ICON_RENDER;
if (*stop) {
break;
@@ -1649,7 +1588,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
* they can skip this test. */
/* TODO: Decouple the ID-type-specific render functions from this function, so that it's not
* necessary to know here what happens inside lower-level functions. */
- const bool use_solid_render_mode = (ip->id != NULL) && ELEM(GS(ip->id->name), ID_OB, ID_AC);
+ const bool use_solid_render_mode = (ip->id != nullptr) && ELEM(GS(ip->id->name), ID_OB, ID_AC);
if (!use_solid_render_mode && preview_method_is_render(pr_method) &&
!check_engine_supports_preview(ip->scene)) {
continue;
@@ -1662,7 +1601,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
}
#endif
- if (ip->id != NULL) {
+ if (ip->id != nullptr) {
switch (GS(ip->id->name)) {
case ID_OB:
if (object_preview_is_type_supported((Object *)ip->id)) {
@@ -1675,7 +1614,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
action_preview_render(ip, cur_size);
continue;
default:
- /* Fall through to the same code as the `ip->id == NULL` case. */
+ /* Fall through to the same code as the `ip->id == nullptr` case. */
break;
}
}
@@ -1685,7 +1624,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey)
{
- IconPreviewSize *cur_size = ip->sizes.first, *new_size;
+ IconPreviewSize *cur_size = static_cast<IconPreviewSize *>(ip->sizes.first);
while (cur_size) {
if (cur_size->sizex == sizex && cur_size->sizey == sizey) {
@@ -1696,7 +1635,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si
cur_size = cur_size->next;
}
- new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize");
+ IconPreviewSize *new_size = MEM_cnew<IconPreviewSize>("IconPreviewSize");
new_size->sizex = sizex;
new_size->sizey = sizey;
new_size->rect = rect;
@@ -1706,7 +1645,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si
static void icon_preview_endjob(void *customdata)
{
- IconPreview *ip = customdata;
+ IconPreview *ip = static_cast<IconPreview *>(customdata);
if (ip->id) {
@@ -1723,7 +1662,7 @@ static void icon_preview_endjob(void *customdata)
for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv_img->gputexture[i]) {
GPU_texture_free(prv_img->gputexture[i]);
- prv_img->gputexture[i] = NULL;
+ prv_img->gputexture[i] = nullptr;
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ip->id);
}
}
@@ -1732,7 +1671,7 @@ static void icon_preview_endjob(void *customdata)
}
if (ip->owner) {
- PreviewImage *prv_img = ip->owner;
+ PreviewImage *prv_img = static_cast<PreviewImage *>(ip->owner);
prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING;
LISTBASE_FOREACH (IconPreviewSize *, icon_size, &ip->sizes) {
@@ -1761,20 +1700,23 @@ static void icon_preview_free(void *customdata)
bool ED_preview_id_is_supported(const ID *id)
{
- if (id == NULL) {
+ if (id == nullptr) {
+ return false;
+ }
+ if (GS(id->name) == ID_NT) {
+ /* Node groups don't support standard preview generation. */
return false;
}
-
if (GS(id->name) == ID_OB) {
return object_preview_is_type_supported((const Object *)id);
}
- return BKE_previewimg_id_get_p(id) != NULL;
+ return BKE_previewimg_id_get_p(id) != nullptr;
}
void ED_preview_icon_render(
const bContext *C, Scene *scene, ID *id, uint *rect, int sizex, int sizey)
{
- IconPreview ip = {NULL};
+ IconPreview ip = {nullptr};
short stop = false, update = false;
float progress = 0.0f;
@@ -1797,7 +1739,7 @@ void ED_preview_icon_render(
icon_preview_endjob(&ip);
BLI_freelistN(&ip.sizes);
- if (ip.id_copy != NULL) {
+ if (ip.id_copy != nullptr) {
preview_id_copy_free(ip.id_copy);
}
}
@@ -1818,10 +1760,10 @@ void ED_preview_icon_job(
WM_JOB_EXCL_RENDER,
WM_JOB_TYPE_RENDER_PREVIEW);
- ip = MEM_callocN(sizeof(IconPreview), "icon preview");
+ ip = MEM_cnew<IconPreview>("icon preview");
/* render all resolutions from suspended job too */
- old_ip = WM_jobs_customdata_get(wm_job);
+ old_ip = static_cast<IconPreview *>(WM_jobs_customdata_get(wm_job));
if (old_ip) {
BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
}
@@ -1840,7 +1782,7 @@ void ED_preview_icon_job(
/* Special threading hack:
* warn main code that this preview is being rendered and cannot be freed... */
{
- PreviewImage *prv_img = owner;
+ PreviewImage *prv_img = static_cast<PreviewImage *>(owner);
if (prv_img->tag & PRV_TAG_DEFFERED) {
prv_img->tag |= PRV_TAG_DEFFERED_RENDERING;
}
@@ -1853,7 +1795,8 @@ void ED_preview_icon_job(
* Particularly important for heavy scenes and Eevee using OpenGL that blocks
* the user interface drawing. */
WM_jobs_delay_start(wm_job, (delay) ? 2.0 : 0.0);
- WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);
+ WM_jobs_callbacks(
+ wm_job, icon_preview_startjob_all_sizes, nullptr, nullptr, icon_preview_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
@@ -1865,13 +1808,13 @@ void ED_preview_shader_job(const bContext *C,
MTex *slot,
int sizex,
int sizey,
- int method)
+ ePreviewRenderMethod method)
{
Object *ob = CTX_data_active_object(C);
wmJob *wm_job;
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));
@@ -1882,11 +1825,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),
@@ -1895,7 +1833,7 @@ void ED_preview_shader_job(const bContext *C,
"Shader Preview",
WM_JOB_EXCL_RENDER,
WM_JOB_TYPE_RENDER_PREVIEW);
- sp = MEM_callocN(sizeof(ShaderPreview), "shader preview");
+ sp = MEM_cnew<ShaderPreview>("shader preview");
/* customdata for preview thread */
sp->scene = scene;
@@ -1909,17 +1847,17 @@ void ED_preview_shader_job(const bContext *C,
sp->parent = parent;
sp->slot = slot;
sp->bmain = CTX_data_main(C);
- Material *ma = NULL;
+ Material *ma = nullptr;
/* hardcoded preview .blend for Eevee + Cycles, this should be solved
* once with custom preview .blend path for external engines */
/* grease pencil use its own preview file */
- if (GS(id->name) == ID_MA) {
+ if (id_type == ID_MA) {
ma = (Material *)id;
}
- if ((ma == NULL) || (ma->gp_style == NULL)) {
+ if ((ma == nullptr) || (ma->gp_style == nullptr)) {
sp->pr_main = G_pr_main;
}
else {
@@ -1936,7 +1874,7 @@ void ED_preview_shader_job(const bContext *C,
/* setup job */
WM_jobs_customdata_set(wm_job, sp, shader_preview_free);
WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
- WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL);
+ WM_jobs_callbacks(wm_job, common_preview_startjob, nullptr, shader_preview_updatejob, nullptr);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
@@ -1946,28 +1884,28 @@ void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain))
if (wm) {
/* This is called to stop all preview jobs before scene data changes, to
* avoid invalid memory access. */
- WM_jobs_kill(wm, NULL, common_preview_startjob);
- WM_jobs_kill(wm, NULL, icon_preview_startjob_all_sizes);
+ WM_jobs_kill(wm, nullptr, common_preview_startjob);
+ WM_jobs_kill(wm, nullptr, icon_preview_startjob_all_sizes);
}
}
-typedef struct PreviewRestartQueueEntry {
+struct PreviewRestartQueueEntry {
struct PreviewRestartQueueEntry *next, *prev;
enum eIconSizes size;
ID *id;
-} PreviewRestartQueueEntry;
+};
static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue;
-void ED_preview_restart_queue_free(void)
+void ED_preview_restart_queue_free()
{
BLI_freelistN(&G_restart_previews_queue);
}
void ED_preview_restart_queue_add(ID *id, enum eIconSizes size)
{
- PreviewRestartQueueEntry *queue_entry = MEM_mallocN(sizeof(*queue_entry), __func__);
+ PreviewRestartQueueEntry *queue_entry = MEM_new<PreviewRestartQueueEntry>(__func__);
queue_entry->size = size;
queue_entry->id = id;
BLI_addtail(&G_restart_previews_queue, queue_entry);
@@ -1986,7 +1924,7 @@ void ED_preview_restart_queue_work(const bContext *C)
}
BKE_previewimg_clear_single(preview, queue_entry->size);
- UI_icon_render_id(C, NULL, queue_entry->id, queue_entry->size, true);
+ UI_icon_render_id(C, nullptr, queue_entry->id, queue_entry->size, true);
BLI_freelinkN(&G_restart_previews_queue, queue_entry);
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.cc
index 54ff25ede28..19ab6841e22 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.cc
@@ -20,8 +20,8 @@
* \ingroup edrend
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -64,6 +64,8 @@
#include "BKE_workspace.h"
#include "BKE_world.h"
+#include "NOD_composite.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -96,7 +98,7 @@
#include "engines/eevee/eevee_lightcache.h"
-#include "render_intern.h" /* own include */
+#include "render_intern.hh" /* own include */
static bool object_materials_supported_poll_ex(bContext *C, const Object *ob);
@@ -106,7 +108,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob);
static bool object_array_for_shading_edit_mode_enabled_filter(const Object *ob, void *user_data)
{
- bContext *C = user_data;
+ bContext *C = static_cast<bContext *>(user_data);
if (object_materials_supported_poll_ex(C, ob)) {
if (BKE_object_is_in_editmode(ob) == true) {
return true;
@@ -123,7 +125,7 @@ static Object **object_array_for_shading_edit_mode_enabled(bContext *C, uint *r_
static bool object_array_for_shading_edit_mode_disabled_filter(const Object *ob, void *user_data)
{
- bContext *C = user_data;
+ bContext *C = static_cast<bContext *>(user_data);
if (object_materials_supported_poll_ex(C, ob)) {
if (BKE_object_is_in_editmode(ob) == false) {
return true;
@@ -159,7 +161,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob)
}
/* Material linked to obdata. */
- const ID *data = ob->data;
+ const ID *data = static_cast<ID *>(ob->data);
return (data && !ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data));
}
@@ -188,8 +190,8 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -238,8 +240,8 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op)
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
@@ -277,7 +279,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
bool changed_multi = false;
Object *obact = CTX_data_active_object(C);
- const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL;
+ const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr;
uint objects_len = 0;
Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len);
@@ -328,7 +330,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data);
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
+ for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) {
if (ED_curve_nurb_select_check(v3d, nu)) {
changed = true;
nu->mat_nr = mat_nr_active;
@@ -384,7 +386,7 @@ static int material_slot_de_select(bContext *C, bool select)
{
bool changed_multi = false;
Object *obact = CTX_data_active_object(C);
- const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL;
+ const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr;
uint objects_len = 0;
Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len);
@@ -432,7 +434,7 @@ static int material_slot_de_select(bContext *C, bool select)
int a;
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
+ for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) {
if (nu->mat_nr == mat_nr_active) {
if (nu->bezt) {
a = nu->pntsu;
@@ -477,7 +479,7 @@ static int material_slot_de_select(bContext *C, bool select)
if (changed) {
changed_multi = true;
- DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
}
@@ -545,7 +547,8 @@ static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op))
Material ***matar_object = &ob->mat;
- Material **matar = MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__);
+ Material **matar = static_cast<Material **>(
+ MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__));
for (int i = ob->totcol; i--;) {
matar[i] = ob->matbits[i] ? (*matar_object)[i] : (*matar_obdata)[i];
}
@@ -620,7 +623,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- slot_remap = MEM_mallocN(sizeof(uint) * ob->totcol, __func__);
+ slot_remap = static_cast<uint *>(MEM_mallocN(sizeof(uint) * ob->totcol, __func__));
range_vn_u(slot_remap, ob->totcol, 0);
@@ -643,7 +646,7 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot)
static const EnumPropertyItem material_slot_move[] = {
{1, "UP", 0, "Up", ""},
{-1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -715,8 +718,8 @@ static int material_slot_remove_unused_exec(bContext *C, wmOperator *op)
if (ob_active->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob_active, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob_active, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_active);
@@ -749,7 +752,8 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot)
static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -757,17 +761,18 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
/* hook into UI */
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
- Object *ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL;
+ Object *ob = static_cast<Object *>((prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data :
+ nullptr);
/* add or copy material */
if (ma) {
Material *new_ma = (Material *)BKE_id_copy_ex(
- bmain, &ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
+ bmain, &ma->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
ma = new_ma;
}
else {
const char *name = DATA_("Material");
- if (!(ob != NULL && ob->type == OB_GPENCIL)) {
+ if (!(ob != nullptr && ob->type == OB_GPENCIL)) {
ma = BKE_material_add(bmain, name);
}
else {
@@ -778,10 +783,10 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
}
if (prop) {
- if (ob != NULL) {
+ if (ob != nullptr) {
/* Add slot follows user-preferences for creating new slots,
* RNA pointer assignment doesn't, see: T60014. */
- if (BKE_object_material_get_p(ob, ob->actcol) == NULL) {
+ if (BKE_object_material_get_p(ob, ob->actcol) == nullptr) {
BKE_object_material_slot_add(bmain, ob);
}
}
@@ -791,7 +796,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&ma->id);
RNA_id_pointer_create(&ma->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -823,7 +828,7 @@ void MATERIAL_OT_new(wmOperatorType *ot)
static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
{
- Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
+ Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -845,7 +850,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&tex->id);
RNA_id_pointer_create(&tex->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -876,7 +881,7 @@ void TEXTURE_OT_new(wmOperatorType *ot)
static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
{
- World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
+ World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -884,7 +889,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
/* add or copy world */
if (wo) {
World *new_wo = (World *)BKE_id_copy_ex(
- bmain, &wo->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
+ bmain, &wo->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
wo = new_wo;
}
else {
@@ -902,7 +907,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&wo->id);
RNA_id_pointer_create(&wo->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -960,7 +965,7 @@ void SCENE_OT_view_layer_add(wmOperatorType *ot)
0,
"Blank",
"Add a new view layer with all collections disabled"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -997,7 +1002,7 @@ static int view_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- if (!ED_scene_view_layer_delete(bmain, scene, view_layer, NULL)) {
+ if (!ED_scene_view_layer_delete(bmain, scene, view_layer, nullptr)) {
return OPERATOR_CANCELLED;
}
@@ -1041,7 +1046,7 @@ static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op))
BKE_view_layer_verify_aov(engine, scene, view_layer);
}
RE_engine_free(engine);
- engine = NULL;
+ engine = nullptr;
}
if (scene->nodetree) {
@@ -1080,7 +1085,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- if (view_layer->active_aov == NULL) {
+ if (view_layer->active_aov == nullptr) {
return OPERATOR_FINISHED;
}
@@ -1093,7 +1098,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
BKE_view_layer_verify_aov(engine, scene, view_layer);
}
RE_engine_free(engine);
- engine = NULL;
+ engine = nullptr;
}
if (scene->nodetree) {
@@ -1135,7 +1140,7 @@ enum {
static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op)
{
- if (scene->eevee.light_cache_data != NULL) {
+ if (scene->eevee.light_cache_data != nullptr) {
int subset = RNA_enum_get(op->ptr, "subset");
switch (subset) {
case LIGHTCACHE_SUBSET_ALL:
@@ -1261,7 +1266,7 @@ void SCENE_OT_light_cache_bake(wmOperatorType *ot)
0,
"Cubemaps Only",
"Try to only bake reflection cubemaps if irradiance grids are up to date"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1317,7 +1322,7 @@ static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op))
}
EEVEE_lightcache_free(scene->eevee.light_cache_data);
- scene->eevee.light_cache_data = NULL;
+ scene->eevee.light_cache_data = nullptr;
EEVEE_lightcache_info_update(&scene->eevee);
@@ -1358,7 +1363,7 @@ static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- BKE_scene_add_render_view(scene, NULL);
+ BKE_scene_add_render_view(scene, nullptr);
scene->r.actview = BLI_listbase_count(&scene->r.views) - 1;
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -1389,7 +1394,8 @@ void SCENE_OT_render_view_add(wmOperatorType *ot)
static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview);
+ SceneRenderView *rv = static_cast<SceneRenderView *>(
+ BLI_findlink(&scene->r.views, scene->r.actview));
if (!BKE_scene_remove_render_view(scene, rv)) {
return OPERATOR_CANCELLED;
@@ -1444,9 +1450,9 @@ static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportLi
static bool freestyle_active_module_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
- return module != NULL;
+ return module != nullptr;
}
static int freestyle_module_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1486,7 +1492,7 @@ static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
BKE_freestyle_module_delete(&view_layer->freestyle_config, module);
@@ -1516,7 +1522,7 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
int dir = RNA_enum_get(op->ptr, "direction");
if (BKE_freestyle_module_move(&view_layer->freestyle_config, module, dir)) {
@@ -1538,7 +1544,7 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1574,7 +1580,7 @@ static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, NULL);
+ BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, nullptr);
DEG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -1610,7 +1616,7 @@ static bool freestyle_active_lineset_poll(bContext *C)
return false;
}
- return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != NULL;
+ return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != nullptr;
}
static int freestyle_lineset_copy_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1730,7 +1736,7 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1814,7 +1820,7 @@ static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_color_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_color_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type");
return OPERATOR_CANCELLED;
}
@@ -1861,7 +1867,7 @@ static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type");
return OPERATOR_CANCELLED;
}
@@ -1908,7 +1914,7 @@ static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type");
return OPERATOR_CANCELLED;
}
@@ -1955,7 +1961,7 @@ static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type");
return OPERATOR_CANCELLED;
}
@@ -2014,7 +2020,7 @@ static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
return OPERATOR_CANCELLED;
@@ -2070,7 +2076,7 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
return OPERATOR_CANCELLED;
@@ -2126,7 +2132,7 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
int dir = RNA_enum_get(op->ptr, "direction");
bool changed = false;
@@ -2166,7 +2172,7 @@ void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -2252,9 +2258,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op)
mtex_ar[act] = mtex_ar[act - 1];
mtex_ar[act - 1] = mtexswap;
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act - 1, -1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act - 1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act - 1, -1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act - 1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false);
set_active_mtex(id, act - 1);
}
@@ -2265,9 +2274,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op)
mtex_ar[act] = mtex_ar[act + 1];
mtex_ar[act + 1] = mtexswap;
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act + 1, -1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act + 1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act + 1, -1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act + 1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false);
set_active_mtex(id, act + 1);
}
@@ -2285,7 +2297,7 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot)
static const EnumPropertyItem slot_move[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -2311,9 +2323,10 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot)
/* material copy/paste */
static int copy_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
- if (ma == NULL) {
+ if (ma == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2345,9 +2358,10 @@ void MATERIAL_OT_copy(wmOperatorType *ot)
static int paste_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
- if (ma == NULL) {
+ if (ma == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2382,14 +2396,14 @@ void MATERIAL_OT_paste(wmOperatorType *ot)
static short mtexcopied = 0; /* must be reset on file load */
static MTex mtexcopybuf;
-void ED_render_clear_mtex_copybuf(void)
+void ED_render_clear_mtex_copybuf()
{ /* use for file reload */
mtexcopied = 0;
}
static void copy_mtex_copybuf(ID *id)
{
- MTex **mtex = NULL;
+ MTex **mtex = nullptr;
switch (GS(id->name)) {
case ID_PA:
@@ -2413,9 +2427,9 @@ static void copy_mtex_copybuf(ID *id)
static void paste_mtex_copybuf(ID *id)
{
- MTex **mtex = NULL;
+ MTex **mtex = nullptr;
- if (mtexcopied == 0 || mtexcopybuf.tex == NULL) {
+ if (mtexcopied == 0 || mtexcopybuf.tex == nullptr) {
return;
}
@@ -2432,8 +2446,8 @@ static void paste_mtex_copybuf(ID *id)
}
if (mtex) {
- if (*mtex == NULL) {
- *mtex = MEM_mallocN(sizeof(MTex), "mtex copy");
+ if (*mtex == nullptr) {
+ *mtex = MEM_new<MTex>("mtex copy");
}
else if ((*mtex)->tex) {
id_us_min(&(*mtex)->tex->id);
@@ -2455,7 +2469,7 @@ static int copy_mtex_exec(bContext *C, wmOperator *UNUSED(op))
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- if (id == NULL) {
+ if (id == nullptr) {
/* copying empty slot */
ED_render_clear_mtex_copybuf();
return OPERATOR_CANCELLED;
@@ -2470,7 +2484,7 @@ static bool copy_mtex_poll(bContext *C)
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- return (id != NULL);
+ return (id != nullptr);
}
void TEXTURE_OT_slot_copy(wmOperatorType *ot)
@@ -2499,14 +2513,15 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- if (id == NULL) {
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
- Light *la = CTX_data_pointer_get_type(C, "light", &RNA_Light).data;
- World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
- ParticleSystem *psys =
- CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
- FreestyleLineStyle *linestyle =
- CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data;
+ if (id == nullptr) {
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
+ Light *la = static_cast<Light *>(CTX_data_pointer_get_type(C, "light", &RNA_Light).data);
+ World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data);
+ ParticleSystem *psys = static_cast<ParticleSystem *>(
+ CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data);
+ FreestyleLineStyle *linestyle = static_cast<FreestyleLineStyle *>(
+ CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data);
if (ma) {
id = &ma->id;
@@ -2524,14 +2539,14 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))
id = &linestyle->id;
}
- if (id == NULL) {
+ if (id == nullptr) {
return OPERATOR_CANCELLED;
}
}
paste_mtex_copybuf(id);
- WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, NULL);
+ WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, nullptr);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.cc
index e975eab4736..b1e8e3927ef 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.cc
@@ -20,8 +20,8 @@
* \ingroup edrend
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "DNA_cachefile_types.h"
#include "DNA_light_types.h"
@@ -49,6 +49,8 @@
#include "BKE_paint.h"
#include "BKE_scene.h"
+#include "NOD_composite.h"
+
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -62,7 +64,7 @@
#include "WM_api.h"
-#include <stdio.h>
+#include <cstdio>
/* -------------------------------------------------------------------- */
/** \name Render Engines
@@ -82,8 +84,8 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
continue;
}
- View3D *v3d = area->spacedata.first;
- RegionView3D *rv3d = region->regiondata;
+ View3D *v3d = static_cast<View3D *>(area->spacedata.first);
+ RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
RenderEngine *engine = rv3d->render_engine;
/* call update if the scene changed, or if the render engine
@@ -94,7 +96,7 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
bContext *C = CTX_create();
CTX_data_main_set(C, bmain);
CTX_data_scene_set(C, scene);
- CTX_wm_manager_set(C, bmain->wm.first);
+ CTX_wm_manager_set(C, static_cast<wmWindowManager *>(bmain->wm.first));
CTX_wm_window_set(C, window);
CTX_wm_screen_set(C, WM_window_get_active_screen(window));
CTX_wm_area_set(C, area);
@@ -111,15 +113,15 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
else {
RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
if (updated) {
- DRW_notify_view_update((&(DRWUpdateContext){
- .bmain = bmain,
- .depsgraph = depsgraph,
- .scene = scene,
- .view_layer = view_layer,
- .region = region,
- .v3d = v3d,
- .engine_type = engine_type,
- }));
+ DRWUpdateContext drw_context = {nullptr};
+ drw_context.bmain = bmain;
+ drw_context.depsgraph = depsgraph;
+ drw_context.scene = scene;
+ drw_context.view_layer = view_layer;
+ drw_context.region = region;
+ drw_context.v3d = v3d;
+ drw_context.engine_type = engine_type;
+ DRW_notify_view_update(&drw_context);
}
}
}
@@ -148,7 +150,7 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, const bool
recursive_check = true;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(window);
@@ -166,13 +168,13 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area)
{
/* clear all render engines in this area */
ARegion *region;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (area->spacetype != SPACE_VIEW3D) {
return;
}
- for (region = area->regionbase.first; region; region = region->next) {
+ for (region = static_cast<ARegion *>(area->regionbase.first); region; region = region->next) {
if (region->regiontype != RGN_TYPE_WINDOW || !(region->regiondata)) {
continue;
}
@@ -183,16 +185,18 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area)
void ED_render_engine_changed(Main *bmain, const bool update_scene_data)
{
/* on changing the render engine type, clear all running render engines */
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen;
+ screen = static_cast<bScreen *>(screen->id.next)) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
ED_render_engine_area_exit(bmain, area);
}
}
- RE_FreePersistentData(NULL);
+ RE_FreePersistentData(nullptr);
/* Inform all render engines and draw managers. */
- DEGEditorUpdateContext update_ctx = {NULL};
+ DEGEditorUpdateContext update_ctx = {nullptr};
update_ctx.bmain = bmain;
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene;
+ scene = static_cast<Scene *>(scene->id.next)) {
update_ctx.scene = scene;
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
/* TDODO(sergey): Iterate over depsgraphs instead? */
@@ -258,14 +262,16 @@ static void texture_changed(Main *bmain, Tex *tex)
/* icons */
BKE_icon_changed(BKE_icon_id_ensure(&tex->id));
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ for (scene = static_cast<Scene *>(bmain->scenes.first); scene;
+ scene = static_cast<Scene *>(scene->id.next)) {
/* paint overlays */
- for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (view_layer = static_cast<ViewLayer *>(scene->view_layers.first); view_layer;
+ view_layer = view_layer->next) {
BKE_paint_invalidate_overlay_tex(scene, view_layer, tex);
}
/* find compositing nodes */
if (scene->use_nodes && scene->nodetree) {
- for (node = scene->nodetree->nodes.first; node; node = node->next) {
+ for (node = static_cast<bNode *>(scene->nodetree->nodes.first); node; node = node->next) {
if (node->id == &tex->id) {
ED_node_tag_update_id(&scene->id);
}
@@ -288,7 +294,8 @@ static void image_changed(Main *bmain, Image *ima)
BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
/* textures */
- for (tex = bmain->textures.first; tex; tex = tex->id.next) {
+ for (tex = static_cast<Tex *>(bmain->textures.first); tex;
+ tex = static_cast<Tex *>(tex->id.next)) {
if (tex->type == TEX_IMAGE && tex->ima == ima) {
texture_changed(bmain, tex);
}
@@ -300,10 +307,11 @@ static void scene_changed(Main *bmain, Scene *scene)
Object *ob;
/* glsl */
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ for (ob = static_cast<Object *>(bmain->objects.first); ob;
+ ob = static_cast<Object *>(ob->id.next)) {
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
BKE_texpaint_slots_refresh_object(scene, ob);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
}
}
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.cc
index 9163718ffad..980cd899120 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.cc
@@ -21,8 +21,8 @@
* \ingroup edrend
*/
-#include <stddef.h>
-#include <string.h>
+#include <cstddef>
+#include <cstring>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -47,7 +47,7 @@
#include "wm_window.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/*********************** utilities for finding areas *************************/
@@ -59,11 +59,11 @@
static ScrArea *biggest_non_image_area(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area, *big = NULL;
+ ScrArea *area, *big = nullptr;
int size, maxsize = 0, bwmaxsize = 0;
short foundwin = 0;
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->winx > 30 && area->winy > 30) {
size = area->winx * area->winy;
if (!area->full && area->spacetype == SPACE_PROPERTIES) {
@@ -86,17 +86,17 @@ static ScrArea *biggest_non_image_area(bContext *C)
static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow **win)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *area = NULL;
+ ScrArea *area = nullptr;
SpaceImage *sima;
/* find an imagewindow showing render result */
- for (*win = wm->windows.first; *win; *win = (*win)->next) {
+ for (*win = static_cast<wmWindow *>(wm->windows.first); *win; *win = (*win)->next) {
if (WM_window_get_active_scene(*win) == scene) {
const bScreen *screen = WM_window_get_active_screen(*win);
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->spacetype == SPACE_IMAGE) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
break;
}
@@ -118,9 +118,9 @@ static ScrArea *find_area_image_empty(bContext *C)
SpaceImage *sima;
/* find an imagewindow showing render result */
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->spacetype == SPACE_IMAGE) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
if ((sima->mode == SI_MODE_VIEW) && !sima->image) {
break;
}
@@ -136,13 +136,13 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- wmWindow *win = NULL;
- ScrArea *area = NULL;
+ wmWindow *win = nullptr;
+ ScrArea *area = nullptr;
SpaceImage *sima;
bool area_was_image = false;
if (U.render_display_type == USER_RENDER_DISPLAY_NONE) {
- return NULL;
+ return nullptr;
}
if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) {
@@ -168,14 +168,14 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
true,
false,
true,
- WIN_ALIGN_LOCATION_CENTER) == NULL) {
+ WIN_ALIGN_LOCATION_CENTER) == nullptr) {
BKE_report(reports, RPT_ERROR, "Failed to open window!");
- return NULL;
+ return nullptr;
}
area = CTX_wm_area(C);
if (BLI_listbase_is_single(&area->spacedata) == false) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
sima->flag |= SI_PREVSPACE;
}
}
@@ -185,7 +185,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
/* If the active screen is already in full-screen mode, skip this and
* unset the area, so that the full-screen area is just changed later. */
if (area && area->full) {
- area = NULL;
+ area = nullptr;
}
else {
if (area && area->spacetype == SPACE_IMAGE) {
@@ -199,7 +199,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
if (!area) {
area = find_area_showing_r_result(C, scene, &win);
- if (area == NULL) {
+ if (area == nullptr) {
area = find_area_image_empty(C);
}
@@ -208,12 +208,12 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
wm_window_raise(win);
}
- if (area == NULL) {
+ if (area == nullptr) {
/* find largest open non-image area */
area = biggest_non_image_area(C);
if (area) {
ED_area_newspace(C, area, SPACE_IMAGE, true);
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
/* Makes "Escape" go back to previous space. */
sima->flag |= SI_PREVSPACE;
@@ -228,7 +228,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
if (area->spacetype != SPACE_IMAGE) {
// XXX newspace(area, SPACE_IMAGE);
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
/* Makes "Escape" go back to previous space. */
sima->flag |= SI_PREVSPACE;
@@ -236,7 +236,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
}
}
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
sima->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
/* get the correct image, and scale it */
@@ -272,7 +272,7 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
/* ensure image editor full-screen and area full-screen states are in sync */
if ((sima->flag & SI_FULLWINDOW) && !area->full) {
@@ -333,7 +333,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
ScrArea *area = find_area_showing_r_result(C, CTX_data_scene(C), &winshow);
/* is there another window on current scene showing result? */
- for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) {
+ for (win = static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first); win; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
if ((WM_window_is_temp_screen(win) &&
@@ -348,7 +348,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
if (area) {
/* but don't close it when rendering */
if (G.is_rendering == false) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
if (sima->flag & SI_PREVSPACE) {
sima->flag &= ~SI_PREVSPACE;
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 5dc6fe88663..c6834c84794 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1667,7 +1667,7 @@ static bool event_in_markers_region(const ARegion *region, const wmEvent *event)
{
rcti rect = region->winrct;
rect.ymax = rect.ymin + UI_MARKER_MARGIN_Y;
- return BLI_rcti_isect_pt(&rect, event->xy[0], event->xy[1]);
+ return BLI_rcti_isect_pt_v(&rect, event->xy);
}
/**
@@ -1680,7 +1680,7 @@ static void ed_default_handlers(
/* NOTE: add-handler checks if it already exists. */
- /* XXX it would be good to have boundbox checks for some of these... */
+ /* XXX: it would be good to have bound-box checks for some of these. */
if (flag & ED_KEYMAP_UI) {
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "User Interface", 0, 0);
WM_event_add_keymap_handler(handlers, keymap);
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 5f523df18d1..63b7fbc14a7 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -64,7 +64,7 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
state.shader = GPU_shader_get_builtin_shader(builtin);
- /* Shader will be unbind by immUnbindProgram in immDrawPixelsTexScaled_clipping */
+ /* Shader will be unbind by immUnbindProgram in a `immDrawPixelsTex` function. */
immBindBuiltinProgram(builtin);
immUniform1i("image", 0);
state.do_shader_unbind = true;
@@ -72,23 +72,92 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
return state;
}
-void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state,
+ const float x,
+ const float y,
+ const int img_w,
+ const int img_h,
+ const eGPUTextureFormat gpu_format,
+ const bool use_filter,
+ const void *rect,
+ const float scaleX,
+ const float scaleY,
+ const float xzoom,
+ const float yzoom,
+ const float color[4])
+{
+ static const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const float draw_width = img_w * scaleX * xzoom;
+ const float draw_height = img_h * scaleY * yzoom;
+ /* Down-scaling with regular bi-linear interpolation (i.e. #GL_LINEAR) doesn't give good
+ * filtering results. Mipmaps can be used to get better results (i.e. #GL_LINEAR_MIPMAP_LINEAR),
+ * so always use mipmaps when filtering. */
+ const bool use_mipmap = use_filter && ((draw_width < img_w) || (draw_height < img_h));
+
+ GPUTexture *tex = GPU_texture_create_2d("immDrawPixels", img_w, img_h, 1, gpu_format, NULL);
+
+ const bool use_float_data = ELEM(gpu_format, GPU_RGBA16F, GPU_RGB16F, GPU_R16F);
+ eGPUDataFormat gpu_data_format = (use_float_data) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
+ GPU_texture_update(tex, gpu_data_format, rect);
+
+ GPU_texture_filter_mode(tex, use_filter);
+ if (use_mipmap) {
+ GPU_texture_generate_mipmap(tex);
+ GPU_texture_mipmap_mode(tex, true, true);
+ }
+ GPU_texture_wrap_mode(tex, false, true);
+
+ GPU_texture_bind(tex, 0);
+
+ /* optional */
+ /* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since
+ * it does not need color.
+ */
+ if (state->shader != NULL && GPU_shader_get_uniform(state->shader, "color") != -1) {
+ immUniformColor4fv((color) ? color : white);
+ }
+
+ uint pos = state->pos, texco = state->texco;
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+ immAttr2f(texco, 0.0f, 0.0f);
+ immVertex2f(pos, x, y);
+
+ immAttr2f(texco, 1.0f, 0.0f);
+ immVertex2f(pos, x + draw_width, y);
+
+ immAttr2f(texco, 1.0f, 1.0f);
+ immVertex2f(pos, x + draw_width, y + draw_height);
+
+ immAttr2f(texco, 0.0f, 1.0f);
+ immVertex2f(pos, x, y + draw_height);
+ immEnd();
+
+ if (state->do_shader_unbind) {
+ immUnbindProgram();
+ }
+
+ GPU_texture_unbind(tex);
+ GPU_texture_free(tex);
+}
+
+void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
int subpart_x, subpart_y, tex_w = 256, tex_h = 256;
int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
@@ -242,103 +311,103 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
GPU_unpack_row_length_set(0);
}
-void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float scaleX,
- float scaleY,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexTiled_scaling(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float scaleX,
+ float scaleY,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
- immDrawPixelsTexScaled_clipping(state,
- x,
- y,
- img_w,
- img_h,
- gpu_format,
- use_filter,
- rect,
- scaleX,
- scaleY,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- xzoom,
- yzoom,
- color);
+ immDrawPixelsTexTiled_scaling_clipping(state,
+ x,
+ y,
+ img_w,
+ img_h,
+ gpu_format,
+ use_filter,
+ rect,
+ scaleX,
+ scaleY,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ xzoom,
+ yzoom,
+ color);
}
-void immDrawPixelsTex(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexTiled(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
- immDrawPixelsTexScaled_clipping(state,
- x,
- y,
- img_w,
- img_h,
- gpu_format,
- use_filter,
- rect,
- 1.0f,
- 1.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- xzoom,
- yzoom,
- color);
+ immDrawPixelsTexTiled_scaling_clipping(state,
+ x,
+ y,
+ img_w,
+ img_h,
+ gpu_format,
+ use_filter,
+ rect,
+ 1.0f,
+ 1.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ xzoom,
+ yzoom,
+ color);
}
-void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
- float x,
- float y,
- int img_w,
- int img_h,
- eGPUTextureFormat gpu_format,
- bool use_filter,
- void *rect,
- float clip_min_x,
- float clip_min_y,
- float clip_max_x,
- float clip_max_y,
- float xzoom,
- float yzoom,
- const float color[4])
+void immDrawPixelsTexTiled_clipping(IMMDrawPixelsTexState *state,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
+ void *rect,
+ float clip_min_x,
+ float clip_min_y,
+ float clip_max_x,
+ float clip_max_y,
+ float xzoom,
+ float yzoom,
+ const float color[4])
{
- immDrawPixelsTexScaled_clipping(state,
- x,
- y,
- img_w,
- img_h,
- gpu_format,
- use_filter,
- rect,
- 1.0f,
- 1.0f,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- xzoom,
- yzoom,
- color);
+ immDrawPixelsTexTiled_scaling_clipping(state,
+ x,
+ y,
+ img_w,
+ img_h,
+ gpu_format,
+ use_filter,
+ rect,
+ 1.0f,
+ 1.0f,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ xzoom,
+ yzoom,
+ color);
}
/* **** Color management helper functions for GLSL display/transform ***** */
@@ -409,40 +478,40 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
}
if (format != 0) {
- immDrawPixelsTex_clipping(&state,
- x,
- y,
- ibuf->x,
- ibuf->y,
- format,
- use_filter,
- ibuf->rect_float,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- zoom_x,
- zoom_y,
- NULL);
+ immDrawPixelsTexTiled_clipping(&state,
+ x,
+ y,
+ ibuf->x,
+ ibuf->y,
+ format,
+ use_filter,
+ ibuf->rect_float,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ zoom_x,
+ zoom_y,
+ NULL);
}
}
else if (ibuf->rect) {
/* ibuf->rect is always RGBA */
- immDrawPixelsTex_clipping(&state,
- x,
- y,
- ibuf->x,
- ibuf->y,
- GPU_RGBA8,
- use_filter,
- ibuf->rect,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- zoom_x,
- zoom_y,
- NULL);
+ immDrawPixelsTexTiled_clipping(&state,
+ x,
+ y,
+ ibuf->x,
+ ibuf->y,
+ GPU_RGBA8,
+ use_filter,
+ ibuf->rect,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ zoom_x,
+ zoom_y,
+ NULL);
}
IMB_colormanagement_finish_glsl_draw();
@@ -461,21 +530,21 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
if (display_buffer) {
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex_clipping(&state,
- x,
- y,
- ibuf->x,
- ibuf->y,
- GPU_RGBA8,
- use_filter,
- display_buffer,
- clip_min_x,
- clip_min_y,
- clip_max_x,
- clip_max_y,
- zoom_x,
- zoom_y,
- NULL);
+ immDrawPixelsTexTiled_clipping(&state,
+ x,
+ y,
+ ibuf->x,
+ ibuf->y,
+ GPU_RGBA8,
+ use_filter,
+ display_buffer,
+ clip_min_x,
+ clip_min_y,
+ clip_max_x,
+ clip_max_y,
+ zoom_x,
+ zoom_y,
+ NULL);
}
IMB_display_buffer_release(cache_handle);
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 304205d0cc4..04df90bf912 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -501,7 +501,7 @@ static eContextResult screen_ctx_active_pose_bone(const bContext *C, bContextDat
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
Object *obpose = BKE_object_pose_armature_get(obact);
- bPoseChannel *pchan = BKE_pose_channel_active(obpose);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(obpose);
if (pchan) {
CTX_data_pointer_set(result, &obpose->id, &RNA_PoseBone, pchan);
return CTX_RESULT_OK;
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index e720ae4b9d8..01730b3c9aa 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -144,7 +144,7 @@ static void drawscredge_area_draw(
}
GPUBatch *batch = batch_screen_edges_get(NULL);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_EDGES);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_BORDERS);
GPU_batch_uniform_4fv(batch, "rect", (float *)&rect);
GPU_batch_draw(batch);
}
@@ -212,7 +212,7 @@ void ED_screen_draw_edges(wmWindow *win)
GPU_blend(GPU_BLEND_ALPHA);
GPUBatch *batch = batch_screen_edges_get(&verts_per_corner);
- GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_EDGES);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_BORDERS);
GPU_batch_uniform_1i(batch, "cornerLen", verts_per_corner);
GPU_batch_uniform_1f(batch, "scale", corner_scale);
GPU_batch_uniform_4fv(batch, "color", col);
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index bc06e46ba96..e42c891b0ba 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -71,10 +71,10 @@ typedef enum eScreenAxis {
/**
* 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_copy(ScrArea *area_dst, ScrArea *area_src, 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);
+void region_toggle_hidden(struct bContext *C, ARegion *region, bool do_fade);
/* screen_draw.c */
@@ -85,7 +85,7 @@ void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fad
* \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);
+void screen_draw_split_preview(struct ScrArea *area, eScreenAxis dir_axis, float fac);
/* screen_edit.c */
@@ -111,9 +111,9 @@ void screen_change_prepare(bScreen *screen_old,
ScrArea *area_split(const wmWindow *win,
bScreen *screen,
ScrArea *area,
- const eScreenAxis dir_axis,
- const float fac,
- const bool merge);
+ eScreenAxis dir_axis,
+ float fac,
+ bool merge);
/**
* Join any two neighboring areas. Might involve complex changes.
*/
@@ -127,8 +127,7 @@ 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);
+void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, eScreenDir dir, int *r_offset1, int *r_offset2);
/**
* Close a screen area, allowing most-aligned neighbor to take its place.
*/
@@ -150,15 +149,15 @@ bool screen_geom_edge_is_horizontal(ScrEdge *se);
*/
ScrEdge *screen_geom_area_map_find_active_scredge(const struct ScrAreaMap *area_map,
const rcti *bounds_rect,
- const int mx,
- const int my);
+ int mx,
+ 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);
+ int mx,
+ int my);
/**
* \brief Main screen-layout calculation function.
*
@@ -172,7 +171,7 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen);
*/
short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
- const eScreenAxis dir_axis,
+ eScreenAxis dir_axis,
float fac);
/**
* Select all edges that are directly or indirectly connected to \a edge.
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index d017345b523..6581bffb6bd 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -1128,8 +1128,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
AREAMAP_FROM_SCREEN(screen), &screen_rect, event->xy[0], event->xy[1]) == NULL)) {
/* What area are we now in? */
- ScrArea *area = BKE_screen_find_area_xy(
- screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
if (area == sad->sa1) {
/* Same area, so possible split. */
@@ -1173,7 +1172,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* gesture is large enough? */
if (is_gesture) {
/* second area, for join when (sa1 != sa2) */
- sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
/* apply sends event */
actionzone_apply(C, op, sad->az->type);
actionzone_exit(op);
@@ -1241,12 +1240,16 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C,
int borderwidth = (4 * UI_DPI_FAC);
ScrArea *sa1, *sa2;
if (screen_geom_edge_is_horizontal(actedge)) {
- sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] + borderwidth);
- sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] - borderwidth);
+ sa1 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] + borderwidth});
+ sa2 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] - borderwidth});
}
else {
- sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] + borderwidth, cursor[1]);
- sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] - borderwidth, cursor[1]);
+ sa1 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] + borderwidth, cursor[1]});
+ sa2 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] - borderwidth, cursor[1]});
}
bool isGlobal = ((sa1 && ED_area_is_global(sa1)) || (sa2 && ED_area_is_global(sa2)));
if (!isGlobal) {
@@ -1334,8 +1337,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE:
/* second area, for join */
- sad->sa2 = BKE_screen_find_area_xy(
- CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ sad->sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy);
break;
case LEFTMOUSE: /* release LMB */
if (event->val == KM_RELEASE) {
@@ -2081,15 +2083,31 @@ typedef struct sAreaSplitData {
} sAreaSplitData;
+static bool area_split_allowed(const ScrArea *area, const eScreenAxis dir_axis)
+{
+ if (!area || area->global) {
+ /* Must be a non-global area. */
+ return false;
+ }
+
+ if ((dir_axis == SCREEN_AXIS_V && area->winx <= 2 * AREAMINX) ||
+ (dir_axis == SCREEN_AXIS_H && area->winy <= 2 * ED_area_headersize())) {
+ /* Must be at least double minimum sizes to split into two. */
+ return false;
+ }
+
+ return true;
+}
+
static void area_split_draw_cb(const struct wmWindow *UNUSED(win), void *userdata)
{
const wmOperator *op = userdata;
sAreaSplitData *sd = op->customdata;
- if (sd->sarea) {
- const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
- float fac = RNA_float_get(op->ptr, "factor");
+ const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
+ if (area_split_allowed(sd->sarea, dir_axis)) {
+ float fac = RNA_float_get(op->ptr, "factor");
screen_draw_split_preview(sd->sarea, dir_axis, fac);
}
}
@@ -2119,18 +2137,6 @@ static bool area_split_init(bContext *C, wmOperator *op)
/* required properties */
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
- /* minimal size */
- if (dir_axis == SCREEN_AXIS_V) {
- if (area->winx < 2 * AREAMINX) {
- return false;
- }
- }
- else {
- if (area->winy < 2 * ED_area_headersize()) {
- return false;
- }
- }
-
/* custom data */
sAreaSplitData *sd = (sAreaSplitData *)MEM_callocN(sizeof(sAreaSplitData), "op_area_split");
op->customdata = sd;
@@ -2187,6 +2193,10 @@ static bool area_split_apply(bContext *C, wmOperator *op)
float fac = RNA_float_get(op->ptr, "factor");
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
+ if (!area_split_allowed(sd->sarea, dir_axis)) {
+ return false;
+ }
+
sd->narea = area_split(win, screen, sd->sarea, dir_axis, fac, false); /* false = no merge */
if (sd->narea == NULL) {
@@ -2252,9 +2262,15 @@ static void area_split_exit(bContext *C, wmOperator *op)
static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
{
- wmWindow *win = CTX_wm_window(C);
+ sAreaSplitData *sd = (sAreaSplitData *)op->customdata;
const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction");
- WM_cursor_set(win, (dir_axis == SCREEN_AXIS_H) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
+ if (area_split_allowed(sd->sarea, dir_axis)) {
+ WM_cursor_set(CTX_wm_window(C),
+ (dir_axis == SCREEN_AXIS_H) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
+ }
+ else {
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_STOP);
+ }
}
/* UI callback, adds new handler */
@@ -2507,9 +2523,11 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (sd->sarea) {
ED_area_tag_redraw(sd->sarea);
}
+
+ area_split_preview_update_cursor(C, op);
+
/* area context not set */
- sd->sarea = BKE_screen_find_area_xy(
- CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy);
if (sd->sarea) {
ScrArea *area = sd->sarea;
@@ -3517,7 +3535,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE: {
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
jd->dir = area_getorientation(jd->sa1, jd->sa2);
if (area == jd->sa1) {
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 5c4ba67d72a..4bc9f1e2565 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -166,8 +166,7 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (use_crop) {
area = CTX_wm_area(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area_test = BKE_screen_find_area_xy(
- screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area_test = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
if (area_test != NULL) {
area = area_test;
}
@@ -180,8 +179,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 125b345a1ed..6e69c82ba67 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -495,7 +495,7 @@ static void WORKSPACE_OT_reorder_to_back(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Workspace Reorder to Back";
- ot->description = "Reorder workspace to be first in the list";
+ ot->description = "Reorder workspace to be last in the list";
ot->idname = "WORKSPACE_OT_reorder_to_back";
/* api callbacks */
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index b826ff8701d..b15b6784d34 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../gpu
../../imbuf
../../makesdna
+ ../../nodes
../../makesrna
../../render
../../windowmanager
@@ -59,6 +60,7 @@ set(SRC
sculpt.c
sculpt_automasking.c
sculpt_boundary.c
+ sculpt_brush_types.c
sculpt_cloth.c
sculpt_detail.c
sculpt_dyntopo.c
@@ -71,6 +73,7 @@ set(SRC
sculpt_mask_expand.c
sculpt_mask_init.c
sculpt_multiplane_scrape.c
+ sculpt_ops.c
sculpt_paint_color.c
sculpt_pose.c
sculpt_smooth.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 265746e27cd..4010b87a2ed 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -47,6 +47,8 @@
#include "BKE_object.h"
#include "BKE_paint.h"
+#include "NOD_texture.h"
+
#include "WM_api.h"
#include "wm_cursors.h"
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index dc2eaacca0c..a912bb5cf3b 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -56,6 +56,8 @@
#include "BKE_paint.h"
#include "BKE_undo_system.h"
+#include "NOD_texture.h"
+
#include "DEG_depsgraph.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 7df5848e068..ca012f20f01 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -414,6 +414,7 @@ typedef struct ProjPaintState {
int totvert_eval;
const MVert *mvert_eval;
+ const float (*vert_normals)[3];
const MEdge *medge_eval;
const MPoly *mpoly_eval;
const MLoop *mloop_eval;
@@ -1718,10 +1719,10 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
float no[3], angle_cos;
if (mp->flag & ME_SMOOTH) {
- const short *no1, *no2, *no3;
- no1 = ps->mvert_eval[lt_vtri[0]].no;
- no2 = ps->mvert_eval[lt_vtri[1]].no;
- no3 = ps->mvert_eval[lt_vtri[2]].no;
+ const float *no1, *no2, *no3;
+ no1 = ps->vert_normals[lt_vtri[0]];
+ no2 = ps->vert_normals[lt_vtri[1]];
+ no3 = ps->vert_normals[lt_vtri[2]];
no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
@@ -3871,7 +3872,6 @@ static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int di
static void proj_paint_state_cavity_init(ProjPaintState *ps)
{
- const MVert *mv;
const MEdge *me;
float *cavities;
int a;
@@ -3891,13 +3891,11 @@ static void proj_paint_state_cavity_init(ProjPaintState *ps)
sub_v3_v3(edges[me->v1], e);
counter[me->v1]++;
}
- for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
+ for (a = 0; a < ps->totvert_eval; a++) {
if (counter[a] > 0) {
- float no[3];
mul_v3_fl(edges[a], 1.0f / counter[a]);
- normal_short_to_float_v3(no, mv->no);
/* Augment the difference. */
- cavities[a] = saacos(10.0f * dot_v3v3(no, edges[a])) * (float)M_1_PI;
+ cavities[a] = saacos(10.0f * dot_v3v3(ps->vert_normals[a], edges[a])) * (float)M_1_PI;
}
else {
cavities[a] = 0.0;
@@ -3964,7 +3962,7 @@ static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
ps->vertFlags = MEM_callocN(sizeof(char) * ps->totvert_eval, "paint-vertFlags");
for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
- normal_short_to_float_v3(no, mv->no);
+ copy_v3_v3(no, ps->vert_normals[a]);
if (UNLIKELY(ps->is_flip_object)) {
negate_v3(no);
}
@@ -4064,6 +4062,7 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
ps->mat_array[totmat - 1] = NULL;
ps->mvert_eval = ps->me_eval->mvert;
+ ps->vert_normals = BKE_mesh_vertex_normals_ensure(ps->me_eval);
if (ps->do_mask_cavity) {
ps->medge_eval = ps->me_eval->medge;
}
@@ -6567,7 +6566,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
nodeSetActive(ntree, imanode);
- /* Connect to first available principled bsdf node. */
+ /* Connect to first available principled BSDF node. */
bNode *in_node = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED);
bNode *out_node = imanode;
@@ -6623,7 +6622,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
}
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ ED_node_tree_propagate_change(C, bmain, ntree);
/* In case we added more than one node, position them too. */
nodePositionPropagate(out_node);
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 90887b9fc39..d31390bbb42 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -25,6 +25,8 @@
#include "BKE_paint.h"
+#include "BLI_compiler_compat.h"
+#include "BLI_math.h"
#include "BLI_rect.h"
#include "DNA_scene_types.h"
@@ -150,10 +152,7 @@ unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp, bool
/**
* \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);
+unsigned int ED_vpaint_blend_tool(int tool, uint col, uint paintcol, int alpha_i);
/**
* Apply callback to each vertex of the active vertex color layer.
*/
@@ -171,10 +170,7 @@ bool ED_vpaint_color_transform(struct Object *ob,
*
* \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,
- const float alpha);
+float ED_wpaint_blend_tool(int tool, float weight, float paintval, float alpha);
/* Utility for tools to ensure vertex groups exist before they begin. */
enum eWPaintFlag {
WPAINT_ENSURE_MIRROR = (1 << 0),
@@ -191,7 +187,7 @@ bool ED_wpaint_ensure_data(struct bContext *C,
enum eWPaintFlag flag,
struct WPaintVGroupIndex *vgroup_index);
/** Return -1 when invalid. */
-int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, const int vgroup_active);
+int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, int vgroup_active);
/* paint_vertex_color_ops.c */
@@ -244,7 +240,7 @@ void paint_2d_stroke_done(void *ps);
void paint_2d_stroke(void *ps,
const float prev_mval[2],
const float mval[2],
- const bool eraser,
+ bool eraser,
float pressure,
float distance,
float size);
@@ -267,7 +263,7 @@ void paint_proj_stroke(const struct bContext *C,
void *ps_handle_p,
const float prev_pos[2],
const float pos[2],
- const bool eraser,
+ bool eraser,
float pressure,
float distance,
float size);
@@ -331,8 +327,8 @@ typedef struct 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,
+ int diameter,
+ float radius,
const float cursor_position[2]);
/* sculpt_uv.c */
@@ -404,8 +400,61 @@ bool facemask_paint_poll(struct bContext *C);
/**
* Uses symm to selectively flip any axis of a coordinate.
*/
-void flip_v3_v3(float out[3], const float in[3], const enum ePaintSymmetryFlags symm);
-void flip_qt_qt(float out[4], const float in[4], const enum ePaintSymmetryFlags symm);
+
+BLI_INLINE void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
+{
+ if (symm & PAINT_SYMM_X) {
+ out[0] = -in[0];
+ }
+ else {
+ out[0] = in[0];
+ }
+ if (symm & PAINT_SYMM_Y) {
+ out[1] = -in[1];
+ }
+ else {
+ out[1] = in[1];
+ }
+ if (symm & PAINT_SYMM_Z) {
+ out[2] = -in[2];
+ }
+ else {
+ out[2] = in[2];
+ }
+}
+
+BLI_INLINE void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
+{
+ float axis[3], angle;
+
+ quat_to_axis_angle(axis, &angle, in);
+ normalize_v3(axis);
+
+ if (symm & PAINT_SYMM_X) {
+ axis[0] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Y) {
+ axis[1] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Z) {
+ axis[2] *= -1.0f;
+ angle *= -1.0f;
+ }
+
+ axis_angle_normalized_to_quat(out, axis, angle);
+}
+
+BLI_INLINE void flip_v3(float v[3], const ePaintSymmetryFlags symm)
+{
+ flip_v3_v3(v, v, symm);
+}
+
+BLI_INLINE void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
+{
+ flip_qt_qt(quat, quat, symm);
+}
/* stroke operator */
typedef enum BrushStrokeMode {
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 541893f7957..95a0aba1ffb 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -397,51 +397,6 @@ static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index)
return ima;
}
-void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
-{
- if (symm & PAINT_SYMM_X) {
- out[0] = -in[0];
- }
- else {
- out[0] = in[0];
- }
- if (symm & PAINT_SYMM_Y) {
- out[1] = -in[1];
- }
- else {
- out[1] = in[1];
- }
- if (symm & PAINT_SYMM_Z) {
- out[2] = -in[2];
- }
- else {
- out[2] = in[2];
- }
-}
-
-void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
-{
- float axis[3], angle;
-
- quat_to_axis_angle(axis, &angle, in);
- normalize_v3(axis);
-
- if (symm & PAINT_SYMM_X) {
- axis[0] *= -1.0f;
- angle *= -1.0f;
- }
- if (symm & PAINT_SYMM_Y) {
- axis[1] *= -1.0f;
- angle *= -1.0f;
- }
- if (symm & PAINT_SYMM_Z) {
- axis[2] *= -1.0f;
- angle *= -1.0f;
- }
-
- axis_angle_normalized_to_quat(out, axis, angle);
-}
-
void paint_sample_color(
bContext *C, ARegion *region, int x, int y, bool texpaint_proj, bool use_palette)
{
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 23e03f3e576..75d4237d157 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -32,6 +32,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
+#include "BLI_string.h"
#include "BLI_task.h"
#include "DNA_brush_types.h"
@@ -43,9 +44,11 @@
#include "RNA_access.h"
#include "BKE_brush.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_layer.h"
+#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
@@ -1470,14 +1473,48 @@ struct WPaintData {
bool precomputed_weight_ready;
};
+static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = paint->brush;
+ int cur_brush_size = BKE_brush_size_get(scene, brush);
+
+ BLI_strncpy(
+ cache->saved_active_brush_name, brush->id.name + 2, sizeof(cache->saved_active_brush_name));
+
+ /* Switch to the blur (smooth) brush. */
+ brush = BKE_paint_toolslots_brush_get(paint, WPAINT_TOOL_BLUR);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
+ cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
+ BKE_brush_size_set(scene, brush, cur_brush_size);
+ BKE_curvemapping_init(brush->curve);
+ }
+}
+
+static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = BKE_paint_brush(paint);
+ /* The current brush should match with what we have stored in the cache. */
+ BLI_assert(brush == cache->brush);
+
+ /* Try to switch back to the saved/previous brush. */
+ BKE_brush_size_set(scene, brush, cache->saved_smooth_size);
+ brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, cache->saved_active_brush_name);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
+ }
+}
+
/* Initialize the stroke cache invariants from operator properties */
static void vwpaint_update_cache_invariants(
- bContext *C, const VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
+ bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
{
StrokeCache *cache;
Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- const Brush *brush = vp->paint.brush;
ViewContext *vc = paint_stroke_view_context(op->customdata);
Object *ob = CTX_data_active_object(C);
float mat[3][3];
@@ -1513,7 +1550,12 @@ static void vwpaint_update_cache_invariants(
ups->draw_inverted = false;
}
+ if (cache->alt_smooth) {
+ smooth_brush_toggle_on(C, &vp->paint, cache);
+ }
+
copy_v2_v2(cache->mouse, cache->initial_mouse);
+ Brush *brush = vp->paint.brush;
/* Truly temporary data that isn't stored in properties */
cache->vc = vc;
cache->brush = brush;
@@ -1715,15 +1757,15 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
wpd->mirror.lock = tmpflags;
}
- if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
- wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
- }
-
/* If not previously created, create vertex/weight paint mode session data */
vertex_paint_init_stroke(depsgraph, ob);
vwpaint_update_cache_invariants(C, vp, ss, op, mouse);
vertex_paint_init_session_data(ts, ob);
+ if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) {
+ wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__);
+ }
+
if (ob->sculpt->mode.wpaint.dvert_prev != NULL) {
MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev;
for (int i = 0; i < me->totvert; i++, dv++) {
@@ -1735,13 +1777,6 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
return true;
}
-static float dot_vf3vs3(const float brushNormal[3], const short vertexNormal[3])
-{
- float normal[3];
- normal_short_to_float_v3(normal, vertexNormal);
- return dot_v3v3(brushNormal, normal);
-}
-
static void get_brush_alpha_data(const Scene *scene,
const SculptSession *ss,
const Brush *brush,
@@ -1868,7 +1903,7 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
if (total_hit_loops != 0) {
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
@@ -1948,7 +1983,7 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) {
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
@@ -2054,9 +2089,8 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
/* If the vertex is selected */
if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -2111,7 +2145,7 @@ static void do_wpaint_brush_calc_average_weight_cb_ex(
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float angle_cos = (use_normal && vd.no) ? dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (angle_cos > 0.0 &&
BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) {
@@ -2403,7 +2437,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
wpi.vgroup_validmap = wpd->vgroup_validmap;
wpi.vgroup_locked = wpd->vgroup_locked;
wpi.vgroup_unlocked = wpd->vgroup_unlocked;
- wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip");
+ wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip") || ss->cache->invert;
wpi.do_multipaint = wpd->do_multipaint;
wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != NULL) &&
(wpi.do_multipaint || wpi.vgroup_validmap[wpi.active.index]));
@@ -2488,6 +2522,14 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN(wpd);
}
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->cache->alt_smooth) {
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ VPaint *vp = ts->wpaint;
+ smooth_brush_toggle_off(C, &vp->paint, ss->cache);
+ }
+
/* and particles too */
if (ob->particlesystem.first) {
ParticleSystem *psys;
@@ -2895,9 +2937,8 @@ static void do_vpaint_brush_draw_task_cb_ex(void *__restrict userdata,
/* Calc the dot prod. between ray norm on surf and current vert
* (ie splash prevention factor), and only paint front facing verts. */
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -2990,9 +3031,8 @@ static void do_vpaint_brush_blur_task_cb_ex(void *__restrict userdata,
/* If the vertex is selected for painting. */
if (!use_vert_sel || mv->flag & SELECT) {
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -3116,7 +3156,7 @@ static void do_vpaint_brush_smear_task_cb_ex(void *__restrict userdata,
* (ie splash prevention factor), and only paint front facing verts. */
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
@@ -3443,6 +3483,14 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
MEM_freeN(vpd->smear.color_curr);
}
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->cache->alt_smooth) {
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ VPaint *vp = ts->vpaint;
+ smooth_brush_toggle_off(C, &vp->paint, ss->cache);
+ }
+
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
MEM_freeN(vpd);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
index 85cd211367a..9d5fffdcfcc 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
@@ -72,8 +72,10 @@ struct VertProjUpdate {
/* -------------------------------------------------------------------- */
/* Internal Init */
-static void vpaint_proj_dm_map_cosnos_init__map_cb(
- void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
+static void vpaint_proj_dm_map_cosnos_init__map_cb(void *userData,
+ int index,
+ const float co[3],
+ const float no[3])
{
struct VertProjHandle *vp_handle = userData;
CoNo *co_no = &vp_handle->vcosnos[index];
@@ -86,12 +88,7 @@ static void vpaint_proj_dm_map_cosnos_init__map_cb(
}
copy_v3_v3(co_no->co, co);
- if (no_f) {
- copy_v3_v3(co_no->no, no_f);
- }
- else {
- normal_short_to_float_v3(co_no->no, no_s);
- }
+ copy_v3_v3(co_no->no, no);
}
static void vpaint_proj_dm_map_cosnos_init(struct Depsgraph *depsgraph,
@@ -116,8 +113,10 @@ static void vpaint_proj_dm_map_cosnos_init(struct Depsgraph *depsgraph,
/* Same as init but take mouse location into account */
-static void vpaint_proj_dm_map_cosnos_update__map_cb(
- void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
+static void vpaint_proj_dm_map_cosnos_update__map_cb(void *userData,
+ int index,
+ const float co[3],
+ const float no[3])
{
struct VertProjUpdate *vp_update = userData;
struct VertProjHandle *vp_handle = vp_update->vp_handle;
@@ -148,12 +147,7 @@ static void vpaint_proj_dm_map_cosnos_update__map_cb(
/* continue with regular functionality */
copy_v3_v3(co_no->co, co);
- if (no_f) {
- copy_v3_v3(co_no->no, no_f);
- }
- else {
- normal_short_to_float_v3(co_no->no, no_s);
- }
+ copy_v3_v3(co_no->no, no);
}
static void vpaint_proj_dm_map_cosnos_update(struct Depsgraph *depsgraph,
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 d10a56be866..1dfc4db6ac3 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -665,8 +665,7 @@ static void gradientVert_update(WPGradient_userData *grad_data, int index)
static void gradientVertUpdate__mapFunc(void *userData,
int index,
const float UNUSED(co[3]),
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
WPGradient_userData *grad_data = userData;
WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
@@ -681,8 +680,7 @@ static void gradientVertUpdate__mapFunc(void *userData,
static void gradientVertInit__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
WPGradient_userData *grad_data = userData;
Mesh *me = grad_data->me;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index aeeed094aab..2725fc1eae4 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -73,6 +73,8 @@
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
+#include "NOD_texture.h"
+
#include "DEG_depsgraph.h"
#include "IMB_colormanagement.h"
@@ -177,11 +179,11 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
if (ss->shapekey_active || ss->deform_modifiers_active) {
- const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
- normal_short_to_float_v3(no, mverts[index].no);
+ const float(*vert_normals)[3] = BKE_pbvh_get_vert_normals(ss->pbvh);
+ copy_v3_v3(no, vert_normals[index]);
}
else {
- normal_short_to_float_v3(no, ss->mvert[index].no);
+ copy_v3_v3(no, ss->vert_normals[index]);
}
break;
}
@@ -1329,103 +1331,6 @@ static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3
}
}
-static void sculpt_rake_rotate(const SculptSession *ss,
- const float sculpt_co[3],
- const float v_co[3],
- float factor,
- float r_delta[3])
-{
- float vec_rot[3];
-
-#if 0
- /* lerp */
- sub_v3_v3v3(vec_rot, v_co, sculpt_co);
- mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
- add_v3_v3(vec_rot, sculpt_co);
- sub_v3_v3v3(r_delta, vec_rot, v_co);
- mul_v3_fl(r_delta, factor);
-#else
- /* slerp */
- float q_interp[4];
- sub_v3_v3v3(vec_rot, v_co, sculpt_co);
-
- copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
- pow_qt_fl_normalized(q_interp, factor);
- mul_qt_v3(q_interp, vec_rot);
-
- add_v3_v3(vec_rot, sculpt_co);
- sub_v3_v3v3(r_delta, vec_rot, v_co);
-#endif
-}
-
-/**
- * Align the grab delta to the brush normal.
- *
- * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`.
- */
-static void sculpt_project_v3_normal_align(SculptSession *ss,
- const float normal_weight,
- float grab_delta[3])
-{
- /* Signed to support grabbing in (to make a hole) as well as out. */
- const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
-
- /* This scale effectively projects the offset so dragging follows the cursor,
- * as the normal points towards the view, the scale increases. */
- float len_view_scale;
- {
- float view_aligned_normal[3];
- project_plane_v3_v3v3(
- view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
- len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
- len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
- }
-
- mul_v3_fl(grab_delta, 1.0f - normal_weight);
- madd_v3_v3fl(
- grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name SculptProjectVector
- *
- * Fast-path for #project_plane_v3_v3v3
- * \{ */
-
-typedef struct SculptProjectVector {
- float plane[3];
- float len_sq;
- float len_sq_inv_neg;
- bool is_valid;
-
-} SculptProjectVector;
-
-/**
- * \param plane: Direction, can be any length.
- */
-static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3])
-{
- copy_v3_v3(spvc->plane, plane);
- spvc->len_sq = len_squared_v3(spvc->plane);
- spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
- spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
-}
-
-/**
- * Calculate the projection.
- */
-static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3])
-{
-#if 0
- project_plane_v3_v3v3(r_vec, vec, spvc->plane);
-#else
- /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
- madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
-#endif
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1484,10 +1389,10 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
copy_v3_v3(vd.co, orig_data.co);
if (vd.no) {
- copy_v3_v3_short(vd.no, orig_data.no);
+ copy_v3_v3(vd.no, orig_data.no);
}
else {
- normal_short_to_float_v3(vd.fno, orig_data.no);
+ copy_v3_v3(vd.fno, orig_data.no);
}
}
else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
@@ -1786,7 +1691,7 @@ const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
static float frontface(const Brush *br,
const float sculpt_normal[3],
- const short no[3],
+ const float no[3],
const float fno[3])
{
if (!(br->flag & BRUSH_FRONTFACE)) {
@@ -1795,10 +1700,7 @@ static float frontface(const Brush *br,
float dot;
if (no) {
- float tmp[3];
-
- normal_short_to_float_v3(tmp, no);
- dot = dot_v3v3(tmp, sculpt_normal);
+ dot = dot_v3v3(no, sculpt_normal);
}
else {
dot = dot_v3v3(fno, sculpt_normal);
@@ -1835,15 +1737,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
/* ===== Sculpting =====
*/
-static void flip_v3(float v[3], const ePaintSymmetryFlags symm)
-{
- flip_v3_v3(v, v, symm);
-}
-
-static void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
-{
- flip_qt_qt(quat, quat, symm);
-}
static float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle)
{
@@ -1913,9 +1806,9 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* (optionally using original coordinates).
*
* Functions are:
- * - #calc_area_center
- * - #calc_area_normal
- * - #calc_area_normal_and_center
+ * - #SCULPT_calc_area_center
+ * - #SCULPT_calc_area_normal
+ * - #SCULPT_calc_area_normal_and_center
*
* \note These are all _very_ similar, when changing one, check others.
* \{ */
@@ -2044,19 +1937,19 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
float co[3];
/* For bm_vert only. */
- short no_s[3];
+ float no_s[3];
if (use_original) {
if (unode->bm_entry) {
const float *temp_co;
- const short *temp_no_s;
+ const float *temp_no_s;
BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s);
copy_v3_v3(co, temp_co);
- copy_v3_v3_short(no_s, temp_no_s);
+ copy_v3_v3(no_s, temp_no_s);
}
else {
copy_v3_v3(co, unode->co[vd.i]);
- copy_v3_v3_short(no_s, unode->no[vd.i]);
+ copy_v3_v3(no_s, unode->no[vd.i]);
}
}
else {
@@ -2076,11 +1969,11 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
data->any_vertex_sampled = true;
if (use_original) {
- normal_short_to_float_v3(no, no_s);
+ copy_v3_v3(no, no_s);
}
else {
if (vd.no) {
- normal_short_to_float_v3(no, vd.no);
+ copy_v3_v3(no, vd.no);
}
else {
copy_v3_v3(no, vd.fno);
@@ -2137,7 +2030,7 @@ static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(use
add_v2_v2_int(join->count_co, anctd->count_co);
}
-static void calc_area_center(
+void SCULPT_calc_area_center(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
@@ -2234,11 +2127,7 @@ 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.
- */
-static void calc_area_normal_and_center(
+void SCULPT_calc_area_normal_and_center(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
@@ -2460,7 +2349,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
const Brush *br,
const float brush_point[3],
const float len,
- const short vno[3],
+ const float vno[3],
const float fno[3],
const float mask,
const int vertex_index,
@@ -2633,9 +2522,23 @@ void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
continue;
}
- if (ss->cache && (ss->cache->flag & (CLIP_X << i)) &&
- (fabsf(co[i]) <= ss->cache->clip_tolerance[i])) {
- co[i] = 0.0f;
+ bool do_clip = false;
+ float co_clip[3];
+ if (ss->cache && (ss->cache->flag & (CLIP_X << i))) {
+ /* Take possible mirror object into account. */
+ mul_v3_m4v3(co_clip, ss->cache->clip_mirror_mtx, co);
+
+ if (fabsf(co_clip[i]) <= ss->cache->clip_tolerance[i]) {
+ co_clip[i] = 0.0f;
+ float imtx[4][4];
+ invert_m4_m4(imtx, ss->cache->clip_mirror_mtx);
+ mul_m4_v3(imtx, co_clip);
+ do_clip = true;
+ }
+ }
+
+ if (do_clip) {
+ co[i] = co_clip[i];
}
else {
co[i] = val[i];
@@ -2856,10 +2759,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Topology Rake (Shared Utility)
- * \{ */
-
typedef struct {
SculptSession *ss;
const float *ray_start;
@@ -2885,1295 +2784,6 @@ typedef struct {
bool original;
} SculptFindNearestToRayData;
-static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
-
- float direction[3];
- copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
-
- float tmp[3];
- mul_v3_v3fl(
- tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
- sub_v3_v3(direction, tmp);
- normalize_v3(direction);
-
- /* Cancel if there's no grab data. */
- if (is_zero_v3(direction)) {
- return;
- }
-
- const float bstrength = clamp_f(data->strength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade =
- bstrength *
- SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
- ss->cache->pressure;
-
- float avg[3], val[3];
-
- SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
-
- sub_v3_v3v3(val, avg, vd.co);
-
- madd_v3_v3v3fl(val, vd.co, val, fade);
-
- SCULPT_clip(sd, ss, vd.co, val);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void bmesh_topology_rake(
- Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- const float strength = clamp_f(bstrength, 0.0f, 1.0f);
-
- /* Interactions increase both strength and quality. */
- const int iterations = 3;
-
- int iteration;
- const int count = iterations * strength + 1;
- const float factor = iterations * strength / count;
-
- for (iteration = 0; iteration <= count; iteration++) {
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .strength = factor,
- };
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
-
- BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Mask Brush
- * \{ */
-
-static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- const float fade = SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
-
- if (bstrength > 0.0f) {
- (*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
- }
- else {
- (*vd.mask) += fade * bstrength * (*vd.mask);
- }
- *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
-}
-
-static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- switch ((BrushMaskTool)brush->mask_tool) {
- case BRUSH_MASK_DRAW:
- do_mask_brush_draw(sd, ob, nodes, totnode);
- break;
- case BRUSH_MASK_SMOOTH:
- SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
- break;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Multires Displacement Eraser Brush
- * \{ */
-
-static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
-
- float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- float limit_co[3];
- float disp[3];
- SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co);
- sub_v3_v3v3(disp, limit_co, vd.co);
- mul_v3_v3fl(proxy[vd.i], disp, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Multires Displacement Smear Brush
- * \{ */
-
-static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- float current_disp[3];
- float current_disp_norm[3];
- float interp_limit_surface_disp[3];
-
- copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]);
-
- switch (brush->smear_deform_type) {
- case BRUSH_SMEAR_DEFORM_DRAG:
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
- break;
- case BRUSH_SMEAR_DEFORM_PINCH:
- sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
- break;
- case BRUSH_SMEAR_DEFORM_EXPAND:
- sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
- break;
- }
-
- normalize_v3_v3(current_disp_norm, current_disp);
- mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
-
- float weights_accum = 1.0f;
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
- float vertex_disp[3];
- float vertex_disp_norm[3];
- float neighbor_limit_co[3];
- SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
- sub_v3_v3v3(vertex_disp,
- ss->cache->limit_surface_co[ni.index],
- ss->cache->limit_surface_co[vd.index]);
- const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index];
- normalize_v3_v3(vertex_disp_norm, vertex_disp);
-
- if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
- continue;
- }
-
- const float disp_interp = clamp_f(
- -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f);
- madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp);
- weights_accum += disp_interp;
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum);
-
- float new_co[3];
- add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp);
- interp_v3_v3v3(vd.co, vd.co, new_co, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_smear_store_prev_disp_task_cb_ex(
- void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
- SCULPT_vertex_co_get(ss, vd.index),
- ss->cache->limit_surface_co[vd.index]);
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
-
- BKE_curvemapping_init(brush->curve);
-
- const int totvert = SCULPT_vertex_count_get(ss);
- if (!ss->cache->prev_displacement) {
- ss->cache->prev_displacement = MEM_malloc_arrayN(
- totvert, sizeof(float[3]), "prev displacement");
- ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
- for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
- sub_v3_v3v3(ss->cache->prev_displacement[i],
- SCULPT_vertex_co_get(ss, i),
- ss->cache->limit_surface_co[i]);
- }
- }
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(
- 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings);
- BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Draw Brush
- * \{ */
-
-static void do_draw_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], offset, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- const float bstrength = ss->cache->bstrength;
-
- /* Offset with as much as possible factored in already. */
- float effective_normal[3];
- SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
- mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
- * initialize before threads so they can do curve mapping. */
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .offset = offset,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
-}
-
-static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], offset, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- const float bstrength = ss->cache->bstrength;
-
- /* Offset with as much as possible factored in already. */
- float effective_normal[3];
- SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
- mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
- * initialize before threads so they can do curve mapping. */
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .offset = offset,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Topology Brush
- * \{ */
-
-static void do_topology_slide_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float current_disp[3];
- float current_disp_norm[3];
- float final_disp[3] = {0.0f, 0.0f, 0.0f};
-
- switch (brush->slide_deform_type) {
- case BRUSH_SLIDE_DEFORM_DRAG:
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
- break;
- case BRUSH_SLIDE_DEFORM_PINCH:
- sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
- break;
- case BRUSH_SLIDE_DEFORM_EXPAND:
- sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
- break;
- }
-
- normalize_v3_v3(current_disp_norm, current_disp);
- mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
- float vertex_disp[3];
- float vertex_disp_norm[3];
- sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
- normalize_v3_v3(vertex_disp_norm, vertex_disp);
- if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) {
- madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- mul_v3_v3fl(proxy[vd.i], final_disp, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-void SCULPT_relax_vertex(SculptSession *ss,
- PBVHVertexIter *vd,
- float factor,
- bool filter_boundary_face_sets,
- float *r_final_pos)
-{
- float smooth_pos[3];
- float final_disp[3];
- float boundary_normal[3];
- int avg_count = 0;
- int neighbor_count = 0;
- zero_v3(smooth_pos);
- zero_v3(boundary_normal);
- const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index);
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
- neighbor_count++;
- if (!filter_boundary_face_sets ||
- (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
-
- /* When the vertex to relax is boundary, use only connected boundary vertices for the average
- * position. */
- if (is_boundary) {
- if (!SCULPT_vertex_is_boundary(ss, ni.index)) {
- continue;
- }
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
- avg_count++;
-
- /* Calculate a normal for the constraint plane using the edges of the boundary. */
- float to_neighbor[3];
- sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co);
- normalize_v3(to_neighbor);
- add_v3_v3(boundary_normal, to_neighbor);
- }
- else {
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
- avg_count++;
- }
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- /* Don't modify corner vertices. */
- if (neighbor_count <= 2) {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- if (avg_count > 0) {
- mul_v3_fl(smooth_pos, 1.0f / avg_count);
- }
- else {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- float plane[4];
- float smooth_closest_plane[3];
- float vno[3];
-
- if (is_boundary && avg_count == 2) {
- normalize_v3_v3(vno, boundary_normal);
- }
- else {
- SCULPT_vertex_normal_get(ss, vd->index, vno);
- }
-
- if (is_zero_v3(vno)) {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- plane_from_point_normal_v3(plane, vd->co, vno);
- closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos);
- sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co);
-
- mul_v3_fl(final_disp, factor);
- add_v3_v3v3(r_final_pos, vd->co, final_disp);
-}
-
-static void do_topology_relax_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- BKE_curvemapping_init(brush->curve);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- if (ss->cache->alt_smooth) {
- SCULPT_boundary_info_ensure(ob);
- for (int i = 0; i < 4; i++) {
- BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
- }
- }
- else {
- BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
- }
-}
-
-static void calc_sculpt_plane(
- Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) &&
- (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) ||
- !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
- switch (brush->sculpt_plane) {
- case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(r_area_no, ss->cache->true_view_normal);
- break;
-
- case SCULPT_DISP_DIR_X:
- ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f);
- break;
-
- case SCULPT_DISP_DIR_Y:
- ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f);
- break;
-
- case SCULPT_DISP_DIR_Z:
- ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f);
- break;
-
- case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
- normalize_v3(r_area_no);
- }
- break;
-
- default:
- break;
- }
-
- /* For flatten center. */
- /* Flatten center has not been calculated yet if we are not using the area normal. */
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
- calc_area_center(sd, ob, nodes, totnode, r_area_co);
- }
-
- /* For area normal. */
- if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
- (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
- }
- else {
- copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
- }
-
- /* For flatten center. */
- if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
- (brush->flag & BRUSH_ORIGINAL_PLANE)) {
- copy_v3_v3(r_area_co, ss->cache->last_center);
- }
- else {
- copy_v3_v3(ss->cache->last_center, r_area_co);
- }
- }
- else {
- /* For area normal. */
- copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
-
- /* For flatten center. */
- copy_v3_v3(r_area_co, ss->cache->last_center);
-
- /* For area normal. */
- flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
-
- /* For flatten center. */
- flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
-
- /* For area normal. */
- mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
-
- /* For flatten center. */
- mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
-
- /* Shift the plane for the current tile. */
- add_v3_v3(r_area_co, ss->cache->plane_offset);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Crease & Blob Brush
- * \{ */
-
-/**
- * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
- */
-static void do_crease_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- SculptProjectVector *spvc = data->spvc;
- const float flippedbstrength = data->flippedbstrength;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float val1[3];
- float val2[3];
-
- /* First we pinch. */
- sub_v3_v3v3(val1, test.location, vd.co);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(val1, val1, ss->cache->view_normal);
- }
-
- mul_v3_fl(val1, fade * flippedbstrength);
-
- sculpt_project_v3(spvc, val1, val1);
-
- /* Then we draw. */
- mul_v3_v3fl(val2, offset, fade);
-
- add_v3_v3v3(proxy[vd.i], val1, val2);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- const Scene *scene = ss->cache->vc->scene;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- float bstrength = ss->cache->bstrength;
- float flippedbstrength, crease_correction;
- float brush_alpha;
-
- SculptProjectVector spvc;
-
- /* Offset with as much as possible factored in already. */
- mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* We divide out the squared alpha and multiply by the squared crease
- * to give us the pinch strength. */
- crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor;
- brush_alpha = BKE_brush_alpha_get(scene, brush);
- if (brush_alpha > 0.0f) {
- crease_correction /= brush_alpha * brush_alpha;
- }
-
- /* We always want crease to pinch or blob to relax even when draw is negative. */
- flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength :
- crease_correction * bstrength;
-
- if (brush->sculpt_tool == SCULPT_TOOL_BLOB) {
- flippedbstrength *= -1.0f;
- }
-
- /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single
- * point. Without this we get a 'flat' surface surrounding the pinch. */
- sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .spvc = &spvc,
- .offset = offset,
- .flippedbstrength = flippedbstrength,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
-}
-
-static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*stroke_xz)[3] = data->stroke_xz;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- float x_object_space[3];
- float z_object_space[3];
- copy_v3_v3(x_object_space, stroke_xz[0]);
- copy_v3_v3(z_object_space, stroke_xz[1]);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float disp_center[3];
- float x_disp[3];
- float z_disp[3];
- /* Calculate displacement from the vertex to the brush center. */
- sub_v3_v3v3(disp_center, test.location, vd.co);
-
- /* Project the displacement into the X vector (aligned to the stroke). */
- mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space));
-
- /* Project the displacement into the Z vector (aligned to the surface normal). */
- mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space));
-
- /* Add the two projected vectors to calculate the final displacement.
- * The Y component is removed. */
- add_v3_v3v3(disp_center, x_disp, z_disp);
-
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal);
- }
- mul_v3_v3fl(proxy[vd.i], disp_center, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- float area_no[3];
- float area_co[3];
-
- float mat[4][4];
- calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- /* delay the first daub because grab delta is not setup */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- /* Initialize `mat`. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], ss->cache->location);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- float stroke_xz[2][3];
- normalize_v3_v3(stroke_xz[0], mat[0]);
- normalize_v3_v3(stroke_xz[1], mat[2]);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .stroke_xz = stroke_xz,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
-}
-
-static void do_grab_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *grab_delta = data->grab_delta;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- if (grab_silhouette) {
- float silhouette_test_dir[3];
- normalize_v3_v3(silhouette_test_dir, grab_delta);
- if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) {
- mul_v3_fl(silhouette_test_dir, -1.0f);
- }
- float vno[3];
- normal_short_to_float_v3(vno, orig_data.no);
- fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f);
- }
-
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
-}
-
-static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *grab_delta = data->grab_delta;
- const float *location = ss->cache->location;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- float dir;
- if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
- dir = 1.0f;
- }
- else {
- dir = -1.0f;
- }
-
- if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
- int symm = ss->cache->mirror_symmetry_pass;
- if (ELEM(symm, 1, 2, 4, 7)) {
- dir = -dir;
- }
- }
-
- KelvinletParams params;
- float force = len_v3(grab_delta) * dir * bstrength;
- BKE_kelvinlet_init_params(
- &params, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- float final_disp[3];
- switch (brush->elastic_deform_type) {
- case BRUSH_ELASTIC_DEFORM_GRAB:
- BKE_kelvinlet_grab(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: {
- BKE_kelvinlet_grab_biscale(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- }
- case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: {
- BKE_kelvinlet_grab_triscale(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- }
- case BRUSH_ELASTIC_DEFORM_SCALE:
- BKE_kelvinlet_scale(
- final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
- break;
- case BRUSH_ELASTIC_DEFORM_TWIST:
- BKE_kelvinlet_twist(
- final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
- break;
- }
-
- if (vd.mask) {
- mul_v3_fl(final_disp, 1.0f - *vd.mask);
- }
-
- mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
-
- copy_v3_v3(proxy[vd.i], final_disp);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
-}
-
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3])
{
ePaintSymmetryAreas symm_area = PAINT_SYMM_AREA_DEFAULT;
@@ -4257,7 +2867,7 @@ void SCULPT_calc_brush_plane(
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
+ SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
normalize_v3(r_area_no);
@@ -4271,7 +2881,7 @@ void SCULPT_calc_brush_plane(
/* For flatten center. */
/* Flatten center has not been calculated yet if we are not using the area normal. */
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
- calc_area_center(sd, ob, nodes, totnode, r_area_co);
+ SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co);
}
/* For area normal. */
@@ -4316,564 +2926,12 @@ void SCULPT_calc_brush_plane(
}
}
-static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *cono = data->cono;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], cono, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float tmp[3], cono[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
- cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .cono = cono,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
-}
-
-static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- SculptProjectVector *spvc = data->spvc;
- const float *grab_delta = data->grab_delta;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
- const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
- const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
- const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) *
- (len_v3(grab_delta) / ss->cache->radius)) :
- 0.0f;
-
- const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- KelvinletParams params;
- BKE_kelvinlet_init_params(&params, ss->cache->radius, bstrength, 1.0f, 0.4f);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float fade;
- if (do_elastic) {
- fade = 1.0f;
- }
- else {
- fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- }
-
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
-
- /* Negative pinch will inflate, helps maintain volume. */
- if (do_pinch) {
- float delta_pinch_init[3], delta_pinch[3];
-
- sub_v3_v3v3(delta_pinch, vd.co, test.location);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal);
- }
-
- /* Important to calculate based on the grabbed location
- * (intentionally ignore fade here). */
- add_v3_v3(delta_pinch, grab_delta);
-
- sculpt_project_v3(spvc, delta_pinch, delta_pinch);
-
- copy_v3_v3(delta_pinch_init, delta_pinch);
-
- float pinch_fade = pinch * fade;
- /* When reducing, scale reduction back by how close to the center we are,
- * so we don't pinch into nothingness. */
- if (pinch > 0.0f) {
- /* Square to have even less impact for close vertices. */
- pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
- }
- mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
- sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
- add_v3_v3(proxy[vd.i], delta_pinch);
- }
-
- if (do_rake_rotation) {
- float delta_rotate[3];
- sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
- add_v3_v3(proxy[vd.i], delta_rotate);
- }
-
- if (do_elastic) {
- float disp[3];
- BKE_kelvinlet_grab_triscale(disp, &params, vd.co, ss->cache->location, proxy[vd.i]);
- mul_v3_fl(disp, bstrength * 20.0f);
- if (vd.mask) {
- mul_v3_fl(disp, 1.0f - *vd.mask);
- }
- mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
- copy_v3_v3(proxy[vd.i], disp);
- }
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- const float bstrength = ss->cache->bstrength;
- float grab_delta[3];
-
- SculptProjectVector spvc;
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (bstrength < 0.0f) {
- negate_v3(grab_delta);
- }
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- /* Optionally pinch while painting. */
- if (brush->crease_pinch_factor != 0.5f) {
- sculpt_project_v3_cache_init(&spvc, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .spvc = &spvc,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
-}
-
-static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *cono = data->cono;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], cono, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float tmp[3], cono[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
- cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .cono = cono,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
-}
-
-static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float angle = data->angle;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- float vec[3], rot[3][3];
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
- axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
- mul_v3_m3v3(proxy[vd.i], rot, vec);
- add_v3_v3(proxy[vd.i], ss->cache->location);
- sub_v3_v3(proxy[vd.i], orig_data.co);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1};
- const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .angle = angle,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
-}
-
-static void do_layer_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
-
- const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- const int vi = vd.index;
- float *disp_factor;
- if (use_persistent_base) {
- disp_factor = &ss->persistent_base[vi].disp;
- }
- else {
- disp_factor = &ss->cache->layer_displacement_factor[vi];
- }
-
- /* When using persistent base, the layer brush (holding Control) invert mode resets the
- * height of the layer to 0. This makes possible to clean edges of previously added layers
- * on top of the base. */
- /* The main direction of the layers is inverted using the regular brush strength with the
- * brush direction property. */
- if (use_persistent_base && ss->cache->invert) {
- (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) *
- ((*disp_factor) > 0.0f ? -1.0f : 1.0f);
- }
- else {
- (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor));
- }
- if (vd.mask) {
- const float clamp_mask = 1.0f - *vd.mask;
- *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask);
- }
- else {
- *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f);
- }
-
- float final_co[3];
- float normal[3];
-
- if (use_persistent_base) {
- SCULPT_vertex_persistent_normal_get(ss, vi, normal);
- mul_v3_fl(normal, brush->height);
- madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor);
- }
- else {
- normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_fl(normal, brush->height);
- madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
- }
-
- float vdisp[3];
- sub_v3_v3v3(vdisp, final_co, vd.co);
- mul_v3_fl(vdisp, fabsf(fade));
- add_v3_v3v3(final_co, vd.co, vdisp);
-
- SCULPT_clip(sd, ss, vd.co, final_co);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (ss->cache->layer_displacement_factor == NULL) {
- ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
- "layer displacement factor");
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
-}
-
-static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float val[3];
-
- if (vd.fno) {
- copy_v3_v3(val, vd.fno);
- }
- else {
- normal_short_to_float_v3(val, vd.no);
- }
-
- mul_v3_fl(val, fade * ss->cache->radius);
- mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
-}
-
int SCULPT_plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
{
return (!(brush->flag & BRUSH_PLANE_TRIM) ||
((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared)));
}
-static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip)
-{
- float d = plane_point_side_v3(plane, co);
- if (flip) {
- d = -d;
- }
- return d <= 0.0f;
-}
-
int SCULPT_plane_point_side(const float co[3], const float plane[4])
{
float d = plane_point_side_v3(plane, co);
@@ -4893,807 +2951,6 @@ float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss)
return rv;
}
-static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- float intr[3];
- float val[3];
-
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
-
- sub_v3_v3v3(val, intr, vd.co);
-
- if (SCULPT_plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
-
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
- float displace;
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Clay Brush
- * \{ */
-
-typedef struct ClaySampleData {
- float plane_dist[2];
-} ClaySampleData;
-
-static void calc_clay_surface_task_cb(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- ClaySampleData *csd = tls->userdata_chunk;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
- float plane[4];
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, brush->falloff_shape);
-
- /* Apply the brush normal radius to the test before sampling. */
- float test_radius = sqrtf(test.radius_squared);
- test_radius *= brush->normal_radius_factor;
- test.radius_squared = test_radius * test_radius;
- plane_from_point_normal_v3(plane, area_co, area_no);
-
- if (is_zero_v4(plane)) {
- return;
- }
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float plane_dist = dist_signed_to_plane_v3(vd.co, plane);
- float plane_dist_abs = fabsf(plane_dist);
- if (plane_dist > 0.0f) {
- csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs);
- }
- else {
- csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs);
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata),
- void *__restrict chunk_join,
- void *__restrict chunk)
-{
- ClaySampleData *join = chunk_join;
- ClaySampleData *csd = chunk;
- join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]);
- join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]);
-}
-
-static void do_clay_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = fabsf(ss->cache->bstrength);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
-
- sub_v3_v3v3(val, intr, vd.co);
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = fabsf(ss->cache->radius);
- const float initial_radius = fabsf(ss->cache->initial_radius);
- bool flip = ss->cache->bstrength < 0.0f;
-
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
- float displace;
-
- float area_no[3];
- float area_co[3];
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SculptThreadedTaskData sample_data = {
- .sd = NULL,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .totnode = totnode,
- .area_no = area_no,
- .area_co = ss->cache->location,
- };
-
- ClaySampleData csd = {{0}};
-
- TaskParallelSettings sample_settings;
- BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode);
- sample_settings.func_reduce = calc_clay_surface_reduce;
- sample_settings.userdata_chunk = &csd;
- sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
-
- BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
-
- float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
- d_offset = min_ff(radius, d_offset);
- d_offset = d_offset / radius;
- d_offset = 1.0f - d_offset;
- displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f)));
- if (flip) {
- displace = -displace;
- }
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- copy_v3_v3(area_co, ss->cache->location);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
-}
-
-static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*mat)[4] = data->mat;
- const float *area_no_sp = data->area_no_sp;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- SculptBrushTest test;
- float(*proxy)[3];
- const bool flip = (ss->cache->bstrength < 0.0f);
- const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SCULPT_brush_test_init(ss, &test);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
- continue;
- }
-
- if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
- /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- ss->cache->radius * test.dist,
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const bool flip = (ss->cache->bstrength < 0.0f);
- const float radius = flip ? -ss->cache->radius : ss->cache->radius;
- const float offset = SCULPT_brush_plane_offset_get(sd, ss);
- const float displace = radius * (0.18f + offset);
-
- /* The sculpt-plane normal (whatever its set to). */
- float area_no_sp[3];
-
- /* Geometry normal */
- float area_no[3];
- float area_co[3];
-
- float temp[3];
- float mat[4][4];
- float scale[4][4];
- float tmat[4][4];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
- SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor);
-
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
- }
- else {
- copy_v3_v3(area_no, area_no_sp);
- }
-
- /* Delay the first daub because grab delta is not setup. */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the
- * vertices. When in Add mode, vertices that are below the plane and inside the cube are move
- * towards the plane. In this situation, there may be cases where a vertex is outside the cube
- * but below the plane, so won't be deformed, causing artifacts. In order to prevent these
- * artifacts, this displaces the test cube space in relation to the plane in order to
- * deform more vertices that may be below it. */
- /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set
- * by doing multiple tests using the default "Clay Strips" brush preset. */
- float area_co_displaced[3];
- madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f);
-
- /* Initialize brush local-space matrix. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], area_co_displaced);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- /* Scale brush local space matrix. */
- scale_m4_fl(scale, ss->cache->radius);
- mul_m4_m4m4(tmat, mat, scale);
-
- /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in
- * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices
- * during big deformation while keeping the surface as uniform as possible. */
- mul_v3_fl(tmat[2], 1.25f);
-
- invert_m4_m4(mat, tmat);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no_sp = area_no_sp,
- .area_co = area_co,
- .mat = mat,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
-}
-
-static void do_fill_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
-
- float displace;
-
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
-}
-
-static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- if (SCULPT_plane_point_side(vd.co, test.plane_tool)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
-
- float displace;
-
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = -radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Clay Thumb Brush
- * \{ */
-
-static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*mat)[4] = data->mat;
- const float *area_no_sp = data->area_no_sp;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = data->clay_strength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- float plane_tilt[4];
- float normal_tilt[3];
- float imat[4][4];
-
- invert_m4_m4(imat, mat);
- rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle));
-
- /* Plane aligned to the geometry normal (back part of the brush). */
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
- /* Tilted plane (front part of the brush). */
- plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- float local_co[3];
- mul_v3_m4v3(local_co, mat, vd.co);
- float intr[3], intr_tilt[3];
- float val[3];
-
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co);
-
- /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex
- * coordinates. */
- /* We can also control the mix with a curve if it produces noticeable artifacts in the center
- * of the brush. */
- const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f;
- interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix);
- sub_v3_v3v3(val, intr_tilt, vd.co);
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static float sculpt_clay_thumb_get_stabilized_pressure(StrokeCache *cache)
-{
- float final_pressure = 0.0f;
- for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
- final_pressure += cache->clay_pressure_stabilizer[i];
- }
- return final_pressure / SCULPT_CLAY_STABILIZER_LEN;
-}
-
-static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
- const float offset = SCULPT_brush_plane_offset_get(sd, ss);
- const float displace = radius * (0.25f + offset);
-
- /* Sampled geometry normal and area center. */
- float area_no_sp[3];
- float area_no[3];
- float area_co[3];
-
- float temp[3];
- float mat[4][4];
- float scale[4][4];
- float tmat[4][4];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
-
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
- }
- else {
- copy_v3_v3(area_no, area_no_sp);
- }
-
- /* Delay the first daub because grab delta is not setup. */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- ss->cache->clay_thumb_front_angle = 0.0f;
- return;
- }
-
- /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the
- * stroke. */
- if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) {
- ss->cache->clay_thumb_front_angle += 0.8f;
- ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f);
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- /* Displace the brush planes. */
- copy_v3_v3(area_co, ss->cache->location);
- mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- /* Initialize brush local-space matrix. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], ss->cache->location);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- /* Scale brush local space matrix. */
- scale_m4_fl(scale, ss->cache->radius);
- mul_m4_m4m4(tmat, mat, scale);
- invert_m4_m4(mat, tmat);
-
- float clay_strength = ss->cache->bstrength *
- sculpt_clay_thumb_get_stabilized_pressure(ss->cache);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no_sp = area_no_sp,
- .area_co = ss->cache->location,
- .mat = mat,
- .clay_strength = clay_strength,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -5773,7 +3030,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Sculpt Prush Utilities
+/** \name Sculpt Brush Utilities
* \{ */
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
@@ -5980,14 +3237,22 @@ 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. */
+ /* 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)) {
+ /* Initialize auto-masking cache. */
if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob);
}
+ /* Initialize surface smooth cache. */
+ if ((brush->sculpt_tool == SCULPT_TOOL_SMOOTH) &&
+ (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE)) {
+ BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL);
+ ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
+ sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b");
+ }
}
}
@@ -6036,7 +3301,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* Apply one type of brush action. */
switch (brush->sculpt_tool) {
case SCULPT_TOOL_DRAW:
- do_draw_brush(sd, ob, nodes, totnode);
+ SCULPT_do_draw_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SMOOTH:
if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_LAPLACIAN) {
@@ -6047,80 +3312,80 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
break;
case SCULPT_TOOL_CREASE:
- do_crease_brush(sd, ob, nodes, totnode);
+ SCULPT_do_crease_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_BLOB:
- do_crease_brush(sd, ob, nodes, totnode);
+ SCULPT_do_crease_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_PINCH:
- do_pinch_brush(sd, ob, nodes, totnode);
+ SCULPT_do_pinch_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_INFLATE:
- do_inflate_brush(sd, ob, nodes, totnode);
+ SCULPT_do_inflate_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_GRAB:
- do_grab_brush(sd, ob, nodes, totnode);
+ SCULPT_do_grab_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ROTATE:
- do_rotate_brush(sd, ob, nodes, totnode);
+ SCULPT_do_rotate_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SNAKE_HOOK:
- do_snake_hook_brush(sd, ob, nodes, totnode);
+ SCULPT_do_snake_hook_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_NUDGE:
- do_nudge_brush(sd, ob, nodes, totnode);
+ SCULPT_do_nudge_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_THUMB:
- do_thumb_brush(sd, ob, nodes, totnode);
+ SCULPT_do_thumb_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_LAYER:
- do_layer_brush(sd, ob, nodes, totnode);
+ SCULPT_do_layer_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FLATTEN:
- do_flatten_brush(sd, ob, nodes, totnode);
+ SCULPT_do_flatten_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY:
- do_clay_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY_STRIPS:
- do_clay_strips_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_strips_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_MULTIPLANE_SCRAPE:
SCULPT_do_multiplane_scrape_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY_THUMB:
- do_clay_thumb_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_thumb_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FILL:
if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
- do_scrape_brush(sd, ob, nodes, totnode);
+ SCULPT_do_scrape_brush(sd, ob, nodes, totnode);
}
else {
- do_fill_brush(sd, ob, nodes, totnode);
+ SCULPT_do_fill_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_SCRAPE:
if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
- do_fill_brush(sd, ob, nodes, totnode);
+ SCULPT_do_fill_brush(sd, ob, nodes, totnode);
}
else {
- do_scrape_brush(sd, ob, nodes, totnode);
+ SCULPT_do_scrape_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_MASK:
- do_mask_brush(sd, ob, nodes, totnode);
+ SCULPT_do_mask_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_POSE:
SCULPT_do_pose_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DRAW_SHARP:
- do_draw_sharp_brush(sd, ob, nodes, totnode);
+ SCULPT_do_draw_sharp_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ELASTIC_DEFORM:
- do_elastic_deform_brush(sd, ob, nodes, totnode);
+ SCULPT_do_elastic_deform_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SLIDE_RELAX:
- do_slide_relax_brush(sd, ob, nodes, totnode);
+ SCULPT_do_slide_relax_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_BOUNDARY:
SCULPT_do_boundary_brush(sd, ob, nodes, totnode);
@@ -6132,10 +3397,10 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DISPLACEMENT_ERASER:
- do_displacement_eraser_brush(sd, ob, nodes, totnode);
+ SCULPT_do_displacement_eraser_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DISPLACEMENT_SMEAR:
- do_displacement_smear_brush(sd, ob, nodes, totnode);
+ SCULPT_do_displacement_smear_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_PAINT:
SCULPT_do_paint_brush(sd, ob, nodes, totnode);
@@ -6157,7 +3422,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
if (sculpt_brush_use_topology_rake(ss, brush)) {
- bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
+ SCULPT_bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
}
/* The cloth brush adds the gravity as a regular force and it is processed in the solver. */
@@ -6386,11 +3651,6 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
}
MEM_SAFE_FREE(nodes);
-
- /* Modifiers could depend on mesh normals, so we should update them.
- * NOTE: then if sculpting happens on locked key, normals should be re-calculate after applying
- * coords from key-block on base mesh. */
- BKE_mesh_calc_normals(me);
}
else if (ss->shapekey_active) {
sculpt_update_keyblock(ob);
@@ -6701,8 +3961,7 @@ static const char *sculpt_tool_name(Sculpt *sd)
return "Sculpting";
}
-/**
- * Operator for applying a stroke (various attributes including mouse path)
+/* Operator for applying a stroke (various attributes including mouse path)
* using the current brush. */
void SCULPT_cache_free(StrokeCache *cache)
@@ -6737,6 +3996,8 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
{
ModifierData *md;
+ unit_m4(ss->cache->clip_mirror_mtx);
+
for (md = ob->modifiers.first; md; md = md->next) {
if (!(md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime))) {
continue;
@@ -6758,6 +4019,73 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
if (mmd->tolerance > ss->cache->clip_tolerance[i]) {
ss->cache->clip_tolerance[i] = mmd->tolerance;
}
+
+ /* Store matrix for mirror object clipping. */
+ if (mmd->mirror_ob) {
+ float imtx_mirror_ob[4][4];
+ invert_m4_m4(imtx_mirror_ob, mmd->mirror_ob->obmat);
+ mul_m4_m4m4(ss->cache->clip_mirror_mtx, imtx_mirror_ob, ob->obmat);
+ }
+ }
+ }
+}
+
+static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = paint->brush;
+
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ cache->saved_mask_brush_tool = brush->mask_tool;
+ brush->mask_tool = BRUSH_MASK_SMOOTH;
+ }
+ else if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_SLIDE_RELAX,
+ SCULPT_TOOL_DRAW_FACE_SETS,
+ SCULPT_TOOL_PAINT,
+ SCULPT_TOOL_SMEAR)) {
+ /* Do nothing, this tool has its own smooth mode. */
+ }
+ else {
+ int cur_brush_size = BKE_brush_size_get(scene, brush);
+
+ BLI_strncpy(cache->saved_active_brush_name,
+ brush->id.name + 2,
+ sizeof(cache->saved_active_brush_name));
+
+ /* Switch to the smooth brush. */
+ brush = BKE_paint_toolslots_brush_get(paint, SCULPT_TOOL_SMOOTH);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
+ cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
+ BKE_brush_size_set(scene, brush, cur_brush_size);
+ BKE_curvemapping_init(brush->curve);
+ }
+ }
+}
+
+static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Brush *brush = BKE_paint_brush(paint);
+
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ brush->mask_tool = cache->saved_mask_brush_tool;
+ }
+ else if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_SLIDE_RELAX,
+ SCULPT_TOOL_DRAW_FACE_SETS,
+ SCULPT_TOOL_PAINT,
+ SCULPT_TOOL_SMEAR)) {
+ /* Do nothing. */
+ }
+ else {
+ /* Try to switch back to the saved/previous brush. */
+ BKE_brush_size_set(scene, brush, cache->saved_smooth_size);
+ brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, cache->saved_active_brush_name);
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
}
}
}
@@ -6767,8 +4095,6 @@ static void sculpt_update_cache_invariants(
bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Brush *brush = BKE_paint_brush(&sd->paint);
ViewContext *vc = paint_stroke_view_context(op->customdata);
@@ -6833,35 +4159,9 @@ static void sculpt_update_cache_invariants(
/* Alt-Smooth. */
if (cache->alt_smooth) {
- if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- cache->saved_mask_brush_tool = brush->mask_tool;
- brush->mask_tool = BRUSH_MASK_SMOOTH;
- }
- else if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_SLIDE_RELAX,
- SCULPT_TOOL_DRAW_FACE_SETS,
- SCULPT_TOOL_PAINT,
- SCULPT_TOOL_SMEAR)) {
- /* Do nothing, this tool has its own smooth mode. */
- }
- else {
- Paint *p = &sd->paint;
- Brush *br;
- int size = BKE_brush_size_get(scene, brush);
-
- BLI_strncpy(cache->saved_active_brush_name,
- brush->id.name + 2,
- sizeof(cache->saved_active_brush_name));
-
- br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Smooth");
- if (br) {
- BKE_paint_brush_set(p, br);
- brush = br;
- cache->saved_smooth_size = BKE_brush_size_get(scene, brush);
- BKE_brush_size_set(scene, brush, size);
- BKE_curvemapping_init(brush->curve);
- }
- }
+ smooth_brush_toggle_on(C, &sd->paint, cache);
+ /* Refresh the brush pointer in case we switched brush in the toggle function. */
+ brush = BKE_paint_brush(&sd->paint);
}
copy_v2_v2(cache->mouse, cache->initial_mouse);
@@ -6869,9 +4169,7 @@ static void sculpt_update_cache_invariants(
copy_v2_v2(ups->tex_mouse, cache->initial_mouse);
/* Truly temporary data that isn't stored in properties. */
-
cache->vc = vc;
-
cache->brush = brush;
/* Cache projection matrix. */
@@ -6946,7 +4244,7 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
case SCULPT_TOOL_CLAY_STRIPS:
return max_ff(initial_size * 0.30f, initial_size * powf(cache->pressure, 1.5f));
case SCULPT_TOOL_CLAY_THUMB: {
- float clay_stabilized_pressure = sculpt_clay_thumb_get_stabilized_pressure(cache);
+ float clay_stabilized_pressure = SCULPT_clay_thumb_get_stabilized_pressure(cache);
return initial_size * clay_stabilized_pressure;
}
default:
@@ -7989,9 +5287,7 @@ static void sculpt_brush_exit_tex(Sculpt *sd)
static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke))
{
- Main *bmain = CTX_data_main(C);
Object *ob = CTX_data_active_object(C);
- Scene *scene = CTX_data_scene(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -8009,23 +5305,9 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
/* Alt-Smooth. */
if (ss->cache->alt_smooth) {
- if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- brush->mask_tool = ss->cache->saved_mask_brush_tool;
- }
- else if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_SLIDE_RELAX,
- SCULPT_TOOL_DRAW_FACE_SETS,
- SCULPT_TOOL_PAINT,
- SCULPT_TOOL_SMEAR)) {
- /* Do nothing. */
- }
- else {
- BKE_brush_size_set(scene, brush, ss->cache->saved_smooth_size);
- brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, ss->cache->saved_active_brush_name);
- if (brush) {
- BKE_paint_brush_set(&sd->paint, brush);
- }
- }
+ smooth_brush_toggle_off(C, &sd->paint, ss->cache);
+ /* Refresh the brush pointer in case we switched brush in the toggle function. */
+ brush = BKE_paint_brush(&sd->paint);
}
if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
@@ -8131,7 +5413,7 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
sculpt_brush_exit_tex(sd);
}
-static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
+void SCULPT_OT_brush_stroke(wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Sculpt";
@@ -8159,677 +5441,6 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
"Clicks on the background do not start the stroke");
}
-/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */
-
-static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- if (!ss) {
- return OPERATOR_FINISHED;
- }
- SCULPT_vertex_random_access_ensure(ss);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
-
- MEM_SAFE_FREE(ss->persistent_base);
-
- const int totvert = SCULPT_vertex_count_get(ss);
- ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert,
- "layer persistent base");
-
- for (int i = 0; i < totvert; i++) {
- copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i));
- SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no);
- ss->persistent_base[i].disp = 0.0f;
- }
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Set Persistent Base";
- ot->idname = "SCULPT_OT_set_persistent_base";
- ot->description = "Reset the copy of the mesh that is being sculpted on";
-
- /* API callbacks. */
- ot->exec = sculpt_set_persistent_base_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/************************* SCULPT_OT_optimize *************************/
-
-static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- SCULPT_pbvh_clear(ob);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-/* The BVH gets less optimal more quickly with dynamic topology than
- * regular sculpting. There is no doubt more clever stuff we can do to
- * optimize it on the fly, but for now this gives the user a nicer way
- * to recalculate it than toggling modes. */
-static void SCULPT_OT_optimize(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Rebuild BVH";
- ot->idname = "SCULPT_OT_optimize";
- ot->description = "Recalculate the sculpt BVH to improve performance";
-
- /* API callbacks. */
- ot->exec = sculpt_optimize_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************* Dynamic topology symmetrize ********************/
-
-static bool sculpt_no_multires_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) {
- return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS;
- }
- return false;
-}
-
-static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_active_object(C);
- const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- SculptSession *ss = ob->sculpt;
- PBVH *pbvh = ss->pbvh;
- const float dist = RNA_float_get(op->ptr, "merge_tolerance");
-
- if (!pbvh) {
- return OPERATOR_CANCELLED;
- }
-
- switch (BKE_pbvh_type(pbvh)) {
- case PBVH_BMESH:
- /* Dyntopo Symmetrize. */
-
- /* To simplify undo for symmetrize, all BMesh elements are logged
- * as deleted, then after symmetrize operation all BMesh elements
- * are logged as added (as opposed to attempting to store just the
- * parts that symmetrize modifies). */
- SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize");
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
- BM_log_before_all_removed(ss->bm, ss->bm_log);
-
- BM_mesh_toolflags_set(ss->bm, true);
-
- /* Symmetrize and re-triangulate. */
- BMO_op_callf(ss->bm,
- (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
- "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b",
- sd->symmetrize_direction,
- dist,
- true);
- SCULPT_dynamic_topology_triangulate(ss->bm);
-
- /* Bisect operator flags edges (keep tags clean for edge queue). */
- BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
-
- BM_mesh_toolflags_set(ss->bm, false);
-
- /* Finish undo. */
- BM_log_all_added(ss->bm, ss->bm_log);
- SCULPT_undo_push_end();
-
- break;
- case PBVH_FACES:
- /* Mesh Symmetrize. */
- ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize");
- Mesh *mesh = ob->data;
-
- BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist);
-
- ED_sculpt_undo_geometry_end(ob);
- BKE_mesh_calc_normals(ob->data);
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
-
- break;
- case PBVH_GRIDS:
- return OPERATOR_CANCELLED;
- }
-
- /* Redraw. */
- SCULPT_pbvh_clear(ob);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_symmetrize(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Symmetrize";
- ot->idname = "SCULPT_OT_symmetrize";
- ot->description = "Symmetrize the topology modifications";
-
- /* API callbacks. */
- ot->exec = sculpt_symmetrize_exec;
- ot->poll = sculpt_no_multires_poll;
-
- RNA_def_float(ot->srna,
- "merge_tolerance",
- 0.001f,
- 0.0f,
- FLT_MAX,
- "Merge Distance",
- "Distance within which symmetrical vertices are merged",
- 0.0f,
- 1.0f);
-}
-
-/**** Toggle operator for turning sculpt mode on or off ****/
-
-static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
-{
- /* Create persistent sculpt mode data. */
- BKE_sculpt_toolsettings_data_ensure(scene);
-
- /* Create sculpt mode session data. */
- if (ob->sculpt != NULL) {
- BKE_sculptsession_free(ob);
- }
- ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- ob->sculpt->mode_type = OB_MODE_SCULPT;
-
- BKE_sculpt_ensure_orig_mesh_data(scene, ob);
-
- BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
-
- /* This function expects a fully evaluated depsgraph. */
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
-
- /* Here we can detect geometry that was just added to Sculpt Mode as it has the
- * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
- /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
- * initialized, which is used is some operators that modify the mesh topology to perform certain
- * actions in the new polys. After these operations are finished, all polys should have a valid
- * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility
- * correctly. */
- /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new
- * objects, like moving the transform pivot position to the new area or masking existing
- * geometry. */
- SculptSession *ss = ob->sculpt;
- const int new_face_set = SCULPT_face_set_next_available_get(ss);
- for (int i = 0; i < ss->totfaces; i++) {
- if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) {
- ss->face_sets[i] = new_face_set;
- }
- }
-}
-
-void ED_object_sculptmode_enter_ex(Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- const bool force_dyntopo,
- ReportList *reports)
-{
- const int mode_flag = OB_MODE_SCULPT;
- Mesh *me = BKE_mesh_from_object(ob);
-
- /* Enter sculpt mode. */
- ob->mode |= mode_flag;
-
- sculpt_init_session(bmain, depsgraph, scene, ob);
-
- if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f &&
- fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) {
- BKE_report(
- reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable");
- }
- else if (is_negative_m4(ob->obmat)) {
- BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable");
- }
-
- Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
- BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
-
- paint_cursor_start(paint, SCULPT_mode_poll_view3d);
-
- /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
- * As long as no data was added that is not supported. */
- if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
-
- const char *message_unsupported = NULL;
- if (me->totloop != me->totpoly * 3) {
- message_unsupported = TIP_("non-triangle face");
- }
- else if (mmd != NULL) {
- message_unsupported = TIP_("multi-res modifier");
- }
- else {
- enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
- if (flag == 0) {
- /* pass */
- }
- else if (flag & DYNTOPO_WARN_VDATA) {
- message_unsupported = TIP_("vertex data");
- }
- else if (flag & DYNTOPO_WARN_EDATA) {
- message_unsupported = TIP_("edge data");
- }
- else if (flag & DYNTOPO_WARN_LDATA) {
- message_unsupported = TIP_("face data");
- }
- else if (flag & DYNTOPO_WARN_MODIFIER) {
- message_unsupported = TIP_("constructive modifier");
- }
- else {
- BLI_assert(0);
- }
- }
-
- if ((message_unsupported == NULL) || force_dyntopo) {
- /* Needed because we may be entering this mode before the undo system loads. */
- wmWindowManager *wm = bmain->wm.first;
- bool has_undo = wm->undo_stack != NULL;
- /* Undo push is needed to prevent memory leak. */
- if (has_undo) {
- SCULPT_undo_push_begin(ob, "Dynamic topology enable");
- }
- SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
- if (has_undo) {
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
- SCULPT_undo_push_end();
- }
- }
- else {
- BKE_reportf(
- reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported);
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
- }
- }
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports);
-}
-
-void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
-{
- const int mode_flag = OB_MODE_SCULPT;
- Mesh *me = BKE_mesh_from_object(ob);
-
- multires_flush_sculpt_updates(ob);
-
- /* Not needed for now. */
-#if 0
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
-#endif
-
- /* Always for now, so leaving sculpt mode always ensures scene is in
- * a consistent state. */
- if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
- /* Dynamic topology must be disabled before exiting sculpt
- * mode to ensure the undo stack stays in a consistent
- * state. */
- sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
-
- /* Store so we know to re-enable when entering sculpt mode. */
- me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
- }
-
- /* Leave sculpt mode. */
- ob->mode &= ~mode_flag;
-
- BKE_sculptsession_free(ob);
-
- paint_cursor_delete_textures();
-
- /* Never leave derived meshes behind. */
- BKE_object_free_derived_caches(ob);
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
-}
-
-static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
-{
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- const int mode_flag = OB_MODE_SCULPT;
- const bool is_mode_set = (ob->mode & mode_flag) != 0;
-
- if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
- return OPERATOR_CANCELLED;
- }
- }
-
- if (is_mode_set) {
- ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
- }
- else {
- if (depsgraph) {
- depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- }
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports);
- BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint);
-
- if (ob->mode & mode_flag) {
- Mesh *me = ob->data;
- /* Dyntopo adds its own undo step. */
- if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) {
- /* Without this the memfile undo step is used,
- * while it works it causes lag when undoing the first undo step, see T71564. */
- wmWindowManager *wm = CTX_wm_manager(C);
- if (wm->op_undo_depth <= 1) {
- SCULPT_undo_push_begin(ob, op->type->name);
- }
- }
- }
- }
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
-
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
-
- WM_toolsystem_update_from_context_view3d(C);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Sculpt Mode";
- ot->idname = "SCULPT_OT_sculptmode_toggle";
- ot->description = "Toggle sculpt mode in 3D view";
-
- /* API callbacks. */
- ot->exec = sculpt_mode_toggle_exec;
- ot->poll = ED_operator_object_active_editable_mesh;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
-
- ss->preview_vert_index_count = 0;
- int totpoints = 0;
-
- /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */
- if (!ss->pbvh) {
- return;
- }
-
- if (!ss->deform_modifiers_active) {
- return;
- }
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return;
- }
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
-
- if (!ss->pmap) {
- return;
- }
-
- float brush_co[3];
- copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));
-
- BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
-
- /* Assuming an average of 6 edges per vertex in a triangulated mesh. */
- const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
-
- if (ss->preview_vert_index_list == NULL) {
- ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
- }
-
- GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
- int active_v = SCULPT_active_vertex_get(ss);
- BLI_gsqueue_push(not_visited_vertices, &active_v);
-
- while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
- int from_v;
- BLI_gsqueue_pop(not_visited_vertices, &from_v);
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
- if (totpoints + (ni.size * 2) < max_preview_vertices) {
- int to_v = ni.index;
- ss->preview_vert_index_list[totpoints] = from_v;
- totpoints++;
- ss->preview_vert_index_list[totpoints] = to_v;
- totpoints++;
- if (BLI_BITMAP_TEST(visited_vertices, to_v)) {
- continue;
- }
- BLI_BITMAP_ENABLE(visited_vertices, to_v);
- const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
- if (len_squared_v3v3(brush_co, co) < radius * radius) {
- BLI_gsqueue_push(not_visited_vertices, &to_v);
- }
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
- }
-
- BLI_gsqueue_free(not_visited_vertices);
-
- MEM_freeN(visited_vertices);
-
- ss->preview_vert_index_count = totpoints;
-}
-
-static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- ID *data;
- data = ob->data;
- if (data && ID_IS_LINKED(data)) {
- return OPERATOR_CANCELLED;
- }
-
- if (ob->type != OB_MESH) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = ob->data;
-
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
- if (mloopcol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
-
- const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
- if (MPropCol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
-
- MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
- MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
-
- for (int i = 0; i < mesh->totpoly; i++) {
- MPoly *c_poly = &polys[i];
- for (int j = 0; j < c_poly->totloop; j++) {
- int loop_index = c_poly->loopstart + j;
- MLoop *c_loop = &loops[c_poly->loopstart + j];
- float srgb_color[4];
- linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color);
- loopcols[loop_index].r = (char)(srgb_color[0] * 255);
- loopcols[loop_index].g = (char)(srgb_color[1] * 255);
- loopcols[loop_index].b = (char)(srgb_color[2] * 255);
- loopcols[loop_index].a = (char)(srgb_color[3] * 255);
- }
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Sculpt Vertex Color to Vertex Color";
- ot->description = "Copy the Sculpt Vertex Color to a regular color layer";
- ot->idname = "SCULPT_OT_vertex_to_loop_colors";
-
- /* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
- ot->exec = vertex_to_loop_colors_exec;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- ID *data;
- data = ob->data;
- if (data && ID_IS_LINKED(data)) {
- return OPERATOR_CANCELLED;
- }
-
- if (ob->type != OB_MESH) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = ob->data;
-
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
- if (mloopcol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
-
- const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
- if (MPropCol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
-
- MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
- MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
-
- for (int i = 0; i < mesh->totpoly; i++) {
- MPoly *c_poly = &polys[i];
- for (int j = 0; j < c_poly->totloop; j++) {
- int loop_index = c_poly->loopstart + j;
- MLoop *c_loop = &loops[c_poly->loopstart + j];
- vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f);
- vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f);
- vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f);
- vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f);
- srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color);
- }
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Color to Sculpt Vertex Color";
- ot->description = "Copy the active loop color layer to the vertex color";
- ot->idname = "SCULPT_OT_loop_to_vertex_colors";
-
- /* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
- ot->exec = loop_to_vertex_colors_exec;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int sculpt_sample_color_invoke(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *UNUSED(e))
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
- int active_vertex = SCULPT_active_vertex_get(ss);
- const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex);
- if (!active_vertex_color) {
- return OPERATOR_CANCELLED;
- }
-
- float color_srgb[3];
- copy_v3_v3(color_srgb, active_vertex_color);
- IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
- BKE_brush_color_set(scene, brush, color_srgb);
-
- WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_sample_color(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Sample Color";
- ot->idname = "SCULPT_OT_sample_color";
- ot->description = "Sample the vertex color of the active vertex";
-
- /* api callbacks */
- ot->invoke = sculpt_sample_color_invoke;
- ot->poll = SCULPT_vertex_colors_poll;
-
- ot->flag = OPTYPE_REGISTER;
-}
-
/* Fake Neighbors. */
/* This allows the sculpt tools to work on meshes with multiple connected components as they had
* only one connected component. When initialized and enabled, the sculpt API will return extra
@@ -9105,356 +5716,10 @@ void SCULPT_fake_neighbors_free(Object *ob)
sculpt_pose_fake_neighbors_free(ss);
}
-/**
- * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the
- * mask based on the difference between two colors (the active color and the color of any other
- * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active
- * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer
- * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between
- * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going
- * to be.
- */
-#define MASK_BY_COLOR_SLOPE 0.25f
-
-static float sculpt_mask_by_color_delta_get(const float *color_a,
- const float *color_b,
- const float threshold,
- const bool invert)
-{
- float len = len_v3v3(color_a, color_b);
- /* Normalize len to the (0, 1) range. */
- len = len / M_SQRT3;
-
- if (len < threshold - MASK_BY_COLOR_SLOPE) {
- len = 1.0f;
- }
- else if (len >= threshold) {
- len = 0.0f;
- }
- else {
- len = (-len + threshold) / MASK_BY_COLOR_SLOPE;
- }
-
- if (invert) {
- return 1.0f - len;
- }
- return len;
-}
-
-static float sculpt_mask_by_color_final_mask_get(const float current_mask,
- const float new_mask,
- const bool invert,
- const bool preserve_mask)
-{
- if (preserve_mask) {
- if (invert) {
- return min_ff(current_mask, new_mask);
- }
- return max_ff(current_mask, new_mask);
- }
- return new_mask;
-}
-
-typedef struct MaskByColorContiguousFloodFillData {
- float threshold;
- bool invert;
- float *new_mask;
- float initial_color[3];
-} MaskByColorContiguousFloodFillData;
-
-static void do_mask_by_color_contiguous_update_nodes_cb(
- void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
- bool update_node = false;
-
- const bool invert = data->mask_by_color_invert;
- const bool preserve_mask = data->mask_by_color_preserve_mask;
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- const float current_mask = *vd.mask;
- const float new_mask = data->mask_by_color_floodfill[vd.index];
- *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
- if (current_mask == *vd.mask) {
- continue;
- }
- update_node = true;
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- if (update_node) {
- BKE_pbvh_node_mark_redraw(data->nodes[n]);
- }
-}
-
-static bool sculpt_mask_by_color_contiguous_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
-{
- MaskByColorContiguousFloodFillData *data = userdata;
- const float *current_color = SCULPT_vertex_color_get(ss, to_v);
- float new_vertex_mask = sculpt_mask_by_color_delta_get(
- current_color, data->initial_color, data->threshold, data->invert);
- data->new_mask[to_v] = new_vertex_mask;
-
- if (is_duplicate) {
- data->new_mask[to_v] = data->new_mask[from_v];
- }
-
- float len = len_v3v3(current_color, data->initial_color);
- len = len / M_SQRT3;
- return len <= data->threshold;
-}
-
-static void sculpt_mask_by_color_contiguous(Object *object,
- const int vertex,
- const float threshold,
- const bool invert,
- const bool preserve_mask)
-{
- SculptSession *ss = object->sculpt;
- const int totvert = SCULPT_vertex_count_get(ss);
-
- float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask");
-
- if (invert) {
- for (int i = 0; i < totvert; i++) {
- new_mask[i] = 1.0f;
- }
- }
-
- SculptFloodFill flood;
- SCULPT_floodfill_init(ss, &flood);
- SCULPT_floodfill_add_initial(&flood, vertex);
-
- MaskByColorContiguousFloodFillData ffd;
- ffd.threshold = threshold;
- ffd.invert = invert;
- ffd.new_mask = new_mask;
- copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex));
-
- SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd);
- SCULPT_floodfill_free(&flood);
-
- int totnode;
- PBVHNode **nodes;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- SculptThreadedTaskData data = {
- .ob = object,
- .nodes = nodes,
- .mask_by_color_floodfill = new_mask,
- .mask_by_color_vertex = vertex,
- .mask_by_color_threshold = threshold,
- .mask_by_color_invert = invert,
- .mask_by_color_preserve_mask = preserve_mask,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(
- 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings);
-
- MEM_SAFE_FREE(nodes);
-
- MEM_freeN(new_mask);
-}
-
-static void do_mask_by_color_task_cb(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
- bool update_node = false;
-
- const float threshold = data->mask_by_color_threshold;
- const bool invert = data->mask_by_color_invert;
- const bool preserve_mask = data->mask_by_color_preserve_mask;
- const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- const float current_mask = *vd.mask;
- const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert);
- *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
-
- if (current_mask == *vd.mask) {
- continue;
- }
- update_node = true;
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- if (update_node) {
- BKE_pbvh_node_mark_redraw(data->nodes[n]);
- }
-}
-
-static void sculpt_mask_by_color_full_mesh(Object *object,
- const int vertex,
- const float threshold,
- const bool invert,
- const bool preserve_mask)
-{
- SculptSession *ss = object->sculpt;
-
- int totnode;
- PBVHNode **nodes;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- SculptThreadedTaskData data = {
- .ob = object,
- .nodes = nodes,
- .mask_by_color_vertex = vertex,
- .mask_by_color_threshold = threshold,
- .mask_by_color_invert = invert,
- .mask_by_color_preserve_mask = preserve_mask,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings);
-
- MEM_SAFE_FREE(nodes);
-}
-
-static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
-
- /* Color data is not available in Multires. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- if (!ss->vcol) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_vertex_random_access_ensure(ss);
-
- /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
- * so it needs to be updated here. */
- SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
-
- SCULPT_undo_push_begin(ob, "Mask by color");
-
- const int active_vertex = SCULPT_active_vertex_get(ss);
- const float threshold = RNA_float_get(op->ptr, "threshold");
- const bool invert = RNA_boolean_get(op->ptr, "invert");
- const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
-
- if (RNA_boolean_get(op->ptr, "contiguous")) {
- sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask);
- }
- else {
- sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask);
- }
-
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
- SCULPT_undo_push_end();
-
- SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Mask by Color";
- ot->idname = "SCULPT_OT_mask_by_color";
- ot->description = "Creates a mask based on the sculpt vertex colors";
-
- /* api callbacks */
- ot->invoke = sculpt_mask_by_color_invoke;
- ot->poll = SCULPT_vertex_colors_poll;
-
- ot->flag = OPTYPE_REGISTER;
-
- ot->prop = RNA_def_boolean(
- ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas");
-
- ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask");
- ot->prop = RNA_def_boolean(
- ot->srna,
- "preserve_previous_mask",
- false,
- "Preserve Previous Mask",
- "Preserve the previous mask and add or subtract the new one generated by the colors");
-
- RNA_def_float(ot->srna,
- "threshold",
- 0.35f,
- 0.0f,
- 1.0f,
- "Threshold",
- "How much changes in color affect the mask generation",
- 0.0f,
- 1.0f);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
/** \name Operator Registration
* \{ */
-void ED_operatortypes_sculpt(void)
-{
- WM_operatortype_append(SCULPT_OT_brush_stroke);
- WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
- WM_operatortype_append(SCULPT_OT_set_persistent_base);
- WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
- WM_operatortype_append(SCULPT_OT_optimize);
- WM_operatortype_append(SCULPT_OT_symmetrize);
- WM_operatortype_append(SCULPT_OT_detail_flood_fill);
- WM_operatortype_append(SCULPT_OT_sample_detail_size);
- WM_operatortype_append(SCULPT_OT_set_detail_size);
- WM_operatortype_append(SCULPT_OT_mesh_filter);
- WM_operatortype_append(SCULPT_OT_mask_filter);
- WM_operatortype_append(SCULPT_OT_dirty_mask);
- WM_operatortype_append(SCULPT_OT_mask_expand);
- WM_operatortype_append(SCULPT_OT_set_pivot_position);
- WM_operatortype_append(SCULPT_OT_face_sets_create);
- WM_operatortype_append(SCULPT_OT_face_sets_change_visibility);
- WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
- WM_operatortype_append(SCULPT_OT_face_sets_init);
- WM_operatortype_append(SCULPT_OT_cloth_filter);
- WM_operatortype_append(SCULPT_OT_face_sets_edit);
- WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture);
- WM_operatortype_append(SCULPT_OT_face_set_box_gesture);
- WM_operatortype_append(SCULPT_OT_trim_box_gesture);
- WM_operatortype_append(SCULPT_OT_trim_lasso_gesture);
- WM_operatortype_append(SCULPT_OT_project_line_gesture);
-
- WM_operatortype_append(SCULPT_OT_sample_color);
- WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
- WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors);
- WM_operatortype_append(SCULPT_OT_color_filter);
- WM_operatortype_append(SCULPT_OT_mask_by_color);
- WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit);
- WM_operatortype_append(SCULPT_OT_mask_init);
-
- WM_operatortype_append(SCULPT_OT_expand);
-}
-
/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index e238fafb063..1e41c5cdbdf 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -772,12 +772,10 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
- float normal[3];
- normal_short_to_float_v3(normal, orig_data.no);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
- normal,
+ orig_data.no,
boundary->edit_info[vd.index].strength_factor * disp * mask * automask *
strength);
diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
new file mode 100644
index 00000000000..c2acc361a79
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
@@ -0,0 +1,2847 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ * Implements the Sculpt Mode tools
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dial_2d.h"
+#include "BLI_ghash.h"
+#include "BLI_gsqueue.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_math_color.h"
+#include "BLI_math_color_blend.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_kelvinlet.h"
+#include "BKE_key.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_mirror.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_pbvh.h"
+#include "BKE_pointcache.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subsurf.h"
+
+#include "DEG_depsgraph.h"
+
+#include "IMB_colormanagement.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* -------------------------------------------------------------------- */
+/** \name SculptProjectVector
+ *
+ * Fast-path for #project_plane_v3_v3v3
+ * \{ */
+
+typedef struct SculptProjectVector {
+ float plane[3];
+ float len_sq;
+ float len_sq_inv_neg;
+ bool is_valid;
+
+} SculptProjectVector;
+
+static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip)
+{
+ float d = plane_point_side_v3(plane, co);
+ if (flip) {
+ d = -d;
+ }
+ return d <= 0.0f;
+}
+
+/**
+ * \param plane: Direction, can be any length.
+ */
+static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3])
+{
+ copy_v3_v3(spvc->plane, plane);
+ spvc->len_sq = len_squared_v3(spvc->plane);
+ spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
+ spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
+}
+
+/**
+ * Calculate the projection.
+ */
+static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3])
+{
+#if 0
+ project_plane_v3_v3v3(r_vec, vec, spvc->plane);
+#else
+ /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
+ madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
+#endif
+}
+
+static void calc_sculpt_plane(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) &&
+ (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) ||
+ !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ switch (brush->sculpt_plane) {
+ case SCULPT_DISP_DIR_VIEW:
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
+ break;
+
+ case SCULPT_DISP_DIR_X:
+ ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f);
+ break;
+
+ case SCULPT_DISP_DIR_Y:
+ ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f);
+ break;
+
+ case SCULPT_DISP_DIR_Z:
+ ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f);
+ break;
+
+ case SCULPT_DISP_DIR_AREA:
+ SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
+ normalize_v3(r_area_no);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* For flatten center. */
+ /* Flatten center has not been calculated yet if we are not using the area normal. */
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
+ SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co);
+ }
+
+ /* For area normal. */
+ if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
+ (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+ }
+ else {
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ }
+
+ /* For flatten center. */
+ if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
+ (brush->flag & BRUSH_ORIGINAL_PLANE)) {
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+ }
+ else {
+ copy_v3_v3(ss->cache->last_center, r_area_co);
+ }
+ }
+ else {
+ /* For area normal. */
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+
+ /* For flatten center. */
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+
+ /* For area normal. */
+ flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
+
+ /* For flatten center. */
+ flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
+
+ /* For area normal. */
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
+
+ /* For flatten center. */
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
+
+ /* Shift the plane for the current tile. */
+ add_v3_v3(r_area_co, ss->cache->plane_offset);
+ }
+}
+
+static void sculpt_rake_rotate(const SculptSession *ss,
+ const float sculpt_co[3],
+ const float v_co[3],
+ float factor,
+ float r_delta[3])
+{
+ float vec_rot[3];
+
+#if 0
+ /* lerp */
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+ mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+ mul_v3_fl(r_delta, factor);
+#else
+ /* slerp */
+ float q_interp[4];
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+
+ copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
+ pow_qt_fl_normalized(q_interp, factor);
+ mul_qt_v3(q_interp, vec_rot);
+
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+#endif
+}
+
+/**
+ * Align the grab delta to the brush normal.
+ *
+ * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`.
+ */
+static void sculpt_project_v3_normal_align(SculptSession *ss,
+ const float normal_weight,
+ float grab_delta[3])
+{
+ /* Signed to support grabbing in (to make a hole) as well as out. */
+ const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
+
+ /* This scale effectively projects the offset so dragging follows the cursor,
+ * as the normal points towards the view, the scale increases. */
+ float len_view_scale;
+ {
+ float view_aligned_normal[3];
+ project_plane_v3_v3v3(
+ view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
+ len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
+ len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
+ }
+
+ mul_v3_fl(grab_delta, 1.0f - normal_weight);
+ madd_v3_v3fl(
+ grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Draw Brush
+ * \{ */
+
+static void do_draw_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ const float bstrength = ss->cache->bstrength;
+
+ /* Offset with as much as possible factored in already. */
+ float effective_normal[3];
+ SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
+ mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping. */
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+static void do_fill_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+
+ float displace;
+
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
+}
+
+static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ if (SCULPT_plane_point_side(vd.co, test.plane_tool)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+
+ float displace;
+
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = -radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Clay Thumb Brush
+ * \{ */
+
+static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = data->clay_strength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ float plane_tilt[4];
+ float normal_tilt[3];
+ float imat[4][4];
+
+ invert_m4_m4(imat, mat);
+ rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle));
+
+ /* Plane aligned to the geometry normal (back part of the brush). */
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ /* Tilted plane (front part of the brush). */
+ plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ float local_co[3];
+ mul_v3_m4v3(local_co, mat, vd.co);
+ float intr[3], intr_tilt[3];
+ float val[3];
+
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co);
+
+ /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex
+ * coordinates. */
+ /* We can also control the mix with a curve if it produces noticeable artifacts in the center
+ * of the brush. */
+ const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f;
+ interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix);
+ sub_v3_v3v3(val, intr_tilt, vd.co);
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+float SCULPT_clay_thumb_get_stabilized_pressure(StrokeCache *cache)
+{
+ float final_pressure = 0.0f;
+ for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
+ final_pressure += cache->clay_pressure_stabilizer[i];
+ }
+ return final_pressure / SCULPT_CLAY_STABILIZER_LEN;
+}
+
+void SCULPT_do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+ const float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ const float displace = radius * (0.25f + offset);
+
+ /* Sampled geometry normal and area center. */
+ float area_no_sp[3];
+ float area_no[3];
+ float area_co[3];
+
+ float temp[3];
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
+
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
+ }
+ else {
+ copy_v3_v3(area_no, area_no_sp);
+ }
+
+ /* Delay the first daub because grab delta is not setup. */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ ss->cache->clay_thumb_front_angle = 0.0f;
+ return;
+ }
+
+ /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the
+ * stroke. */
+ if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) {
+ ss->cache->clay_thumb_front_angle += 0.8f;
+ ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f);
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ /* Displace the brush planes. */
+ copy_v3_v3(area_co, ss->cache->location);
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ /* Initialize brush local-space matrix. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], ss->cache->location);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ /* Scale brush local space matrix. */
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, mat, scale);
+ invert_m4_m4(mat, tmat);
+
+ float clay_strength = ss->cache->bstrength *
+ SCULPT_clay_thumb_get_stabilized_pressure(ss->cache);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no_sp = area_no_sp,
+ .area_co = ss->cache->location,
+ .mat = mat,
+ .clay_strength = clay_strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ float intr[3];
+ float val[3];
+
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (SCULPT_plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ float displace;
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Clay Brush
+ * \{ */
+
+typedef struct ClaySampleData {
+ float plane_dist[2];
+} ClaySampleData;
+
+static void calc_clay_surface_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ ClaySampleData *csd = tls->userdata_chunk;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+ float plane[4];
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, brush->falloff_shape);
+
+ /* Apply the brush normal radius to the test before sampling. */
+ float test_radius = sqrtf(test.radius_squared);
+ test_radius *= brush->normal_radius_factor;
+ test.radius_squared = test_radius * test_radius;
+ plane_from_point_normal_v3(plane, area_co, area_no);
+
+ if (is_zero_v4(plane)) {
+ return;
+ }
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float plane_dist = dist_signed_to_plane_v3(vd.co, plane);
+ float plane_dist_abs = fabsf(plane_dist);
+ if (plane_dist > 0.0f) {
+ csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs);
+ }
+ else {
+ csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs);
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ ClaySampleData *join = chunk_join;
+ ClaySampleData *csd = chunk;
+ join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]);
+ join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]);
+}
+
+static void do_clay_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = fabsf(ss->cache->bstrength);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = fabsf(ss->cache->radius);
+ const float initial_radius = fabsf(ss->cache->initial_radius);
+ bool flip = ss->cache->bstrength < 0.0f;
+
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ float displace;
+
+ float area_no[3];
+ float area_co[3];
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SculptThreadedTaskData sample_data = {
+ .sd = NULL,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .totnode = totnode,
+ .area_no = area_no,
+ .area_co = ss->cache->location,
+ };
+
+ ClaySampleData csd = {{0}};
+
+ TaskParallelSettings sample_settings;
+ BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode);
+ sample_settings.func_reduce = calc_clay_surface_reduce;
+ sample_settings.userdata_chunk = &csd;
+ sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
+
+ BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
+
+ float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
+ d_offset = min_ff(radius, d_offset);
+ d_offset = d_offset / radius;
+ d_offset = 1.0f - d_offset;
+ displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f)));
+ if (flip) {
+ displace = -displace;
+ }
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ copy_v3_v3(area_co, ss->cache->location);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
+}
+
+static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float(*proxy)[3];
+ const bool flip = (ss->cache->bstrength < 0.0f);
+ const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SCULPT_brush_test_init(ss, &test);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
+ continue;
+ }
+
+ if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+ /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ ss->cache->radius * test.dist,
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const bool flip = (ss->cache->bstrength < 0.0f);
+ const float radius = flip ? -ss->cache->radius : ss->cache->radius;
+ const float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ const float displace = radius * (0.18f + offset);
+
+ /* The sculpt-plane normal (whatever its set to). */
+ float area_no_sp[3];
+
+ /* Geometry normal */
+ float area_no[3];
+ float area_co[3];
+
+ float temp[3];
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
+ SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor);
+
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
+ }
+ else {
+ copy_v3_v3(area_no, area_no_sp);
+ }
+
+ /* Delay the first daub because grab delta is not setup. */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the
+ * vertices. When in Add mode, vertices that are below the plane and inside the cube are move
+ * towards the plane. In this situation, there may be cases where a vertex is outside the cube
+ * but below the plane, so won't be deformed, causing artifacts. In order to prevent these
+ * artifacts, this displaces the test cube space in relation to the plane in order to
+ * deform more vertices that may be below it. */
+ /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set
+ * by doing multiple tests using the default "Clay Strips" brush preset. */
+ float area_co_displaced[3];
+ madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f);
+
+ /* Initialize brush local-space matrix. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], area_co_displaced);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ /* Scale brush local space matrix. */
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, mat, scale);
+
+ /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in
+ * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices
+ * during big deformation while keeping the surface as uniform as possible. */
+ mul_v3_fl(tmat[2], 1.25f);
+
+ invert_m4_m4(mat, tmat);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no_sp = area_no_sp,
+ .area_co = area_co,
+ .mat = mat,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
+}
+
+static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float *grab_delta = data->grab_delta;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+ const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
+ const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
+ const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) *
+ (len_v3(grab_delta) / ss->cache->radius)) :
+ 0.0f;
+
+ const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ KelvinletParams params;
+ BKE_kelvinlet_init_params(&params, ss->cache->radius, bstrength, 1.0f, 0.4f);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float fade;
+ if (do_elastic) {
+ fade = 1.0f;
+ }
+ else {
+ fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ }
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ /* Negative pinch will inflate, helps maintain volume. */
+ if (do_pinch) {
+ float delta_pinch_init[3], delta_pinch[3];
+
+ sub_v3_v3v3(delta_pinch, vd.co, test.location);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal);
+ }
+
+ /* Important to calculate based on the grabbed location
+ * (intentionally ignore fade here). */
+ add_v3_v3(delta_pinch, grab_delta);
+
+ sculpt_project_v3(spvc, delta_pinch, delta_pinch);
+
+ copy_v3_v3(delta_pinch_init, delta_pinch);
+
+ float pinch_fade = pinch * fade;
+ /* When reducing, scale reduction back by how close to the center we are,
+ * so we don't pinch into nothingness. */
+ if (pinch > 0.0f) {
+ /* Square to have even less impact for close vertices. */
+ pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
+ }
+ mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
+ sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
+ add_v3_v3(proxy[vd.i], delta_pinch);
+ }
+
+ if (do_rake_rotation) {
+ float delta_rotate[3];
+ sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
+ add_v3_v3(proxy[vd.i], delta_rotate);
+ }
+
+ if (do_elastic) {
+ float disp[3];
+ BKE_kelvinlet_grab_triscale(disp, &params, vd.co, ss->cache->location, proxy[vd.i]);
+ mul_v3_fl(disp, bstrength * 20.0f);
+ if (vd.mask) {
+ mul_v3_fl(disp, 1.0f - *vd.mask);
+ }
+ mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+ copy_v3_v3(proxy[vd.i], disp);
+ }
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const float bstrength = ss->cache->bstrength;
+ float grab_delta[3];
+
+ SculptProjectVector spvc;
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (bstrength < 0.0f) {
+ negate_v3(grab_delta);
+ }
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ /* Optionally pinch while painting. */
+ if (brush->crease_pinch_factor != 0.5f) {
+ sculpt_project_v3_cache_init(&spvc, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .spvc = &spvc,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
+}
+
+static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *cono = data->cono;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+ float tmp[3], cono[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
+ cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .cono = cono,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
+}
+
+static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float angle = data->angle;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ float vec[3], rot[3][3];
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
+ axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
+ mul_v3_m3v3(proxy[vd.i], rot, vec);
+ add_v3_v3(proxy[vd.i], ss->cache->location);
+ sub_v3_v3(proxy[vd.i], orig_data.co);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1};
+ const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .angle = angle,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
+}
+
+static void do_layer_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+
+ const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ const float bstrength = ss->cache->bstrength;
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ const int vi = vd.index;
+ float *disp_factor;
+ if (use_persistent_base) {
+ disp_factor = &ss->persistent_base[vi].disp;
+ }
+ else {
+ disp_factor = &ss->cache->layer_displacement_factor[vi];
+ }
+
+ /* When using persistent base, the layer brush (holding Control) invert mode resets the
+ * height of the layer to 0. This makes possible to clean edges of previously added layers
+ * on top of the base. */
+ /* The main direction of the layers is inverted using the regular brush strength with the
+ * brush direction property. */
+ if (use_persistent_base && ss->cache->invert) {
+ (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) *
+ ((*disp_factor) > 0.0f ? -1.0f : 1.0f);
+ }
+ else {
+ (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor));
+ }
+ if (vd.mask) {
+ const float clamp_mask = 1.0f - *vd.mask;
+ *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask);
+ }
+ else {
+ *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f);
+ }
+
+ float final_co[3];
+ float normal[3];
+
+ if (use_persistent_base) {
+ SCULPT_vertex_persistent_normal_get(ss, vi, normal);
+ mul_v3_fl(normal, brush->height);
+ madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor);
+ }
+ else {
+ copy_v3_v3(normal, orig_data.no);
+ mul_v3_fl(normal, brush->height);
+ madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
+ }
+
+ float vdisp[3];
+ sub_v3_v3v3(vdisp, final_co, vd.co);
+ mul_v3_fl(vdisp, fabsf(fade));
+ add_v3_v3v3(final_co, vd.co, vdisp);
+
+ SCULPT_clip(sd, ss, vd.co, final_co);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (ss->cache->layer_displacement_factor == NULL) {
+ ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
+ "layer displacement factor");
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
+}
+
+static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float val[3];
+
+ if (vd.fno) {
+ copy_v3_v3(val, vd.fno);
+ }
+ else {
+ copy_v3_v3(val, vd.no);
+ }
+
+ mul_v3_fl(val, fade * ss->cache->radius);
+ mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
+}
+
+static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *cono = data->cono;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+ float tmp[3], cono[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
+ cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .cono = cono,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Crease & Blob Brush
+ * \{ */
+
+/**
+ * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
+ */
+static void do_crease_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float flippedbstrength = data->flippedbstrength;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float val1[3];
+ float val2[3];
+
+ /* First we pinch. */
+ sub_v3_v3v3(val1, test.location, vd.co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(val1, val1, ss->cache->view_normal);
+ }
+
+ mul_v3_fl(val1, fade * flippedbstrength);
+
+ sculpt_project_v3(spvc, val1, val1);
+
+ /* Then we draw. */
+ mul_v3_v3fl(val2, offset, fade);
+
+ add_v3_v3v3(proxy[vd.i], val1, val2);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ const Scene *scene = ss->cache->vc->scene;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ float bstrength = ss->cache->bstrength;
+ float flippedbstrength, crease_correction;
+ float brush_alpha;
+
+ SculptProjectVector spvc;
+
+ /* Offset with as much as possible factored in already. */
+ mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* We divide out the squared alpha and multiply by the squared crease
+ * to give us the pinch strength. */
+ crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor;
+ brush_alpha = BKE_brush_alpha_get(scene, brush);
+ if (brush_alpha > 0.0f) {
+ crease_correction /= brush_alpha * brush_alpha;
+ }
+
+ /* We always want crease to pinch or blob to relax even when draw is negative. */
+ flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength :
+ crease_correction * bstrength;
+
+ if (brush->sculpt_tool == SCULPT_TOOL_BLOB) {
+ flippedbstrength *= -1.0f;
+ }
+
+ /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single
+ * point. Without this we get a 'flat' surface surrounding the pinch. */
+ sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .spvc = &spvc,
+ .offset = offset,
+ .flippedbstrength = flippedbstrength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
+}
+
+static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*stroke_xz)[3] = data->stroke_xz;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ float x_object_space[3];
+ float z_object_space[3];
+ copy_v3_v3(x_object_space, stroke_xz[0]);
+ copy_v3_v3(z_object_space, stroke_xz[1]);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float disp_center[3];
+ float x_disp[3];
+ float z_disp[3];
+ /* Calculate displacement from the vertex to the brush center. */
+ sub_v3_v3v3(disp_center, test.location, vd.co);
+
+ /* Project the displacement into the X vector (aligned to the stroke). */
+ mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space));
+
+ /* Project the displacement into the Z vector (aligned to the surface normal). */
+ mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space));
+
+ /* Add the two projected vectors to calculate the final displacement.
+ * The Y component is removed. */
+ add_v3_v3v3(disp_center, x_disp, z_disp);
+
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal);
+ }
+ mul_v3_v3fl(proxy[vd.i], disp_center, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ float area_no[3];
+ float area_co[3];
+
+ float mat[4][4];
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ /* delay the first daub because grab delta is not setup */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ /* Initialize `mat`. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], ss->cache->location);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ float stroke_xz[2][3];
+ normalize_v3_v3(stroke_xz[0], mat[0]);
+ normalize_v3_v3(stroke_xz[1], mat[2]);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .stroke_xz = stroke_xz,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
+}
+
+static void do_grab_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ if (grab_silhouette) {
+ float silhouette_test_dir[3];
+ normalize_v3_v3(silhouette_test_dir, grab_delta);
+ if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) {
+ mul_v3_fl(silhouette_test_dir, -1.0f);
+ }
+ float vno[3];
+ copy_v3_v3(vno, orig_data.no);
+ fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f);
+ }
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
+}
+
+static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
+ const float *location = ss->cache->location;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ float dir;
+ if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
+ dir = 1.0f;
+ }
+ else {
+ dir = -1.0f;
+ }
+
+ if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
+ int symm = ss->cache->mirror_symmetry_pass;
+ if (ELEM(symm, 1, 2, 4, 7)) {
+ dir = -dir;
+ }
+ }
+
+ KelvinletParams params;
+ float force = len_v3(grab_delta) * dir * bstrength;
+ BKE_kelvinlet_init_params(
+ &params, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float final_disp[3];
+ switch (brush->elastic_deform_type) {
+ case BRUSH_ELASTIC_DEFORM_GRAB:
+ BKE_kelvinlet_grab(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: {
+ BKE_kelvinlet_grab_biscale(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: {
+ BKE_kelvinlet_grab_triscale(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_SCALE:
+ BKE_kelvinlet_scale(
+ final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
+ break;
+ case BRUSH_ELASTIC_DEFORM_TWIST:
+ BKE_kelvinlet_twist(
+ final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
+ break;
+ }
+
+ if (vd.mask) {
+ mul_v3_fl(final_disp, 1.0f - *vd.mask);
+ }
+
+ mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+
+ copy_v3_v3(proxy[vd.i], final_disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+}
+/** \} */
+
+static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ const float bstrength = ss->cache->bstrength;
+
+ /* Offset with as much as possible factored in already. */
+ float effective_normal[3];
+ SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
+ mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping. */
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Topology Brush
+ * \{ */
+
+static void do_topology_slide_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float current_disp[3];
+ float current_disp_norm[3];
+ float final_disp[3] = {0.0f, 0.0f, 0.0f};
+
+ switch (brush->slide_deform_type) {
+ case BRUSH_SLIDE_DEFORM_DRAG:
+ sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ break;
+ case BRUSH_SLIDE_DEFORM_PINCH:
+ sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+ break;
+ case BRUSH_SLIDE_DEFORM_EXPAND:
+ sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+ break;
+ }
+
+ normalize_v3_v3(current_disp_norm, current_disp);
+ mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vertex_disp[3];
+ float vertex_disp_norm[3];
+ sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
+ normalize_v3_v3(vertex_disp_norm, vertex_disp);
+ if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) {
+ madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ mul_v3_v3fl(proxy[vd.i], final_disp, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_relax_vertex(SculptSession *ss,
+ PBVHVertexIter *vd,
+ float factor,
+ bool filter_boundary_face_sets,
+ float *r_final_pos)
+{
+ float smooth_pos[3];
+ float final_disp[3];
+ float boundary_normal[3];
+ int avg_count = 0;
+ int neighbor_count = 0;
+ zero_v3(smooth_pos);
+ zero_v3(boundary_normal);
+ const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index);
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
+ neighbor_count++;
+ if (!filter_boundary_face_sets ||
+ (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
+
+ /* When the vertex to relax is boundary, use only connected boundary vertices for the average
+ * position. */
+ if (is_boundary) {
+ if (!SCULPT_vertex_is_boundary(ss, ni.index)) {
+ continue;
+ }
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ avg_count++;
+
+ /* Calculate a normal for the constraint plane using the edges of the boundary. */
+ float to_neighbor[3];
+ sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co);
+ normalize_v3(to_neighbor);
+ add_v3_v3(boundary_normal, to_neighbor);
+ }
+ else {
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ avg_count++;
+ }
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ /* Don't modify corner vertices. */
+ if (neighbor_count <= 2) {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ if (avg_count > 0) {
+ mul_v3_fl(smooth_pos, 1.0f / avg_count);
+ }
+ else {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ float plane[4];
+ float smooth_closest_plane[3];
+ float vno[3];
+
+ if (is_boundary && avg_count == 2) {
+ normalize_v3_v3(vno, boundary_normal);
+ }
+ else {
+ SCULPT_vertex_normal_get(ss, vd->index, vno);
+ }
+
+ if (is_zero_v3(vno)) {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ plane_from_point_normal_v3(plane, vd->co, vno);
+ closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos);
+ sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co);
+
+ mul_v3_fl(final_disp, factor);
+ add_v3_v3v3(r_final_pos, vd->co, final_disp);
+}
+
+static void do_topology_relax_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ BKE_curvemapping_init(brush->curve);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ if (ss->cache->alt_smooth) {
+ SCULPT_boundary_info_ensure(ob);
+ for (int i = 0; i < 4; i++) {
+ BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
+ }
+ }
+ else {
+ BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
+ }
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Multires Displacement Eraser Brush
+ * \{ */
+
+static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
+
+ float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ float limit_co[3];
+ float disp[3];
+ SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co);
+ sub_v3_v3v3(disp, limit_co, vd.co);
+ mul_v3_v3fl(proxy[vd.i], disp, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Multires Displacement Smear Brush
+ * \{ */
+
+static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ float current_disp[3];
+ float current_disp_norm[3];
+ float interp_limit_surface_disp[3];
+
+ copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]);
+
+ switch (brush->smear_deform_type) {
+ case BRUSH_SMEAR_DEFORM_DRAG:
+ sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ break;
+ case BRUSH_SMEAR_DEFORM_PINCH:
+ sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+ break;
+ case BRUSH_SMEAR_DEFORM_EXPAND:
+ sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+ break;
+ }
+
+ normalize_v3_v3(current_disp_norm, current_disp);
+ mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+
+ float weights_accum = 1.0f;
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vertex_disp[3];
+ float vertex_disp_norm[3];
+ float neighbor_limit_co[3];
+ SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
+ sub_v3_v3v3(vertex_disp,
+ ss->cache->limit_surface_co[ni.index],
+ ss->cache->limit_surface_co[vd.index]);
+ const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index];
+ normalize_v3_v3(vertex_disp_norm, vertex_disp);
+
+ if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
+ continue;
+ }
+
+ const float disp_interp = clamp_f(
+ -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f);
+ madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp);
+ weights_accum += disp_interp;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum);
+
+ float new_co[3];
+ add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp);
+ interp_v3_v3v3(vd.co, vd.co, new_co, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_displacement_smear_store_prev_disp_task_cb_ex(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
+ SCULPT_vertex_co_get(ss, vd.index),
+ ss->cache->limit_surface_co[vd.index]);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+
+ BKE_curvemapping_init(brush->curve);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ if (!ss->cache->prev_displacement) {
+ ss->cache->prev_displacement = MEM_malloc_arrayN(
+ totvert, sizeof(float[3]), "prev displacement");
+ ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
+ for (int i = 0; i < totvert; i++) {
+ SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
+ sub_v3_v3v3(ss->cache->prev_displacement[i],
+ SCULPT_vertex_co_get(ss, i),
+ ss->cache->limit_surface_co[i]);
+ }
+ }
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(
+ 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Topology Rake (Shared Utility)
+ * \{ */
+
+static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+
+ float direction[3];
+ copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
+
+ float tmp[3];
+ mul_v3_v3fl(
+ tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
+ sub_v3_v3(direction, tmp);
+ normalize_v3(direction);
+
+ /* Cancel if there's no grab data. */
+ if (is_zero_v3(direction)) {
+ return;
+ }
+
+ const float bstrength = clamp_f(data->strength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade =
+ bstrength *
+ SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
+ ss->cache->pressure;
+
+ float avg[3], val[3];
+
+ SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
+
+ sub_v3_v3v3(val, avg, vd.co);
+
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+
+ SCULPT_clip(sd, ss, vd.co, val);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_bmesh_topology_rake(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const float strength = clamp_f(bstrength, 0.0f, 1.0f);
+
+ /* Interactions increase both strength and quality. */
+ const int iterations = 3;
+
+ int iteration;
+ const int count = iterations * strength + 1;
+ const float factor = iterations * strength / count;
+
+ for (iteration = 0; iteration <= count; iteration++) {
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .strength = factor,
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+
+ BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Mask Brush
+ * \{ */
+
+static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ const float fade = SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
+
+ if (bstrength > 0.0f) {
+ (*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
+ }
+ else {
+ (*vd.mask) += fade * bstrength * (*vd.mask);
+ }
+ *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+void SCULPT_do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
+}
+
+void SCULPT_do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ switch ((BrushMaskTool)brush->mask_tool) {
+ case BRUSH_MASK_DRAW:
+ SCULPT_do_mask_brush_draw(sd, ob, nodes, totnode);
+ break;
+ case BRUSH_MASK_SMOOTH:
+ SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
+ break;
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index dcfd7f7bcdc..3ac57d73d37 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -560,13 +560,6 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
thread_id);
float brush_disp[3];
- float normal[3];
- if (vd.no) {
- normal_short_to_float_v3(normal, vd.no);
- }
- else {
- copy_v3_v3(normal, vd.fno);
- }
switch (brush->cloth_deform_type) {
case BRUSH_CLOTH_DEFORM_DRAG:
@@ -621,7 +614,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(force, disp_center, fade);
} break;
case BRUSH_CLOTH_DEFORM_INFLATE:
- mul_v3_v3fl(force, normal, fade);
+ mul_v3_v3fl(force, vd.no ? vd.no : vd.fno, fade);
break;
case BRUSH_CLOTH_DEFORM_EXPAND:
cloth_sim->length_constraint_tweak[vd.index] += fade * 0.1f;
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index 9082408b8dd..f00b24d690a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -248,8 +248,10 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
{
/* Find 3D view to pick from. */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
- ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my) : NULL;
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, (const int[2]){mx, my});
+ ARegion *region = (area) ?
+ BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}) :
+ NULL;
if (region == NULL) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index 10f141e2311..cf45e25142b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -334,14 +334,7 @@ static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
if (total > 0) {
mul_v3_fl(avg, 1.0f / total);
- float normal[3];
- if (vd->no) {
- normal_short_to_float_v3(normal, vd->no);
- }
- else {
- copy_v3_v3(normal, vd->fno);
- }
- float dot = dot_v3v3(avg, normal);
+ float dot = dot_v3v3(avg, vd->no ? vd->no : vd->fno);
float angle = max_ff(saacosf(dot), 0.0f);
return angle;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index ff1a8935ba0..2d8bdc4e4ac 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -303,7 +303,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
- float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
+ float orig_co[3], val[3], avg[3], disp[3], disp2[3], transform[3][3], final_pos[3];
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
@@ -339,8 +339,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
sub_v3_v3v3(disp, val, orig_co);
break;
case MESH_FILTER_INFLATE:
- normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_v3fl(disp, normal, fade);
+ mul_v3_v3fl(disp, orig_data.no, fade);
break;
case MESH_FILTER_SCALE:
unit_m3(transform);
@@ -372,7 +371,8 @@ static void mesh_filter_task_cb(void *__restrict userdata,
mid_v3_v3v3(disp, disp, disp2);
break;
case MESH_FILTER_RANDOM: {
- normal_short_to_float_v3(normal, orig_data.no);
+ float normal[3];
+ copy_v3_v3(normal, orig_data.no);
/* Index is not unique for multires, so hash by vertex coordinates. */
const uint *hash_co = (const uint *)orig_co;
const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^
@@ -432,7 +432,6 @@ static void mesh_filter_task_cb(void *__restrict userdata,
/* Intensify details. */
if (ss->filter_cache->sharpen_intensify_detail_strength > 0.0f) {
float detail_strength[3];
- normal_short_to_float_v3(detail_strength, orig_data.no);
copy_v3_v3(detail_strength, ss->filter_cache->detail_directions[vd.index]);
madd_v3_v3fl(disp,
detail_strength,
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 4dd2a786922..8de9fa3763b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -29,13 +29,13 @@
#include "DNA_meshdata_types.h"
#include "DNA_vec_types.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
#include "BLI_bitmap.h"
+#include "BLI_compiler_compat.h"
#include "BLI_gsqueue.h"
#include "BLI_threads.h"
-#include "BKE_paint.h"
-#include "BKE_pbvh.h"
-
struct AutomaskingCache;
struct KeyBlock;
struct Object;
@@ -44,18 +44,12 @@ struct bContext;
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.
- */
-bool SCULPT_poll(struct bContext *C);
-bool SCULPT_poll_view3d(struct bContext *C);
-
-bool SCULPT_vertex_colors_poll(struct bContext *C);
-
/* Updates */
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Types
+ * \{ */
+
typedef enum SculptUpdateType {
SCULPT_UPDATE_COORDS = 1 << 0,
SCULPT_UPDATE_MASK = 1 << 1,
@@ -63,86 +57,14 @@ typedef enum SculptUpdateType {
SCULPT_UPDATE_COLOR = 1 << 3,
} 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.
- */
-void SCULPT_tag_update_overlays(bContext *C);
-
-/* Stroke */
-
typedef struct SculptCursorGeometryInfo {
float location[3];
float normal[3];
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],
- bool use_sampled_normal);
-void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
-
-void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush);
-float SCULPT_raycast_init(struct ViewContext *vc,
- const float mouse[2],
- float ray_start[3],
- float ray_end[3],
- float ray_normal[3],
- bool original);
-
-/* Symmetry */
-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);
-const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
-void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]);
-float SCULPT_vertex_mask_get(struct SculptSession *ss, int index);
-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.
- */
-const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
-
-/**
- * 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.
- */
-float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
- const int deform_target,
- PBVHVertexIter *iter);
-
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
+
typedef struct SculptVertexNeighborIter {
/* Storage */
int *neighbors;
@@ -159,531 +81,33 @@ typedef struct SculptVertexNeighborIter {
bool is_duplicate;
} SculptVertexNeighborIter;
-void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
- const int index,
- const bool include_duplicates,
- SculptVertexNeighborIter *iter);
-
-/* Iterator over neighboring vertices. */
-#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
- SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
- for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
- neighbor_iterator.i++) { \
- neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
-
-/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
- * first since they are nearest for floodfill. */
-#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
- SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
- for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
- neighbor_iterator.i--) { \
- neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
- neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
- neighbor_iterator.size - neighbor_iterator.num_duplicates);
-
-#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \
- } \
- if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
- MEM_freeN(neighbor_iterator.neighbors); \
- } \
- ((void)0)
-
-int SCULPT_active_vertex_get(SculptSession *ss);
-const float *SCULPT_active_vertex_co_get(SculptSession *ss);
-void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
-
-/* Returns PBVH deformed vertices array if shape keys or deform modifiers are used, otherwise
- * returns mesh original vertices array. */
-struct MVert *SCULPT_mesh_deformed_mverts_get(SculptSession *ss);
-
-/* Fake Neighbors */
-
-#define FAKE_NEIGHBOR_NONE -1
-
-void SCULPT_fake_neighbors_ensure(struct Sculpt *sd, Object *ob, const float max_dist);
-void SCULPT_fake_neighbors_enable(Object *ob);
-void SCULPT_fake_neighbors_disable(Object *ob);
-void SCULPT_fake_neighbors_free(struct Object *ob);
-
-/* Vertex Info. */
-void SCULPT_boundary_info_ensure(Object *object);
-/* Boundary Info needs to be initialized in order to use this function. */
-bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index);
-
-void SCULPT_connected_components_ensure(Object *ob);
-
-/* Sculpt Visibility API */
-
-void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible);
-bool SCULPT_vertex_visible_get(SculptSession *ss, int index);
-
-void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob);
-void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
-
-/* Face Sets API */
-
-int SCULPT_active_face_set_get(SculptSession *ss);
-int SCULPT_vertex_face_set_get(SculptSession *ss, int index);
-void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set);
-
-bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set);
-bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index);
-
-int SCULPT_face_set_next_available_get(SculptSession *ss);
-
-void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible);
-bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index);
-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 */
typedef struct {
struct BMLog *bm_log;
struct SculptUndoNode *unode;
float (*coords)[3];
- short (*normals)[3];
+ float (*normals)[3];
const float *vmasks;
float (*colors)[4];
/* Original coordinate, normal, and mask. */
const float *co;
- const short *no;
+ const float *no;
float mask;
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);
-
-/* Utils. */
-void SCULPT_calc_brush_plane(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode,
- float r_area_no[3],
- float r_area_co[3]);
-
-void SCULPT_calc_area_normal(
- Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]);
-
-int SCULPT_nearest_vertex_get(struct Sculpt *sd,
- struct Object *ob,
- const float co[3],
- float max_distance,
- bool use_original);
-
-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,
- char symm);
-bool SCULPT_is_symmetry_iteration_valid(char i, char symm);
-void SCULPT_flip_v3_by_symm_area(float v[3],
- const ePaintSymmetryFlags symm,
- const ePaintSymmetryAreas symmarea,
- const float pivot[3]);
-void SCULPT_flip_quat_by_symm_area(float quat[4],
- const ePaintSymmetryFlags symm,
- const ePaintSymmetryAreas symmarea,
- const float pivot[3]);
-
/* Flood Fill. */
typedef struct {
GSQueue *queue;
BLI_bitmap *visited_vertices;
} SculptFloodFill;
-void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood);
-void SCULPT_floodfill_add_active(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- SculptFloodFill *flood,
- float radius);
-void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- SculptFloodFill *flood,
- int index,
- float radius);
-void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index);
-void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index);
-void SCULPT_floodfill_execute(
- struct SculptSession *ss,
- SculptFloodFill *flood,
- bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
- void *userdata);
-void SCULPT_floodfill_free(SculptFloodFill *flood);
-
-/* Dynamic topology */
-
-enum eDynTopoWarnFlag {
- DYNTOPO_WARN_VDATA = (1 << 0),
- DYNTOPO_WARN_EDATA = (1 << 1),
- DYNTOPO_WARN_LDATA = (1 << 2),
- DYNTOPO_WARN_MODIFIER = (1 << 3),
-};
-
-void SCULPT_dynamic_topology_enable_ex(struct Main *bmain,
- struct Depsgraph *depsgraph,
- Scene *scene,
- Object *ob);
-void SCULPT_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
-void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain,
- struct Depsgraph *depsgraph,
- 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);
-void SCULPT_dyntopo_node_layers_add(struct SculptSession *ss);
-
-enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob);
-
-void SCULPT_pbvh_clear(Object *ob);
-
-/* Auto-masking. */
-float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking,
- SculptSession *ss,
- int vert);
-
-/* Returns the automasking cache depending on the active tool. Used for code that can run both for
- * brushes and filter. */
-struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss);
-
-struct AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob);
-void SCULPT_automasking_cache_free(struct AutomaskingCache *automasking);
-
-bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd,
- const Brush *br,
- const eAutomasking_flag mode);
-bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br);
-
typedef enum eBoundaryAutomaskMode {
AUTOMASK_INIT_BOUNDARY_EDGES = 1,
AUTOMASK_INIT_BOUNDARY_FACE_SETS = 2,
} eBoundaryAutomaskMode;
-float *SCULPT_boundary_automasking_init(Object *ob,
- eBoundaryAutomaskMode mode,
- int propagation_steps,
- float *automask_factor);
-
-/* Geodesic distances. */
-
-/**
- * Returns an array indexed by vertex index containing the geodesic distance to the closest vertex
- * in the initial vertex set. The caller is responsible for freeing the array.
- * Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will
- * fallback to euclidean distances to one of the initial vertices in the set.
- */
-float *SCULPT_geodesic_distances_create(struct Object *ob,
- struct GSet *initial_vertices,
- const float limit_radius);
-float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd,
- struct Object *ob,
- const int vertex,
- const float limit_radius);
-float *SCULPT_geodesic_from_vertex(Object *ob, const int vertex, const float limit_radius);
-
-/* Filters. */
-void SCULPT_filter_cache_init(struct bContext *C, Object *ob, Sculpt *sd, const int undo_type);
-void SCULPT_filter_cache_free(SculptSession *ss);
-
-void SCULPT_mask_filter_smooth_apply(
- Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, const int smooth_iterations);
-
-/* Brushes. */
-
-/* Cloth Brush. */
-
-/**
- * Main Brush Function.
- */
-void SCULPT_do_cloth_brush(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode);
-
-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,
- const float cloth_damping,
- const float cloth_softbody_strength,
- const bool use_collisions,
- const bool needs_deform_coords);
-void SCULPT_cloth_brush_simulation_init(struct SculptSession *ss,
- struct SculptClothSimulation *cloth_sim);
-
-void SCULPT_cloth_sim_activate_nodes(struct SculptClothSimulation *cloth_sim,
- PBVHNode **nodes,
- int totnode);
-
-void SCULPT_cloth_brush_store_simulation_state(struct SculptSession *ss,
- struct SculptClothSimulation *cloth_sim);
-
-void SCULPT_cloth_brush_do_simulation_step(struct Sculpt *sd,
- struct Object *ob,
- struct SculptClothSimulation *cloth_sim,
- struct PBVHNode **nodes,
- int totnode);
-
-void SCULPT_cloth_brush_ensure_nodes_constraints(struct Sculpt *sd,
- struct Object *ob,
- struct PBVHNode **nodes,
- int totnode,
- struct SculptClothSimulation *cloth_sim,
- 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],
- const float normal[3],
- const float rds,
- const float line_width,
- const float outline_col[3],
- const float alpha);
-void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
- struct SculptSession *ss,
- const float outline_col[3],
- float outline_alpha);
-
-PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss,
- Brush *brush,
- int *r_totnode);
-
-BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush)
-{
- return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type,
- BRUSH_CLOTH_DEFORM_GRAB,
- BRUSH_CLOTH_DEFORM_SNAKE_HOOK)) ||
- /* All brushes that are not the cloth brush deform the simulation using softbody
- * constraints instead of applying forces. */
- (brush->sculpt_tool != SCULPT_TOOL_CLOTH &&
- brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM);
-}
-
-BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush)
-{
- if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
- /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect
- * of the Kelvinlet is not constrained by the radius. */
- return true;
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
- /* Pose needs all nodes because it applies all symmetry iterations at the same time
- * and the IK chain can grow to any area of the model. */
- /* TODO: This can be optimized by filtering the nodes after calculating the chain. */
- return true;
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) {
- /* Boundary needs all nodes because it is not possible to know where the boundary
- * deformation is going to be propagated before calculating it. */
- /* TODO: after calculating the boundary info in the first iteration, it should be
- * possible to get the nodes that have vertices included in any boundary deformation
- * and cache them. */
- return true;
- }
-
- if (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK &&
- brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC) {
- /* Snake hook in elastic deform type has same requirements as the elastic deform tool. */
- return true;
- }
- return false;
-}
-
-/* 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,
- float initial_location[3],
- float radius,
- float pose_offset,
- float *r_pose_origin,
- float *r_pose_factor);
-void SCULPT_pose_brush_init(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- struct Brush *br);
-struct SculptPoseIKChain *SCULPT_pose_ik_chain_init(struct Sculpt *sd,
- struct Object *ob,
- struct SculptSession *ss,
- struct Brush *br,
- const float initial_location[3],
- const float radius);
-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,
- int totnode);
-
-void SCULPT_boundary_edges_preview_draw(const uint gpuattr,
- struct SculptSession *ss,
- const float outline_col[3],
- const float outline_alpha);
-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,
- SculptSession *ss,
- const float outline_col[3],
- const float outline_alpha);
-/* Draw Face Sets Brush. */
-void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Paint Brush. */
-void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Smear Brush. */
-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 auto-masking.
- */
-void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index);
-
-void SCULPT_smooth(Sculpt *sd,
- Object *ob,
- PBVHNode **nodes,
- const int totnode,
- float bstrength,
- const bool smooth_mask);
-void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Surface Smooth Brush. */
-
-void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
- float *disp,
- const float co[3],
- float (*laplacian_disp)[3],
- const int v_index,
- const float origco[3],
- const float alpha);
-void SCULPT_surface_smooth_displace_step(SculptSession *ss,
- float *co,
- float (*laplacian_disp)[3],
- const int v_index,
- const float beta,
- const float fade);
-void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
-
-/* Slide/Relax */
-void SCULPT_relax_vertex(struct SculptSession *ss,
- struct PBVHVertexIter *vd,
- float factor,
- bool filter_boundary_face_sets,
- float *r_final_pos);
/* Undo */
@@ -726,7 +150,7 @@ typedef struct SculptUndoNode {
float (*co)[3];
float (*orig_co)[3];
- short (*no)[3];
+ float (*no)[3];
float (*col)[4];
float *mask;
int totvert;
@@ -782,7 +206,13 @@ struct SculptRakeData {
float follow_co[3];
};
-/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */
+/*
+Generic thread data. The size of this struct
+has gotten a little out of hand; normally we would
+split it up, but it might be better to see if we can't
+eliminate it altogether after moving to C++ (where
+we'll be able to use lambdas).
+*/
typedef struct SculptThreadedTaskData {
struct bContext *C;
struct Sculpt *sd;
@@ -939,70 +369,12 @@ typedef struct {
struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
} SculptSearchCircleData;
-void SCULPT_brush_test_init(struct SculptSession *ss, SculptBrushTest *test);
-bool SCULPT_brush_test_sphere(SculptBrushTest *test, const float co[3]);
-bool SCULPT_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]);
-bool SCULPT_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3]);
-bool SCULPT_brush_test_cube(SculptBrushTest *test,
- const float co[3],
- 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,
- SculptBrushTest *test,
- char falloff_shape);
-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],
- const float len,
- const short vno[3],
- const float fno[3],
- const float mask,
- const int vertex_index,
- const int thread_id);
-
-/**
- * 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.
- */
-void SCULPT_tilt_effective_normal_get(const SculptSession *ss, const Brush *brush, float r_no[3]);
-
-/**
- * Expose 'calc_area_normal' externally (just for vertex paint).
- */
-bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
- Object *ob,
- PBVHNode **nodes,
- int totnode,
- bool use_threading,
- float r_area_no[3]);
-
-/* Cache stroke properties. Used because
- * RNA property lookup isn't particularly fast.
- *
- * For descriptions of these settings, check the operator properties.
- */
+/* Sculpt Filters */
+typedef enum SculptFilterOrientation {
+ SCULPT_FILTER_ORIENTATION_LOCAL = 0,
+ SCULPT_FILTER_ORIENTATION_WORLD = 1,
+ SCULPT_FILTER_ORIENTATION_VIEW = 2,
+} SculptFilterOrientation;
#define SCULPT_CLAY_STABILIZER_LEN 10
@@ -1019,12 +391,74 @@ typedef struct AutomaskingCache {
float *factor;
} AutomaskingCache;
+typedef struct FilterCache {
+ bool enabled_axis[3];
+ bool enabled_force_axis[3];
+ int random_seed;
+
+ /* Used for alternating between filter operations in filters that need to apply different ones to
+ * achieve certain effects. */
+ int iteration_count;
+
+ /* Stores the displacement produced by the laplacian step of HC smooth. */
+ float (*surface_smooth_laplacian_disp)[3];
+ float surface_smooth_shape_preservation;
+ float surface_smooth_current_vertex;
+
+ /* Sharpen mesh filter. */
+ float sharpen_smooth_ratio;
+ float sharpen_intensify_detail_strength;
+ int sharpen_curvature_smooth_iterations;
+ float *sharpen_factor;
+ float (*detail_directions)[3];
+
+ /* Filter orientation. */
+ SculptFilterOrientation orientation;
+ float obmat[4][4];
+ float obmat_inv[4][4];
+ float viewmat[4][4];
+ float viewmat_inv[4][4];
+
+ /* Displacement eraser. */
+ float (*limit_surface_co)[3];
+
+ /* unmasked nodes */
+ PBVHNode **nodes;
+ int totnode;
+
+ /* Cloth filter. */
+ SculptClothSimulation *cloth_sim;
+ float cloth_sim_pinch_point[3];
+
+ /* mask expand iteration caches */
+ int mask_update_current_it;
+ int mask_update_last_it;
+ int *mask_update_it;
+ float *normal_factor;
+ float *edge_factor;
+ float *prev_mask;
+ float mask_expand_initial_co[3];
+
+ int new_face_set;
+ int *prev_face_set;
+
+ int active_face_set;
+
+ /* Auto-masking. */
+ AutomaskingCache *automasking;
+} FilterCache;
+
+/**
+ * This structure contains all the temporary data
+ * needed for individual brush strokes.
+ */
typedef struct StrokeCache {
/* Invariants */
float initial_radius;
float scale[3];
int flag;
float clip_tolerance[3];
+ float clip_mirror_mtx[4][4];
float initial_mouse[2];
/* Variants */
@@ -1181,27 +615,10 @@ typedef struct StrokeCache {
} StrokeCache;
-/* Sculpt Filters */
-typedef enum SculptFilterOrientation {
- SCULPT_FILTER_ORIENTATION_LOCAL = 0,
- SCULPT_FILTER_ORIENTATION_WORLD = 1,
- SCULPT_FILTER_ORIENTATION_VIEW = 2,
-} SculptFilterOrientation;
-
-/* Defines how transform tools are going to apply its displacement. */
-typedef enum SculptTransformDisplacementMode {
- /* Displaces the elements from their original coordinates. */
- SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL = 0,
- /* Displaces the elements incrementally from their previous position. */
- SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL = 1,
-} SculptTransformDisplacementMode;
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Expand
+ * \{ */
-/* 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);
-
-/* Sculpt Expand. */
typedef enum eSculptExpandFalloffType {
SCULPT_EXPAND_FALLOFF_GEODESIC,
SCULPT_EXPAND_FALLOFF_TOPOLOGY,
@@ -1349,83 +766,676 @@ typedef struct ExpandCache {
int *original_face_sets;
float (*original_colors)[4];
} ExpandCache;
+/** \} */
-typedef struct FilterCache {
- bool enabled_axis[3];
- bool enabled_force_axis[3];
- int random_seed;
+/** \} */
- /* Used for alternating between filter operations in filters that need to apply different ones to
- * achieve certain effects. */
- int iteration_count;
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Poll Functions
+ * \{ */
- /* Stores the displacement produced by the laplacian step of HC smooth. */
- float (*surface_smooth_laplacian_disp)[3];
- float surface_smooth_shape_preservation;
- float surface_smooth_current_vertex;
+bool SCULPT_mode_poll(struct bContext *C);
+bool SCULPT_mode_poll_view3d(struct bContext *C);
+/**
+ * Checks for a brush, not just sculpt mode.
+ */
+bool SCULPT_poll(struct bContext *C);
+bool SCULPT_poll_view3d(struct bContext *C);
- /* Sharpen mesh filter. */
- float sharpen_smooth_ratio;
- float sharpen_intensify_detail_strength;
- int sharpen_curvature_smooth_iterations;
- float *sharpen_factor;
- float (*detail_directions)[3];
+bool SCULPT_vertex_colors_poll(struct bContext *C);
- /* Filter orientation. */
- SculptFilterOrientation orientation;
- float obmat[4][4];
- float obmat_inv[4][4];
- float viewmat[4][4];
- float viewmat_inv[4][4];
+/** \} */
- /* Displacement eraser. */
- float (*limit_surface_co)[3];
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Update Functions
+ * \{ */
- /* unmasked nodes */
- PBVHNode **nodes;
- int totnode;
+void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags);
+void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags);
- /* Cloth filter. */
- SculptClothSimulation *cloth_sim;
- float cloth_sim_pinch_point[3];
+void SCULPT_pbvh_clear(Object *ob);
- /* mask expand iteration caches */
- int mask_update_current_it;
- int mask_update_last_it;
- int *mask_update_it;
- float *normal_factor;
- float *edge_factor;
- float *prev_mask;
- float mask_expand_initial_co[3];
+/**
+ * Flush displacement from deformed PBVH to original layer.
+ */
+void SCULPT_flush_stroke_deform(struct Sculpt *sd, Object *ob, bool is_proxy_used);
- int new_face_set;
- int *prev_face_set;
+/**
+ * Should be used after modifying the mask or Face Sets IDs.
+ */
+void SCULPT_tag_update_overlays(bContext *C);
+/** \} */
- int active_face_set;
+/* -------------------------------------------------------------------- */
+/** \name Stroke Functions
+ * \{ */
- /* Transform. */
- SculptTransformDisplacementMode transform_displacement_mode;
+/* Stroke */
- /* Auto-masking. */
- AutomaskingCache *automasking;
-} FilterCache;
+/**
+ * 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],
+ bool use_sampled_normal);
+void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
+
+void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush);
+float SCULPT_raycast_init(struct ViewContext *vc,
+ const float mouse[2],
+ float ray_start[3],
+ float ray_end[3],
+ float ray_normal[3],
+ bool original);
+
+/* Symmetry */
+char SCULPT_mesh_symmetry_xyz_get(Object *object);
+
+/**
+ * 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);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt mesh accessor API
+ * \{ */
+
+/** Ensure random access; required for PBVH_BMESH */
+void SCULPT_vertex_random_access_ensure(struct SculptSession *ss);
+
+int SCULPT_vertex_count_get(struct SculptSession *ss);
+const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
+
+/** Get the normal for a given sculpt vertex; do not modify the result */
+void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]);
+
+float SCULPT_vertex_mask_get(struct SculptSession *ss, int index);
+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.
+ */
+const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index);
+
+/**
+ * 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.
+ */
+float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
+ int deform_target,
+ PBVHVertexIter *iter);
+
+void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
+ int index,
+ bool include_duplicates,
+ SculptVertexNeighborIter *iter);
+
+/** Iterator over neighboring vertices. */
+#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
+ SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
+ for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
+ neighbor_iterator.i++) { \
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
+
+/** Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
+ * first since they are nearest for floodfill. */
+#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
+ SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
+ for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
+ neighbor_iterator.i--) { \
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
+ neighbor_iterator.size - neighbor_iterator.num_duplicates);
+
+#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \
+ } \
+ if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
+ MEM_freeN(neighbor_iterator.neighbors); \
+ } \
+ ((void)0)
+
+int SCULPT_active_vertex_get(SculptSession *ss);
+const float *SCULPT_active_vertex_co_get(SculptSession *ss);
+void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
+
+/* Returns PBVH deformed vertices array if shape keys or deform modifiers are used, otherwise
+ * returns mesh original vertices array. */
+struct MVert *SCULPT_mesh_deformed_mverts_get(SculptSession *ss);
+
+/* Fake Neighbors */
+
+#define FAKE_NEIGHBOR_NONE -1
+
+void SCULPT_fake_neighbors_ensure(struct Sculpt *sd, Object *ob, float max_dist);
+void SCULPT_fake_neighbors_enable(Object *ob);
+void SCULPT_fake_neighbors_disable(Object *ob);
+void SCULPT_fake_neighbors_free(struct Object *ob);
+
+/* Vertex Info. */
+void SCULPT_boundary_info_ensure(Object *object);
+/* Boundary Info needs to be initialized in order to use this function. */
+bool SCULPT_vertex_is_boundary(const SculptSession *ss, int index);
+
+void SCULPT_connected_components_ensure(Object *ob);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Visibility API
+ * \{ */
+
+void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible);
+bool SCULPT_vertex_visible_get(SculptSession *ss, int index);
+
+void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob);
+void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Face Sets API
+ * \{ */
+
+int SCULPT_active_face_set_get(SculptSession *ss);
+int SCULPT_vertex_face_set_get(SculptSession *ss, int index);
+void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set);
+
+bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set);
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index);
+
+int SCULPT_face_set_next_available_get(SculptSession *ss);
+
+void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible);
+bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index);
+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);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Original Data API
+ * \{ */
+
+/**
+ * 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);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Brush Utilities.
+ * \{ */
+
+BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush)
+{
+ if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect
+ * of the Kelvinlet is not constrained by the radius. */
+ return true;
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ /* Pose needs all nodes because it applies all symmetry iterations at the same time
+ * and the IK chain can grow to any area of the model. */
+ /* TODO: This can be optimized by filtering the nodes after calculating the chain. */
+ return true;
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) {
+ /* Boundary needs all nodes because it is not possible to know where the boundary
+ * deformation is going to be propagated before calculating it. */
+ /* TODO: after calculating the boundary info in the first iteration, it should be
+ * possible to get the nodes that have vertices included in any boundary deformation
+ * and cache them. */
+ return true;
+ }
+
+ if (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK &&
+ brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC) {
+ /* Snake hook in elastic deform type has same requirements as the elastic deform tool. */
+ return true;
+ }
+ return false;
+}
+
+void SCULPT_calc_brush_plane(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode,
+ float r_area_no[3],
+ float r_area_co[3]);
+
+void SCULPT_calc_area_normal(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]);
+/**
+ * This calculates flatten center and area normal together,
+ * amortizing the memory bandwidth and loop overhead to calculate both at the same time.
+ */
+void SCULPT_calc_area_normal_and_center(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]);
+void SCULPT_calc_area_center(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3]);
+
+int SCULPT_nearest_vertex_get(struct Sculpt *sd,
+ struct Object *ob,
+ const float co[3],
+ float max_distance,
+ bool use_original);
+
+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], 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,
+ char symm);
+bool SCULPT_is_symmetry_iteration_valid(char i, char symm);
+void SCULPT_flip_v3_by_symm_area(float v[3],
+ ePaintSymmetryFlags symm,
+ ePaintSymmetryAreas symmarea,
+ const float pivot[3]);
+void SCULPT_flip_quat_by_symm_area(float quat[4],
+ ePaintSymmetryFlags symm,
+ ePaintSymmetryAreas symmarea,
+ const float pivot[3]);
+
+/**
+ * Initialize a point-in-brush test
+ */
+void SCULPT_brush_test_init(struct SculptSession *ss, SculptBrushTest *test);
+
+bool SCULPT_brush_test_sphere(SculptBrushTest *test, const float co[3]);
+bool SCULPT_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]);
+bool SCULPT_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3]);
+bool SCULPT_brush_test_cube(SculptBrushTest *test,
+ const float co[3],
+ const float local[4][4],
+ 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);
+
+/**
+ * Initialize a point-in-brush test with a given falloff shape
+ *
+ * \param falloff_shape PAINT_FALLOFF_SHAPE_SPHERE or PAINT_FALLOFF_SHAPE_TUBE
+ * \return The brush falloff function
+ */
+SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss,
+ SculptBrushTest *test,
+ char falloff_shape);
+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],
+ float len,
+ const float vno[3],
+ const float fno[3],
+ float mask,
+ int vertex_index,
+ int thread_id);
+
+/**
+ * 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,
+ float tilt_strength);
+
+/**
+ * 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]);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flood Fill
+ * \{ */
+
+void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood);
+void SCULPT_floodfill_add_active(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ SculptFloodFill *flood,
+ float radius);
+void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ SculptFloodFill *flood,
+ int index,
+ float radius);
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index);
+void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index);
+void SCULPT_floodfill_execute(
+ struct SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
+ void *userdata);
+void SCULPT_floodfill_free(SculptFloodFill *flood);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dynamic topology
+ * \{ */
+
+enum eDynTopoWarnFlag {
+ DYNTOPO_WARN_VDATA = (1 << 0),
+ DYNTOPO_WARN_EDATA = (1 << 1),
+ DYNTOPO_WARN_LDATA = (1 << 2),
+ DYNTOPO_WARN_MODIFIER = (1 << 3),
+};
+
+/** Enable dynamic topology; mesh will be triangulated */
+void SCULPT_dynamic_topology_enable_ex(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob);
+void SCULPT_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
+void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ 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);
+void SCULPT_dyntopo_node_layers_add(struct SculptSession *ss);
+
+enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-masking.
+ * \{ */
+
+float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking,
+ SculptSession *ss,
+ int vert);
+
+/* Returns the automasking cache depending on the active tool. Used for code that can run both for
+ * brushes and filter. */
+struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss);
+
+struct AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob);
+void SCULPT_automasking_cache_free(struct AutomaskingCache *automasking);
+
+bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd, const Brush *br, eAutomasking_flag mode);
+bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br);
+
+float *SCULPT_boundary_automasking_init(Object *ob,
+ eBoundaryAutomaskMode mode,
+ int propagation_steps,
+ float *automask_factor);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Geodesic distances.
+ * \{ */
+
+/**
+ * Returns an array indexed by vertex index containing the geodesic distance to the closest vertex
+ * in the initial vertex set. The caller is responsible for freeing the array.
+ * Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will
+ * fallback to euclidean distances to one of the initial vertices in the set.
+ */
+float *SCULPT_geodesic_distances_create(struct Object *ob,
+ struct GSet *initial_vertices,
+ float limit_radius);
+float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd,
+ struct Object *ob,
+ int vertex,
+ float limit_radius);
+float *SCULPT_geodesic_from_vertex(Object *ob, int vertex, float limit_radius);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Filter API
+ * \{ */
+
+void SCULPT_filter_cache_init(struct bContext *C, Object *ob, Sculpt *sd, int undo_type);
+void SCULPT_filter_cache_free(SculptSession *ss);
+
+void SCULPT_mask_filter_smooth_apply(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, int smooth_iterations);
+
+/* 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);
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cloth Simulation.
+ * \{ */
+
+/* Main cloth brush function */
+void SCULPT_do_cloth_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim);
+
+/* Public functions. */
+
+struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(struct SculptSession *ss,
+ float cloth_mass,
+ float cloth_damping,
+ float cloth_softbody_strength,
+ bool use_collisions,
+ bool needs_deform_coords);
+void SCULPT_cloth_brush_simulation_init(struct SculptSession *ss,
+ struct SculptClothSimulation *cloth_sim);
+
+void SCULPT_cloth_sim_activate_nodes(struct SculptClothSimulation *cloth_sim,
+ PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_cloth_brush_store_simulation_state(struct SculptSession *ss,
+ struct SculptClothSimulation *cloth_sim);
+
+void SCULPT_cloth_brush_do_simulation_step(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptClothSimulation *cloth_sim,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_cloth_brush_ensure_nodes_constraints(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode,
+ struct SculptClothSimulation *cloth_sim,
+ float initial_location[3],
+ float radius);
+
+/**
+ * Cursor drawing function.
+ */
+void SCULPT_cloth_simulation_limits_draw(uint gpuattr,
+ const struct Brush *brush,
+ const float location[3],
+ const float normal[3],
+ float rds,
+ float line_width,
+ const float outline_col[3],
+ float alpha);
+void SCULPT_cloth_plane_falloff_preview_draw(uint gpuattr,
+ struct SculptSession *ss,
+ const float outline_col[3],
+ float outline_alpha);
+
+PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss,
+ Brush *brush,
+ int *r_totnode);
+
+BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush)
+{
+ return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type,
+ BRUSH_CLOTH_DEFORM_GRAB,
+ BRUSH_CLOTH_DEFORM_SNAKE_HOOK)) ||
+ /* All brushes that are not the cloth brush deform the simulation using softbody
+ * constraints instead of applying forces. */
+ (brush->sculpt_tool != SCULPT_TOOL_CLOTH &&
+ brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM);
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smoothing API
+ * \{ */
+
+/**
+ * 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 auto-masking.
+ */
+void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index);
+
+void SCULPT_smooth(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength, bool smooth_mask);
+void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Surface Smooth Brush. */
+
+void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
+ float *disp,
+ const float co[3],
+ float (*laplacian_disp)[3],
+ int v_index,
+ const float origco[3],
+ float alpha);
+void SCULPT_surface_smooth_displace_step(
+ SculptSession *ss, float *co, float (*laplacian_disp)[3], int v_index, float beta, float fade);
+void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Slide/Relax */
+void SCULPT_relax_vertex(struct SculptSession *ss,
+ struct PBVHVertexIter *vd,
+ float factor,
+ bool filter_boundary_face_sets,
+ float *r_final_pos);
+
+/** \} */
+
+/**
+ * Expose 'calc_area_normal' externally (just for vertex paint).
+ */
+bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
+ Object *ob,
+ PBVHNode **nodes,
+ int totnode,
+ bool use_threading,
+ float r_area_no[3]);
/**
* 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,
- const float angle);
+void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, char symm, char axis, float angle);
void SCULPT_cache_free(StrokeCache *cache);
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Undo
+ * \{ */
+
SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node);
SculptUndoNode *SCULPT_undo_get_first_node(void);
void SCULPT_undo_push_begin(struct Object *ob, const char *name);
void SCULPT_undo_push_end(void);
-void SCULPT_undo_push_end_ex(const bool use_nested_undo);
+void SCULPT_undo_push_end_ex(bool use_nested_undo);
+
+/** \} */
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]);
@@ -1444,12 +1454,17 @@ bool SCULPT_get_redraw_rect(struct ARegion *region,
/* Operators. */
-/* Expand. */
+/* -------------------------------------------------------------------- */
+/** \name Expand Operator
+ * \{ */
void SCULPT_OT_expand(struct wmOperatorType *ot);
void sculpt_expand_modal_keymap(struct wmKeyConfig *keyconf);
+/** \} */
-/* Gestures. */
+/* -------------------------------------------------------------------- */
+/** \name Gesture Operators
+ * \{ */
void SCULPT_OT_face_set_lasso_gesture(struct wmOperatorType *ot);
void SCULPT_OT_face_set_box_gesture(struct wmOperatorType *ot);
@@ -1458,8 +1473,11 @@ void SCULPT_OT_trim_lasso_gesture(struct wmOperatorType *ot);
void SCULPT_OT_trim_box_gesture(struct wmOperatorType *ot);
void SCULPT_OT_project_line_gesture(struct wmOperatorType *ot);
+/** \} */
-/* Face Sets. */
+/* -------------------------------------------------------------------- */
+/** \name Face Set Operators
+ * \{ */
void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot);
@@ -1467,9 +1485,18 @@ void SCULPT_OT_face_sets_init(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_create(struct wmOperatorType *ot);
void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot);
-/* Transform. */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Operators
+ * \{ */
void SCULPT_OT_set_pivot_position(struct wmOperatorType *ot);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Filter Operators
+ * \{ */
/* Mesh Filter. */
@@ -1483,6 +1510,12 @@ void SCULPT_OT_cloth_filter(struct wmOperatorType *ot);
void SCULPT_OT_color_filter(struct wmOperatorType *ot);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Interactive Mask Operators
+ * \{ */
+
/* Mask filter and Dirty Mask. */
void SCULPT_OT_mask_filter(struct wmOperatorType *ot);
@@ -1495,14 +1528,210 @@ void SCULPT_OT_mask_expand(struct wmOperatorType *ot);
/* Mask Init. */
void SCULPT_OT_mask_init(struct wmOperatorType *ot);
+/** \} */
/* Detail size. */
+/* -------------------------------------------------------------------- */
+/** \name Dyntopo/Retopology Operators
+ * \{ */
+
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);
+
+/* sculpt_brush_types.c */
+
+/* -------------------------------------------------------------------- */
+/** \name Brushes
+ * \{ */
+
+/* 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,
+ float initial_location[3],
+ float radius,
+ float pose_offset,
+ float *r_pose_origin,
+ float *r_pose_factor);
+void SCULPT_pose_brush_init(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ struct Brush *br);
+struct SculptPoseIKChain *SCULPT_pose_ik_chain_init(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ struct Brush *br,
+ const float initial_location[3],
+ float radius);
+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,
+ int initial_vertex,
+ 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,
+ int totnode);
+
+void SCULPT_boundary_edges_preview_draw(uint gpuattr,
+ struct SculptSession *ss,
+ const float outline_col[3],
+ float outline_alpha);
+void SCULPT_boundary_pivot_line_preview_draw(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(uint gpuattr,
+ Brush *brush,
+ SculptSession *ss,
+ const float outline_col[3],
+ float outline_alpha);
+/* Draw Face Sets Brush. */
+void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Paint Brush. */
+void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Smear Brush. */
+void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+float SCULPT_clay_thumb_get_stabilized_pressure(struct StrokeCache *cache);
+
+void SCULPT_do_draw_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_do_fill_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_scrape_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_thumb_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_flatten_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_strips_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_snake_hook_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_thumb_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_rotate_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_layer_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_inflate_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_nudge_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_crease_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_pinch_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_grab_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_elastic_deform_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_draw_sharp_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_slide_relax_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_do_displacement_smear_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_displacement_eraser_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_mask_brush_draw(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_mask_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+/** \} */
+
+void SCULPT_bmesh_topology_rake(
+ struct Sculpt *sd, struct Object *ob, struct PBVHNode **nodes, int totnode, float bstrength);
+
+/* end sculpt_brush_types.c */
+
+/* sculpt_ops.c */
+void SCULPT_OT_brush_stroke(struct wmOperatorType *ot);
+
+/* end sculpt_ops.c */
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index 05db799cb00..0fec7a9c4bd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -92,12 +92,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
}
float local_co[3];
float normal[3];
- if (vd.no) {
- normal_short_to_float_v3(normal, vd.no);
- }
- else {
- copy_v3_v3(normal, vd.fno);
- }
+ copy_v3_v3(normal, vd.no ? vd.no : vd.fno);
mul_v3_m4v3(local_co, mat, vd.co);
/* Use the brush falloff to weight the sampled normals. */
const float fade = SCULPT_brush_strength_factor(ss,
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
new file mode 100644
index 00000000000..119d246a770
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -0,0 +1,1141 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ * Implements the Sculpt Mode tools
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.h"
+#include "BLI_blenlib.h"
+#include "BLI_dial_2d.h"
+#include "BLI_ghash.h"
+#include "BLI_gsqueue.h"
+#include "BLI_hash.h"
+#include "BLI_link_utils.h"
+#include "BLI_linklist.h"
+#include "BLI_linklist_stack.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_color_blend.h"
+#include "BLI_memarena.h"
+#include "BLI_rand.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+#include "atomic_ops.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_listBase.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_attribute.h"
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_kelvinlet.h"
+#include "BKE_key.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_fair.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_mirror.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_pbvh.h"
+#include "BKE_pointcache.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subsurf.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "IMB_colormanagement.h"
+
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_space_api.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */
+
+static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss) {
+ return OPERATOR_FINISHED;
+ }
+ SCULPT_vertex_random_access_ensure(ss);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
+
+ MEM_SAFE_FREE(ss->persistent_base);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert,
+ "layer persistent base");
+
+ for (int i = 0; i < totvert; i++) {
+ copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i));
+ SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no);
+ ss->persistent_base[i].disp = 0.0f;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Set Persistent Base";
+ ot->idname = "SCULPT_OT_set_persistent_base";
+ ot->description = "Reset the copy of the mesh that is being sculpted on";
+
+ /* API callbacks. */
+ ot->exec = sculpt_set_persistent_base_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/************************* SCULPT_OT_optimize *************************/
+
+static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ SCULPT_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/* The BVH gets less optimal more quickly with dynamic topology than
+ * regular sculpting. There is no doubt more clever stuff we can do to
+ * optimize it on the fly, but for now this gives the user a nicer way
+ * to recalculate it than toggling modes. */
+static void SCULPT_OT_optimize(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Rebuild BVH";
+ ot->idname = "SCULPT_OT_optimize";
+ ot->description = "Recalculate the sculpt BVH to improve performance";
+
+ /* API callbacks. */
+ ot->exec = sculpt_optimize_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************* Dynamic topology symmetrize ********************/
+
+static bool sculpt_no_multires_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) {
+ return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS;
+ }
+ return false;
+}
+
+static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ss->pbvh;
+ const float dist = RNA_float_get(op->ptr, "merge_tolerance");
+
+ if (!pbvh) {
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (BKE_pbvh_type(pbvh)) {
+ case PBVH_BMESH:
+ /* Dyntopo Symmetrize. */
+
+ /* To simplify undo for symmetrize, all BMesh elements are logged
+ * as deleted, then after symmetrize operation all BMesh elements
+ * are logged as added (as opposed to attempting to store just the
+ * parts that symmetrize modifies). */
+ SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize");
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
+ BM_log_before_all_removed(ss->bm, ss->bm_log);
+
+ BM_mesh_toolflags_set(ss->bm, true);
+
+ /* Symmetrize and re-triangulate. */
+ BMO_op_callf(ss->bm,
+ (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+ "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b",
+ sd->symmetrize_direction,
+ dist,
+ true);
+ SCULPT_dynamic_topology_triangulate(ss->bm);
+
+ /* Bisect operator flags edges (keep tags clean for edge queue). */
+ BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+
+ BM_mesh_toolflags_set(ss->bm, false);
+
+ /* Finish undo. */
+ BM_log_all_added(ss->bm, ss->bm_log);
+ SCULPT_undo_push_end();
+
+ break;
+ case PBVH_FACES:
+ /* Mesh Symmetrize. */
+ ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize");
+ Mesh *mesh = ob->data;
+
+ BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist);
+
+ ED_sculpt_undo_geometry_end(ob);
+ BKE_mesh_calc_normals(ob->data);
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+
+ break;
+ case PBVH_GRIDS:
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Redraw. */
+ SCULPT_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_symmetrize(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Symmetrize";
+ ot->idname = "SCULPT_OT_symmetrize";
+ ot->description = "Symmetrize the topology modifications";
+
+ /* API callbacks. */
+ ot->exec = sculpt_symmetrize_exec;
+ ot->poll = sculpt_no_multires_poll;
+
+ RNA_def_float(ot->srna,
+ "merge_tolerance",
+ 0.001f,
+ 0.0f,
+ FLT_MAX,
+ "Merge Distance",
+ "Distance within which symmetrical vertices are merged",
+ 0.0f,
+ 1.0f);
+}
+
+/**** Toggle operator for turning sculpt mode on or off ****/
+
+static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ /* Create persistent sculpt mode data. */
+ BKE_sculpt_toolsettings_data_ensure(scene);
+
+ /* Create sculpt mode session data. */
+ if (ob->sculpt != NULL) {
+ BKE_sculptsession_free(ob);
+ }
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+ ob->sculpt->mode_type = OB_MODE_SCULPT;
+
+ BKE_sculpt_ensure_orig_mesh_data(scene, ob);
+
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+
+ /* This function expects a fully evaluated depsgraph. */
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
+
+ /* Here we can detect geometry that was just added to Sculpt Mode as it has the
+ * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
+ /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
+ * initialized, which is used is some operators that modify the mesh topology to perform certain
+ * actions in the new polys. After these operations are finished, all polys should have a valid
+ * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility
+ * correctly. */
+ /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new
+ * objects, like moving the transform pivot position to the new area or masking existing
+ * geometry. */
+ SculptSession *ss = ob->sculpt;
+ const int new_face_set = SCULPT_face_set_next_available_get(ss);
+ for (int i = 0; i < ss->totfaces; i++) {
+ if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) {
+ ss->face_sets[i] = new_face_set;
+ }
+ }
+}
+
+void ED_object_sculptmode_enter_ex(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const bool force_dyntopo,
+ ReportList *reports)
+{
+ const int mode_flag = OB_MODE_SCULPT;
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ /* Enter sculpt mode. */
+ ob->mode |= mode_flag;
+
+ sculpt_init_session(bmain, depsgraph, scene, ob);
+
+ if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f &&
+ fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) {
+ BKE_report(
+ reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable");
+ }
+ else if (is_negative_m4(ob->obmat)) {
+ BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable");
+ }
+
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
+ BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
+
+ paint_cursor_start(paint, SCULPT_mode_poll_view3d);
+
+ /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
+ * As long as no data was added that is not supported. */
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+
+ const char *message_unsupported = NULL;
+ if (me->totloop != me->totpoly * 3) {
+ message_unsupported = TIP_("non-triangle face");
+ }
+ else if (mmd != NULL) {
+ message_unsupported = TIP_("multi-res modifier");
+ }
+ else {
+ enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
+ if (flag == 0) {
+ /* pass */
+ }
+ else if (flag & DYNTOPO_WARN_VDATA) {
+ message_unsupported = TIP_("vertex data");
+ }
+ else if (flag & DYNTOPO_WARN_EDATA) {
+ message_unsupported = TIP_("edge data");
+ }
+ else if (flag & DYNTOPO_WARN_LDATA) {
+ message_unsupported = TIP_("face data");
+ }
+ else if (flag & DYNTOPO_WARN_MODIFIER) {
+ message_unsupported = TIP_("constructive modifier");
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if ((message_unsupported == NULL) || force_dyntopo) {
+ /* Needed because we may be entering this mode before the undo system loads. */
+ wmWindowManager *wm = bmain->wm.first;
+ bool has_undo = wm->undo_stack != NULL;
+ /* Undo push is needed to prevent memory leak. */
+ if (has_undo) {
+ SCULPT_undo_push_begin(ob, "Dynamic topology enable");
+ }
+ SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
+ if (has_undo) {
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ SCULPT_undo_push_end();
+ }
+ }
+ else {
+ BKE_reportf(
+ reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported);
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+ }
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports);
+}
+
+void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ const int mode_flag = OB_MODE_SCULPT;
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ multires_flush_sculpt_updates(ob);
+
+ /* Not needed for now. */
+#if 0
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+ const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
+#endif
+
+ /* Always for now, so leaving sculpt mode always ensures scene is in
+ * a consistent state. */
+ if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ /* Dynamic topology must be disabled before exiting sculpt
+ * mode to ensure the undo stack stays in a consistent
+ * state. */
+ sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
+
+ /* Store so we know to re-enable when entering sculpt mode. */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+
+ /* Leave sculpt mode. */
+ ob->mode &= ~mode_flag;
+
+ BKE_sculptsession_free(ob);
+
+ paint_cursor_delete_textures();
+
+ /* Never leave derived meshes behind. */
+ BKE_object_free_derived_caches(ob);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
+}
+
+static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
+{
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ const int mode_flag = OB_MODE_SCULPT;
+ const bool is_mode_set = (ob->mode & mode_flag) != 0;
+
+ if (!is_mode_set) {
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (is_mode_set) {
+ ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
+ }
+ else {
+ if (depsgraph) {
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ }
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint);
+
+ if (ob->mode & mode_flag) {
+ Mesh *me = ob->data;
+ /* Dyntopo adds its own undo step. */
+ if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) {
+ /* Without this the memfile undo step is used,
+ * while it works it causes lag when undoing the first undo step, see T71564. */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->op_undo_depth <= 1) {
+ SCULPT_undo_push_begin(ob, op->type->name);
+ }
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+
+ WM_toolsystem_update_from_context_view3d(C);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Sculpt Mode";
+ ot->idname = "SCULPT_OT_sculptmode_toggle";
+ ot->description = "Toggle sculpt mode in 3D view";
+
+ /* API callbacks. */
+ ot->exec = sculpt_mode_toggle_exec;
+ ot->poll = ED_operator_object_active_editable_mesh;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+
+ ss->preview_vert_index_count = 0;
+ int totpoints = 0;
+
+ /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */
+ if (!ss->pbvh) {
+ return;
+ }
+
+ if (!ss->deform_modifiers_active) {
+ return;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+
+ if (!ss->pmap) {
+ return;
+ }
+
+ float brush_co[3];
+ copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));
+
+ BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
+
+ /* Assuming an average of 6 edges per vertex in a triangulated mesh. */
+ const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
+
+ if (ss->preview_vert_index_list == NULL) {
+ ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
+ }
+
+ GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
+ int active_v = SCULPT_active_vertex_get(ss);
+ BLI_gsqueue_push(not_visited_vertices, &active_v);
+
+ while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
+ int from_v;
+ BLI_gsqueue_pop(not_visited_vertices, &from_v);
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
+ if (totpoints + (ni.size * 2) < max_preview_vertices) {
+ int to_v = ni.index;
+ ss->preview_vert_index_list[totpoints] = from_v;
+ totpoints++;
+ ss->preview_vert_index_list[totpoints] = to_v;
+ totpoints++;
+ if (BLI_BITMAP_TEST(visited_vertices, to_v)) {
+ continue;
+ }
+ BLI_BITMAP_ENABLE(visited_vertices, to_v);
+ const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
+ if (len_squared_v3v3(brush_co, co) < radius * radius) {
+ BLI_gsqueue_push(not_visited_vertices, &to_v);
+ }
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ }
+
+ BLI_gsqueue_free(not_visited_vertices);
+
+ MEM_freeN(visited_vertices);
+
+ ss->preview_vert_index_count = totpoints;
+}
+
+static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ ID *data;
+ data = ob->data;
+ if (data && ID_IS_LINKED(data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ob->type != OB_MESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Mesh *mesh = ob->data;
+
+ const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
+ if (mloopcol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
+
+ const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
+ if (MPropCol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
+
+ MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
+ MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
+
+ for (int i = 0; i < mesh->totpoly; i++) {
+ MPoly *c_poly = &polys[i];
+ for (int j = 0; j < c_poly->totloop; j++) {
+ int loop_index = c_poly->loopstart + j;
+ MLoop *c_loop = &loops[c_poly->loopstart + j];
+ float srgb_color[4];
+ linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color);
+ loopcols[loop_index].r = (char)(srgb_color[0] * 255);
+ loopcols[loop_index].g = (char)(srgb_color[1] * 255);
+ loopcols[loop_index].b = (char)(srgb_color[2] * 255);
+ loopcols[loop_index].a = (char)(srgb_color[3] * 255);
+ }
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sculpt Vertex Color to Vertex Color";
+ ot->description = "Copy the Sculpt Vertex Color to a regular color layer";
+ ot->idname = "SCULPT_OT_vertex_to_loop_colors";
+
+ /* api callbacks */
+ ot->poll = SCULPT_vertex_colors_poll;
+ ot->exec = vertex_to_loop_colors_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ ID *data;
+ data = ob->data;
+ if (data && ID_IS_LINKED(data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ob->type != OB_MESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Mesh *mesh = ob->data;
+
+ const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
+ if (mloopcol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
+
+ const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
+ if (MPropCol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
+
+ MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
+ MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
+
+ for (int i = 0; i < mesh->totpoly; i++) {
+ MPoly *c_poly = &polys[i];
+ for (int j = 0; j < c_poly->totloop; j++) {
+ int loop_index = c_poly->loopstart + j;
+ MLoop *c_loop = &loops[c_poly->loopstart + j];
+ vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f);
+ vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f);
+ vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f);
+ vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f);
+ srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color);
+ }
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Color to Sculpt Vertex Color";
+ ot->description = "Copy the active loop color layer to the vertex color";
+ ot->idname = "SCULPT_OT_loop_to_vertex_colors";
+
+ /* api callbacks */
+ ot->poll = SCULPT_vertex_colors_poll;
+ ot->exec = loop_to_vertex_colors_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int sculpt_sample_color_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(e))
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ int active_vertex = SCULPT_active_vertex_get(ss);
+ const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex);
+ if (!active_vertex_color) {
+ return OPERATOR_CANCELLED;
+ }
+
+ float color_srgb[3];
+ copy_v3_v3(color_srgb, active_vertex_color);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
+ BKE_brush_color_set(scene, brush, color_srgb);
+
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_sample_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sample Color";
+ ot->idname = "SCULPT_OT_sample_color";
+ ot->description = "Sample the vertex color of the active vertex";
+
+ /* api callbacks */
+ ot->invoke = sculpt_sample_color_invoke;
+ ot->poll = SCULPT_vertex_colors_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/**
+ * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the
+ * mask based on the difference between two colors (the active color and the color of any other
+ * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active
+ * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer
+ * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between
+ * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going
+ * to be.
+ */
+#define MASK_BY_COLOR_SLOPE 0.25f
+
+static float sculpt_mask_by_color_delta_get(const float *color_a,
+ const float *color_b,
+ const float threshold,
+ const bool invert)
+{
+ float len = len_v3v3(color_a, color_b);
+ /* Normalize len to the (0, 1) range. */
+ len = len / M_SQRT3;
+
+ if (len < threshold - MASK_BY_COLOR_SLOPE) {
+ len = 1.0f;
+ }
+ else if (len >= threshold) {
+ len = 0.0f;
+ }
+ else {
+ len = (-len + threshold) / MASK_BY_COLOR_SLOPE;
+ }
+
+ if (invert) {
+ return 1.0f - len;
+ }
+ return len;
+}
+
+static float sculpt_mask_by_color_final_mask_get(const float current_mask,
+ const float new_mask,
+ const bool invert,
+ const bool preserve_mask)
+{
+ if (preserve_mask) {
+ if (invert) {
+ return min_ff(current_mask, new_mask);
+ }
+ return max_ff(current_mask, new_mask);
+ }
+ return new_mask;
+}
+
+typedef struct MaskByColorContiguousFloodFillData {
+ float threshold;
+ bool invert;
+ float *new_mask;
+ float initial_color[3];
+} MaskByColorContiguousFloodFillData;
+
+static void do_mask_by_color_contiguous_update_nodes_cb(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
+ bool update_node = false;
+
+ const bool invert = data->mask_by_color_invert;
+ const bool preserve_mask = data->mask_by_color_preserve_mask;
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ const float current_mask = *vd.mask;
+ const float new_mask = data->mask_by_color_floodfill[vd.index];
+ *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
+ if (current_mask == *vd.mask) {
+ continue;
+ }
+ update_node = true;
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ if (update_node) {
+ BKE_pbvh_node_mark_redraw(data->nodes[n]);
+ }
+}
+
+static bool sculpt_mask_by_color_contiguous_floodfill_cb(
+ SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+{
+ MaskByColorContiguousFloodFillData *data = userdata;
+ const float *current_color = SCULPT_vertex_color_get(ss, to_v);
+ float new_vertex_mask = sculpt_mask_by_color_delta_get(
+ current_color, data->initial_color, data->threshold, data->invert);
+ data->new_mask[to_v] = new_vertex_mask;
+
+ if (is_duplicate) {
+ data->new_mask[to_v] = data->new_mask[from_v];
+ }
+
+ float len = len_v3v3(current_color, data->initial_color);
+ len = len / M_SQRT3;
+ return len <= data->threshold;
+}
+
+static void sculpt_mask_by_color_contiguous(Object *object,
+ const int vertex,
+ const float threshold,
+ const bool invert,
+ const bool preserve_mask)
+{
+ SculptSession *ss = object->sculpt;
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask");
+
+ if (invert) {
+ for (int i = 0; i < totvert; i++) {
+ new_mask[i] = 1.0f;
+ }
+ }
+
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_initial(&flood, vertex);
+
+ MaskByColorContiguousFloodFillData ffd;
+ ffd.threshold = threshold;
+ ffd.invert = invert;
+ ffd.new_mask = new_mask;
+ copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex));
+
+ SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd);
+ SCULPT_floodfill_free(&flood);
+
+ int totnode;
+ PBVHNode **nodes;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ SculptThreadedTaskData data = {
+ .ob = object,
+ .nodes = nodes,
+ .mask_by_color_floodfill = new_mask,
+ .mask_by_color_vertex = vertex,
+ .mask_by_color_threshold = threshold,
+ .mask_by_color_invert = invert,
+ .mask_by_color_preserve_mask = preserve_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(
+ 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+
+ MEM_freeN(new_mask);
+}
+
+static void do_mask_by_color_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
+ bool update_node = false;
+
+ const float threshold = data->mask_by_color_threshold;
+ const bool invert = data->mask_by_color_invert;
+ const bool preserve_mask = data->mask_by_color_preserve_mask;
+ const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ const float current_mask = *vd.mask;
+ const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert);
+ *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
+
+ if (current_mask == *vd.mask) {
+ continue;
+ }
+ update_node = true;
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ if (update_node) {
+ BKE_pbvh_node_mark_redraw(data->nodes[n]);
+ }
+}
+
+static void sculpt_mask_by_color_full_mesh(Object *object,
+ const int vertex,
+ const float threshold,
+ const bool invert,
+ const bool preserve_mask)
+{
+ SculptSession *ss = object->sculpt;
+
+ int totnode;
+ PBVHNode **nodes;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ SculptThreadedTaskData data = {
+ .ob = object,
+ .nodes = nodes,
+ .mask_by_color_vertex = vertex,
+ .mask_by_color_threshold = threshold,
+ .mask_by_color_invert = invert,
+ .mask_by_color_preserve_mask = preserve_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+}
+
+static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+
+ /* Color data is not available in Multires. */
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!ss->vcol) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_vertex_random_access_ensure(ss);
+
+ /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
+ * so it needs to be updated here. */
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+
+ SCULPT_undo_push_begin(ob, "Mask by color");
+
+ const int active_vertex = SCULPT_active_vertex_get(ss);
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const bool invert = RNA_boolean_get(op->ptr, "invert");
+ const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
+
+ if (RNA_boolean_get(op->ptr, "contiguous")) {
+ sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask);
+ }
+ else {
+ sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask);
+ }
+
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
+ SCULPT_undo_push_end();
+
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mask by Color";
+ ot->idname = "SCULPT_OT_mask_by_color";
+ ot->description = "Creates a mask based on the sculpt vertex colors";
+
+ /* api callbacks */
+ ot->invoke = sculpt_mask_by_color_invoke;
+ ot->poll = SCULPT_vertex_colors_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ ot->prop = RNA_def_boolean(
+ ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas");
+
+ ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask");
+ ot->prop = RNA_def_boolean(
+ ot->srna,
+ "preserve_previous_mask",
+ false,
+ "Preserve Previous Mask",
+ "Preserve the previous mask and add or subtract the new one generated by the colors");
+
+ RNA_def_float(ot->srna,
+ "threshold",
+ 0.35f,
+ 0.0f,
+ 1.0f,
+ "Threshold",
+ "How much changes in color affect the mask generation",
+ 0.0f,
+ 1.0f);
+}
+
+void ED_operatortypes_sculpt(void)
+{
+ WM_operatortype_append(SCULPT_OT_brush_stroke);
+ WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
+ WM_operatortype_append(SCULPT_OT_set_persistent_base);
+ WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
+ WM_operatortype_append(SCULPT_OT_optimize);
+ WM_operatortype_append(SCULPT_OT_symmetrize);
+ WM_operatortype_append(SCULPT_OT_detail_flood_fill);
+ WM_operatortype_append(SCULPT_OT_sample_detail_size);
+ WM_operatortype_append(SCULPT_OT_set_detail_size);
+ WM_operatortype_append(SCULPT_OT_mesh_filter);
+ WM_operatortype_append(SCULPT_OT_mask_filter);
+ WM_operatortype_append(SCULPT_OT_dirty_mask);
+ WM_operatortype_append(SCULPT_OT_mask_expand);
+ WM_operatortype_append(SCULPT_OT_set_pivot_position);
+ WM_operatortype_append(SCULPT_OT_face_sets_create);
+ WM_operatortype_append(SCULPT_OT_face_sets_change_visibility);
+ WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
+ WM_operatortype_append(SCULPT_OT_face_sets_init);
+ WM_operatortype_append(SCULPT_OT_cloth_filter);
+ WM_operatortype_append(SCULPT_OT_face_sets_edit);
+ WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture);
+ WM_operatortype_append(SCULPT_OT_face_set_box_gesture);
+ WM_operatortype_append(SCULPT_OT_trim_box_gesture);
+ WM_operatortype_append(SCULPT_OT_trim_lasso_gesture);
+ WM_operatortype_append(SCULPT_OT_project_line_gesture);
+
+ WM_operatortype_append(SCULPT_OT_sample_color);
+ WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
+ WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors);
+ WM_operatortype_append(SCULPT_OT_color_filter);
+ WM_operatortype_append(SCULPT_OT_mask_by_color);
+ WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit);
+ WM_operatortype_append(SCULPT_OT_mask_init);
+
+ WM_operatortype_append(SCULPT_OT_expand);
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 847f42fe9e8..c65489548b7 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -538,13 +538,6 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
-
- if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
- BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL);
- ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
- sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b");
- }
/* Threaded loop over nodes. */
SculptThreadedTaskData data = {
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index bfbe545d1ef..b91e05f226e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -70,10 +70,6 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob)
copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot);
copy_v3_v3(ss->init_pivot_scale, ss->pivot_scale);
- copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos);
- copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot);
- copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale);
-
SCULPT_undo_push_begin(ob, "Transform");
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
@@ -81,13 +77,10 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob)
SCULPT_vertex_random_access_ensure(ss);
SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS);
-
- ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL;
}
static void sculpt_transform_matrices_init(SculptSession *ss,
const char symm,
- const SculptTransformDisplacementMode t_mode,
float r_transform_mats[8][4][4])
{
@@ -96,18 +89,9 @@ static void sculpt_transform_matrices_init(SculptSession *ss,
transform_mat[4][4];
float start_pivot_pos[3], start_pivot_rot[4], start_pivot_scale[3];
- switch (t_mode) {
- case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL:
- copy_v3_v3(start_pivot_pos, ss->init_pivot_pos);
- copy_v4_v4(start_pivot_rot, ss->init_pivot_rot);
- copy_v3_v3(start_pivot_scale, ss->init_pivot_scale);
- break;
- case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL:
- copy_v3_v3(start_pivot_pos, ss->prev_pivot_pos);
- copy_v4_v4(start_pivot_rot, ss->prev_pivot_rot);
- copy_v3_v3(start_pivot_scale, ss->prev_pivot_scale);
- break;
- }
+ copy_v3_v3(start_pivot_pos, ss->init_pivot_pos);
+ copy_v4_v4(start_pivot_rot, ss->init_pivot_rot);
+ copy_v3_v3(start_pivot_scale, ss->init_pivot_scale);
for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
ePaintSymmetryAreas v_symm = i;
@@ -167,25 +151,15 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
float transformed_co[3], orig_co[3], disp[3];
- float *start_co;
float fade = vd.mask ? *vd.mask : 0.0f;
copy_v3_v3(orig_co, orig_data.co);
char symm_area = SCULPT_get_vertex_symm_area(orig_co);
- switch (ss->filter_cache->transform_displacement_mode) {
- case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL:
- start_co = orig_co;
- break;
- case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL:
- start_co = vd.co;
- break;
- }
-
- copy_v3_v3(transformed_co, start_co);
+ copy_v3_v3(transformed_co, orig_co);
mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
- sub_v3_v3v3(disp, transformed_co, start_co);
+ sub_v3_v3v3(disp, transformed_co, orig_co);
mul_v3_fl(disp, 1.0f - fade);
- add_v3_v3v3(vd.co, start_co, disp);
+ add_v3_v3v3(vd.co, orig_co, disp);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@@ -207,8 +181,7 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob)
.nodes = ss->filter_cache->nodes,
};
- sculpt_transform_matrices_init(
- ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats);
+ sculpt_transform_matrices_init(ss, symm, data.transform_mats);
/* Regular transform applies all symmetry passes at once as it is split by symmetry areas
* (each vertex can only be transformed once by the transform matrix of its area). */
@@ -229,10 +202,6 @@ void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob)
sculpt_transform_all_vertices(sd, ob);
- copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos);
- copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot);
- copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale);
-
if (ss->deform_modifiers_active || ss->shapekey_active) {
SCULPT_flush_stroke_deform(sd, ob, true);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 4a88b75cf25..8819496c168 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1107,10 +1107,10 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) {
copy_v3_v3(unode->co[vd.i], vd.co);
if (vd.no) {
- copy_v3_v3_short(unode->no[vd.i], vd.no);
+ copy_v3_v3(unode->no[vd.i], vd.no);
}
else {
- normal_float_to_short_v3(unode->no[vd.i], vd.fno);
+ copy_v3_v3(unode->no[vd.i], vd.fno);
}
if (ss->deform_modifiers_active) {
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index f68446b1cae..184d715a347 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -642,6 +642,10 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
}
}
+ /* Grease Pencil needs extra update to refresh the added keyframes. */
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ }
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 4463856f40a..ba96ac52f1f 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -36,6 +36,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_nla.h"
#include "BKE_screen.h"
@@ -814,20 +815,15 @@ static void action_refresh(const bContext *C, ScrArea *area)
/* XXX re-sizing y-extents of tot should go here? */
}
-static void action_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void action_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceAction *sact = (SpaceAction *)slink;
- if ((ID *)sact->action == old_id) {
- sact->action = (bAction *)new_id;
- }
-
- if ((ID *)sact->ads.filter_grp == old_id) {
- sact->ads.filter_grp = (Collection *)new_id;
- }
- if ((ID *)sact->ads.source == old_id) {
- sact->ads.source = new_id;
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sact->action, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&sact->ads.filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, &sact->ads.source, ID_REMAP_APPLY_DEFAULT);
}
/**
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 035bc7e297d..f8adba30547 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -72,7 +72,7 @@
void ED_spacetypes_init(void)
{
- /* UI unit is a variable, may be used in some space type inits. */
+ /* UI unit is a variable, may be used in some space type initialization. */
U.widget_unit = 20;
/* Create space types. */
@@ -248,15 +248,16 @@ void *ED_region_draw_cb_activate(ARegionType *art,
return rdc;
}
-void ED_region_draw_cb_exit(ARegionType *art, void *handle)
+bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
{
LISTBASE_FOREACH (RegionDrawCB *, rdc, &art->drawcalls) {
if (rdc == (RegionDrawCB *)handle) {
BLI_remlink(&art->drawcalls, rdc);
MEM_freeN(rdc);
- return;
+ return true;
}
}
+ return false;
}
static void ed_region_draw_cb_draw(const bContext *C, ARegion *region, ARegionType *art, int type)
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 554edf680be..5dd7c3d240e 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -155,10 +155,10 @@ static void buttons_texture_users_find_nodetree(ListBase *users,
for (node = ntree->nodes.first; node; node = node->next) {
if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
PointerRNA ptr;
- /* PropertyRNA *prop; */ /* UNUSED */
+ // PropertyRNA *prop; /* UNUSED */
RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
- /* prop = RNA_struct_find_property(&ptr, "texture"); */ /* UNUSED */
+ // prop = RNA_struct_find_property(&ptr, "texture"); /* UNUSED */
buttons_texture_user_node_add(
users, id, ntree, node, category, RNA_struct_ui_icon(ptr.type), node->name);
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 007a9105c76..cf1e7788ff8 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -32,6 +32,7 @@
#include "BKE_context.h"
#include "BKE_gpencil_modifier.h" /* Types for registering panels. */
+#include "BKE_lib_remap.h"
#include "BKE_modifier.h"
#include "BKE_screen.h"
#include "BKE_shader_fx.h"
@@ -860,54 +861,53 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
}
}
-static void buttons_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void buttons_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceProperties *sbuts = (SpaceProperties *)slink;
- if (sbuts->pinid == old_id) {
- sbuts->pinid = new_id;
- if (new_id == NULL) {
- sbuts->flag &= ~SB_PIN_CONTEXT;
- }
+ if (BKE_id_remapper_apply(mappings, &sbuts->pinid, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ sbuts->flag &= ~SB_PIN_CONTEXT;
}
if (sbuts->path) {
ButsContextPath *path = sbuts->path;
+ for (int i = 0; i < path->len; i++) {
+ switch (BKE_id_remapper_apply(mappings, &path->ptr[i].owner_id, ID_REMAP_APPLY_DEFAULT)) {
+ case ID_REMAP_RESULT_SOURCE_UNASSIGNED: {
+ if (i == 0) {
+ MEM_SAFE_FREE(sbuts->path);
+ }
+ else {
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ }
+ break;
+ }
+ case ID_REMAP_RESULT_SOURCE_REMAPPED: {
+ RNA_id_pointer_create(path->ptr[i].owner_id, &path->ptr[i]);
+ /* There is no easy way to check/make path downwards valid, just nullify it.
+ * Next redraw will rebuild this anyway. */
+ i++;
+ memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
+ path->len = i;
+ break;
+ }
- int i;
- for (i = 0; i < path->len; i++) {
- if (path->ptr[i].owner_id == old_id) {
- break;
- }
- }
-
- if (i == path->len) {
- /* pass */
- }
- else if (new_id == NULL) {
- if (i == 0) {
- MEM_SAFE_FREE(sbuts->path);
- }
- else {
- memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
- path->len = i;
+ case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE:
+ case ID_REMAP_RESULT_SOURCE_UNAVAILABLE: {
+ /* Nothing to do. */
+ break;
+ }
}
}
- else {
- RNA_id_pointer_create(new_id, &path->ptr[i]);
- /* There is no easy way to check/make path downwards valid, just nullify it.
- * Next redraw will rebuild this anyway. */
- i++;
- memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
- path->len = i;
- }
}
if (sbuts->texuser) {
ButsContextTexture *ct = sbuts->texuser;
- if ((ID *)ct->texture == old_id) {
- ct->texture = (Tex *)new_id;
- }
+ BKE_id_remapper_apply(mappings, (ID **)&ct->texture, ID_REMAP_APPLY_DEFAULT);
BLI_freelistN(&ct->users);
ct->user = NULL;
}
diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt
index 8c7f59d61dd..db881dafa6b 100644
--- a/source/blender/editors/space_clip/CMakeLists.txt
+++ b/source/blender/editors/space_clip/CMakeLists.txt
@@ -31,6 +31,9 @@ set(INC
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
)
set(SRC
@@ -69,4 +72,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+
blender_add_lib(bf_editor_space_clip "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_editor_space_clip bf_dna)
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 5a999b1fad7..d22e4864ecf 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_mask_types.h"
#include "BLI_fileops.h"
@@ -646,7 +647,7 @@ void ED_space_clip_set_mask(bContext *C, SpaceClip *sc, Mask *mask)
* \{ */
typedef struct PrefetchJob {
- /* Clip into which cache the frames will be prefetched into. */
+ /** Clip into which cache the frames will be pre-fetched into. */
MovieClip *clip;
/* Local copy of the clip which is used to decouple reading in a way which does not require
@@ -686,7 +687,7 @@ static bool check_prefetch_break(void)
static uchar *prefetch_read_file_to_memory(
MovieClip *clip, int current_frame, short render_size, short render_flag, size_t *r_size)
{
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
user.framenr = current_frame;
user.render_size = render_size;
user.render_flag = render_flag;
@@ -733,7 +734,7 @@ static int prefetch_find_uncached_frame(MovieClip *clip,
short direction)
{
int current_frame;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
user.render_size = render_size;
user.render_flag = render_flag;
@@ -833,7 +834,7 @@ static void prefetch_task_func(TaskPool *__restrict pool, void *task_data)
while ((mem = prefetch_thread_next_frame(queue, clip, &size, &current_frame))) {
ImBuf *ibuf;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
int flag = IB_rect | IB_multilayer | IB_alphamode_detect | IB_metadata;
int result;
char *colorspace_name = NULL;
@@ -915,7 +916,7 @@ static bool prefetch_movie_frame(MovieClip *clip,
short render_flag,
short *stop)
{
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
if (check_prefetch_break() || *stop) {
return false;
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 20cc6e3da15..15f905f3157 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -184,7 +184,7 @@ void clip_delete_plane_track(struct bContext *C,
* 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);
+ SpaceClip *sc, float x, float y, float *r_offset_x, float *r_offset_y);
void clip_view_center_to_point(SpaceClip *sc, float x, float y);
bool clip_view_calculate_view_selection(
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 0aa7e35aed6..03b6d8c7381 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_scene_types.h" /* min/max frames */
#include "DNA_userdef_types.h"
@@ -1321,7 +1322,7 @@ static uchar *proxy_thread_next_frame(ProxyQueue *queue,
BLI_spin_lock(&queue->spin);
if (!*queue->stop && queue->cfra <= queue->efra) {
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
char name[FILE_MAX];
size_t size;
int file;
@@ -1559,7 +1560,8 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
clip->proxy.build_size_flag,
clip->proxy.quality,
true,
- NULL);
+ NULL,
+ false);
}
WM_jobs_customdata_set(wm_job, pj, proxy_freejob);
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 91083fa9682..da1d2dea653 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -24,6 +24,8 @@
#include <stdio.h>
#include <string.h>
+#include "DNA_defaults.h"
+
#include "DNA_mask_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_scene_types.h"
@@ -37,6 +39,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_movieclip.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
@@ -239,14 +242,7 @@ static SpaceLink *clip_create(const ScrArea *area, const Scene *scene)
ARegion *region;
SpaceClip *sc;
- sc = MEM_callocN(sizeof(SpaceClip), "initclip");
- sc->spacetype = SPACE_CLIP;
- sc->flag = SC_SHOW_MARKER_PATTERN | SC_SHOW_TRACK_PATH | SC_SHOW_GRAPH_TRACKS_MOTION |
- SC_SHOW_GRAPH_FRAMES | SC_SHOW_ANNOTATION;
- sc->zoom = 1.0f;
- sc->path_length = 20;
- sc->scopes.track_preview_height = 120;
- sc->around = V3D_AROUND_CENTER_MEDIAN;
+ sc = DNA_struct_default_alloc(SpaceClip);
/* header */
region = MEM_callocN(sizeof(ARegion), "header for clip");
@@ -1079,6 +1075,9 @@ static void graph_region_draw(const bContext *C, ARegion *region)
/* time-scrubbing */
ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true);
+ /* current frame indicator */
+ ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS);
+
/* scrollers */
UI_view2d_scrollers_draw(v2d, NULL);
@@ -1126,6 +1125,9 @@ static void dopesheet_region_draw(const bContext *C, ARegion *region)
/* time-scrubbing */
ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true);
+ /* current frame indicator */
+ ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS);
+
/* scrollers */
UI_view2d_scrollers_draw(v2d, NULL);
}
@@ -1316,23 +1318,18 @@ static void clip_properties_region_listener(const wmRegionListenerParams *params
/********************* registration ********************/
-static void clip_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void clip_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceClip *sclip = (SpaceClip *)slink;
- if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) {
+ if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_MC | FILTER_ID_MSK)) {
return;
}
- if ((ID *)sclip->clip == old_id) {
- sclip->clip = (MovieClip *)new_id;
- id_us_ensure_real(new_id);
- }
-
- if ((ID *)sclip->mask_info.mask == old_id) {
- sclip->mask_info.mask = (Mask *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sclip->clip, ID_REMAP_APPLY_ENSURE_REAL);
+ BKE_id_remapper_apply(mappings, (ID **)&sclip->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
}
void ED_spacetype_clip(void)
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index 1651269869e..cbeb2e6f529 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -16,8 +16,8 @@
# ***** END GPL LICENSE BLOCK *****
set(INC
- ../include
../asset
+ ../include
../../blenfont
../../blenkernel
../../blenlib
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
index 86c4b78dea4..4107669630f 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -325,7 +325,7 @@ void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column)
/* Doesn't actually exist right now, but could be defined in Python. Reason that this isn't done
* in Python yet is that catalogs are not exposed in BPY, and we'd somehow pass the clicked on
- * catalog to the menu draw callback (via context probably).*/
+ * catalog to the menu draw callback (via context probably). */
MenuType *mt = WM_menutype_find("ASSETBROWSER_MT_catalog_context_menu", true);
if (!mt) {
return;
@@ -679,7 +679,7 @@ using namespace blender::ed::asset_browser;
FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings()
{
- AssetCatalogFilterSettings *filter_settings = OBJECT_GUARDED_NEW(AssetCatalogFilterSettings);
+ AssetCatalogFilterSettings *filter_settings = MEM_new<AssetCatalogFilterSettings>(__func__);
return reinterpret_cast<FileAssetCatalogFilterSettingsHandle *>(filter_settings);
}
@@ -688,7 +688,8 @@ void file_delete_asset_catalog_filter_settings(
{
AssetCatalogFilterSettings **filter_settings = reinterpret_cast<AssetCatalogFilterSettings **>(
filter_settings_handle);
- OBJECT_GUARDED_SAFE_DELETE(*filter_settings, AssetCatalogFilterSettings);
+ MEM_delete(*filter_settings);
+ *filter_settings = nullptr;
}
bool file_set_asset_catalog_filter_settings(
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 44e9735866d..14c786e5dea 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -240,6 +240,7 @@ static void file_draw_string(int sx,
UI_fontstyle_draw(&fs,
&rect,
fname,
+ sizeof(fname),
col,
&(struct uiFontStyleDraw_Params){
.align = align,
@@ -289,12 +290,12 @@ static void file_draw_string_multiline(int sx,
UI_fontstyle_draw_ex(&style->widget,
&rect,
string,
+ len,
text_col,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_LEFT,
.word_wrap = true,
},
- len,
NULL,
NULL,
&result);
@@ -402,19 +403,19 @@ static void file_draw_preview(const SpaceFile *sfile,
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTexScaled(&state,
- (float)xco,
- (float)yco,
- imb->x,
- imb->y,
- GPU_RGBA8,
- true,
- imb->rect,
- scale,
- scale,
- 1.0f,
- 1.0f,
- col);
+ immDrawPixelsTexTiled_scaling(&state,
+ (float)xco,
+ (float)yco,
+ imb->x,
+ imb->y,
+ GPU_RGBA8,
+ true,
+ imb->rect,
+ scale,
+ scale,
+ 1.0f,
+ 1.0f,
+ col);
GPU_blend(GPU_BLEND_ALPHA);
@@ -905,7 +906,8 @@ void file_draw_list(const bContext *C, ARegion *region)
* since it's filelist_file_cache_block() and filelist_cache_previews_update()
* which controls previews task. */
{
- const bool previews_running = filelist_cache_previews_running(files);
+ const bool previews_running = filelist_cache_previews_running(files) &&
+ !filelist_cache_previews_done(files);
// printf("%s: preview task: %d\n", __func__, previews_running);
if (previews_running && !sfile->previews_timer) {
sfile->previews_timer = WM_event_add_timer_notifier(
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 3fe48157a09..bd55e6f78ab 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -34,11 +34,11 @@ extern "C" {
struct ARegion;
struct ARegionType;
struct AssetLibrary;
-struct FileSelectParams;
struct FileAssetSelectParams;
+struct FileSelectParams;
struct SpaceFile;
-struct uiLayout;
struct View2D;
+struct uiLayout;
/* file_draw.c */
@@ -128,7 +128,7 @@ void fileselect_refresh_params(struct SpaceFile *sfile);
/**
* Sets #FileSelectParams.file (name of selected file)
*/
-void fileselect_file_set(SpaceFile *sfile, const int index);
+void fileselect_file_set(SpaceFile *sfile, int index);
bool file_attribute_column_type_enabled(const FileSelectParams *params,
FileAttributeColumnType column);
/**
@@ -204,7 +204,7 @@ 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);
+void file_tile_boundbox(const ARegion *region, FileLayout *layout, int file, rcti *r_bounds);
/**
* If \a path leads to a .blend, remove the trailing slash (if needed).
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 76a0e4f42e7..a1472a2c1b3 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -2463,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];
@@ -2623,7 +2624,8 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
matches = file_select_match(sfile, params->file, matched_file);
/* *After* file_select_match! */
- BLI_filename_make_safe(params->file);
+ const bool allow_tokens = (params->flag & FILE_PATH_TOKENS_ALLOW) != 0;
+ BLI_filename_make_safe_ex(params->file, allow_tokens);
if (matches) {
/* replace the pattern (or filename that the user typed in,
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index e4ea832fe2f..2d31e8030a4 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -339,7 +339,10 @@ typedef struct FileListEntryCache {
/* Previews handling. */
TaskPool *previews_pool;
ThreadQueue *previews_done;
- size_t previews_todo_count;
+ /** Counter for previews that are not fully loaded and ready to display yet. So includes all
+ * previews either in `previews_pool` or `previews_done`. #filelist_cache_previews_update() makes
+ * previews in `preview_done` ready for display, so the counter is decremented there. */
+ int previews_todo_count;
} FileListEntryCache;
/* FileListCache.flags */
@@ -852,7 +855,8 @@ static bool is_filtered_hidden(const char *filename,
/**
* Apply the filter string as file path matching pattern.
- * \return true when the file should be in the result set, false if it should be filtered out. */
+ * \return true when the file should be in the result set, false if it should be filtered out.
+ */
static bool is_filtered_file_relpath(const FileListInternEntry *file, const FileListFilter *filter)
{
if (filter->filter_search[0] == '\0') {
@@ -1646,7 +1650,6 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
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);
}
@@ -1688,6 +1691,7 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache)
}
MEM_freeN(preview);
}
+ cache->previews_todo_count = 0;
}
}
@@ -1758,7 +1762,6 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
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) {
@@ -1779,6 +1782,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
true,
filelist_cache_preview_freef);
}
+ cache->previews_todo_count++;
}
static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size)
@@ -1876,8 +1880,6 @@ FileList *filelist_new(short type)
p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET;
filelist_settype(p, type);
- p->indexer = &file_indexer_noop;
-
return p;
}
@@ -1889,6 +1891,7 @@ void filelist_settype(FileList *filelist, short type)
filelist->type = type;
filelist->tags = 0;
+ filelist->indexer = &file_indexer_noop;
switch (filelist->type) {
case FILE_MAIN:
filelist->check_dir_fn = filelist_checkdir_main;
@@ -2064,7 +2067,7 @@ static char *fileentry_uiname(const char *root,
BLI_join_dirfile(abspath, sizeof(abspath), root, relpath);
name = BLF_display_name_from_file(abspath);
if (name) {
- /* Allocated string, so no need to BLI_strdup.*/
+ /* Allocated string, so no need to #BLI_strdup. */
return name;
}
}
@@ -2693,6 +2696,7 @@ bool filelist_cache_previews_update(FileList *filelist)
}
MEM_freeN(preview);
+ cache->previews_todo_count--;
}
return changed;
@@ -2714,7 +2718,7 @@ bool filelist_cache_previews_done(FileList *filelist)
}
return (cache->previews_pool == NULL) || (cache->previews_done == NULL) ||
- (cache->previews_todo_count == (size_t)BLI_thread_queue_len(cache->previews_done));
+ (cache->previews_todo_count == 0);
}
/* would recognize .blend as well */
@@ -3661,7 +3665,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
list_lib_options |= LIST_LIB_RECURSIVE;
}
/* Only load assets when browsing an asset library. For normal file browsing we return all
- * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user.*/
+ * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user. */
if (filelist->asset_library_ref) {
list_lib_options |= LIST_LIB_ASSETS_ONLY;
}
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index 0119a9b4f52..696986d4660 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -62,16 +62,16 @@ void folder_history_list_ensure_for_active_browse_mode(struct SpaceFile *sfile);
void folder_history_list_free(struct SpaceFile *sfile);
struct ListBase folder_history_list_duplicate(struct ListBase *listbase);
-void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort);
+void filelist_setsorting(struct FileList *filelist, short sort, bool invert_sort);
void filelist_sort(struct FileList *filelist);
void filelist_setfilter_options(struct FileList *filelist,
- const bool do_filter,
- const bool hide_dot,
- const bool hide_parent,
- const uint64_t filter,
- const uint64_t filter_id,
- const bool filter_assets_only,
+ bool do_filter,
+ bool hide_dot,
+ bool hide_parent,
+ uint64_t filter,
+ uint64_t filter_id,
+ bool filter_assets_only,
const char *filter_glob,
const char *filter_search);
/**
@@ -98,19 +98,19 @@ void filelist_setlibrary(struct FileList *filelist,
void filelist_init_icons(void);
void filelist_free_icons(void);
-struct ImBuf *filelist_getimage(struct FileList *filelist, const int index);
+struct ImBuf *filelist_getimage(struct FileList *filelist, int index);
struct ImBuf *filelist_file_getimage(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image_ex(const FileDirEntry *file);
-struct ImBuf *filelist_geticon_image(struct FileList *filelist, const int index);
-int filelist_geticon(struct FileList *filelist, const int index, const bool is_main);
+struct ImBuf *filelist_geticon_image(struct FileList *filelist, int index);
+int filelist_geticon(struct FileList *filelist, int index, bool is_main);
struct FileList *filelist_new(short type);
void filelist_settype(struct FileList *filelist, short type);
void filelist_clear(struct FileList *filelist);
void filelist_clear_ex(struct FileList *filelist,
- const bool do_asset_library,
- const bool do_cache,
- const bool do_selection);
+ bool do_asset_library,
+ bool do_cache,
+ bool do_selection);
/**
* A "smarter" version of #filelist_clear() that calls partial clearing based on the filelist
* force-reset flags.
@@ -156,7 +156,7 @@ void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t win
/**
* 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_file_cache_block(struct FileList *filelist, int index);
bool filelist_needs_force_reset(struct FileList *filelist);
void filelist_tag_force_reset(struct FileList *filelist);
@@ -171,7 +171,7 @@ unsigned int filelist_entry_select_set(const struct FileList *filelist,
unsigned int flag,
FileCheckType check);
void filelist_entry_select_index_set(struct FileList *filelist,
- const int index,
+ int index,
FileSelType select,
unsigned int flag,
FileCheckType check);
@@ -184,9 +184,9 @@ unsigned int filelist_entry_select_get(struct FileList *filelist,
struct FileDirEntry *entry,
FileCheckType check);
unsigned int filelist_entry_select_index_get(struct FileList *filelist,
- const int index,
+ int index,
FileCheckType check);
-bool filelist_entry_is_selected(struct FileList *filelist, const int index);
+bool filelist_entry_is_selected(struct FileList *filelist, int index);
/**
* Set selection of the '..' parent entry, but only if it's actually visible.
*/
@@ -195,7 +195,7 @@ void filelist_entry_parent_select_set(struct FileList *filelist,
unsigned int flag,
FileCheckType check);
-void filelist_setrecursion(struct FileList *filelist, const int recursion_level);
+void filelist_setrecursion(struct FileList *filelist, int recursion_level);
struct AssetLibrary *filelist_asset_library(struct FileList *filelist);
@@ -213,7 +213,7 @@ void filelist_readjob_stop(struct FileList *filelist, struct wmWindowManager *wm
int filelist_readjob_running(struct FileList *filelist, struct wmWindowManager *wm);
bool filelist_cache_previews_update(struct FileList *filelist);
-void filelist_cache_previews_set(struct FileList *filelist, const bool use_previews);
+void filelist_cache_previews_set(struct FileList *filelist, bool use_previews);
bool filelist_cache_previews_running(struct FileList *filelist);
bool filelist_cache_previews_done(struct FileList *filelist);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index e3ac5840da3..f9783d1b19f 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -275,6 +275,9 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
if ((prop = RNA_struct_find_property(op->ptr, "filter_usd"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_USD : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_obj"))) {
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_OBJECT_IO : 0;
+ }
if ((prop = RNA_struct_find_property(op->ptr, "filter_volume"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_VOLUME : 0;
}
@@ -318,6 +321,10 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVE_COLLECTION : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "allow_path_tokens"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_PATH_TOKENS_ALLOW : 0;
+ }
+
if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) {
params->display = RNA_property_enum_get(op->ptr, prop);
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 97f22ca7d89..14f596ae7bf 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -185,8 +185,8 @@ static void fsmenu_xdg_user_dirs_free(GHash *xdg_map)
/**
* Add fsmenu entry for system folders on linux.
- * - Check if a path is stored in the GHash generated from user-dirs.dirs
- * - If not, check for a default path in $HOME
+ * - Check if a path is stored in the #GHash generated from `user-dirs.dirs`.
+ * - If not, check for a default path in `$HOME`.
*
* \param key: Use `user-dirs.dirs` format "XDG_EXAMPLE_DIR"
* \param default_path: Directory name to check in $HOME, also used for the menu entry name.
diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h
index 6296314d40a..0915c9a5a2f 100644
--- a/source/blender/editors/space_file/fsmenu.h
+++ b/source/blender/editors/space_file/fsmenu.h
@@ -42,7 +42,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
const char *path,
const char *name,
int icon,
- const enum FSMenuInsert flag);
+ enum FSMenuInsert flag);
/** Refresh 'valid' status of given menu entry */
void fsmenu_entry_refresh_valid(struct FSMenuEntry *fsentry);
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index bbf3c6f768c..470128f61bd 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -33,6 +33,7 @@
#include "BKE_appdir.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_screen.h"
@@ -57,14 +58,11 @@
#include "UI_view2d.h"
#include "GPU_framebuffer.h"
+#include "file_indexer.h"
#include "file_intern.h" /* own include */
#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;
@@ -359,11 +357,11 @@ 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);
+ const bool use_asset_indexer = !USER_EXPERIMENTAL_TEST(&U, no_asset_indexing);
+ filelist_setindexer(sfile->files,
+ use_asset_indexer ? &file_indexer_asset : &file_indexer_noop);
}
-#endif
/* Update the active indices of bookmarks & co. */
sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir);
@@ -992,7 +990,7 @@ static int /*eContextResult*/ file_context(const bContext *C,
return CTX_RESULT_MEMBER_NOT_FOUND;
}
-static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *UNUSED(new_id))
+static void file_id_remap(ScrArea *area, SpaceLink *sl, const struct IDRemapper *UNUSED(mappings))
{
SpaceFile *sfile = (SpaceFile *)sl;
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 2afee277847..9675901ead3 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -2353,6 +2353,103 @@ void GRAPH_OT_snap(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Equalize Handles Operator
+ * \{ */
+
+/* Defines for equalize handles tool. */
+static const EnumPropertyItem prop_graphkeys_equalize_handles_sides[] = {
+ {GRAPHKEYS_EQUALIZE_LEFT, "LEFT", 0, "Left", "Equalize selected keyframes' left handles"},
+ {GRAPHKEYS_EQUALIZE_RIGHT, "RIGHT", 0, "Right", "Equalize selected keyframes' right handles"},
+ {GRAPHKEYS_EQUALIZE_BOTH, "BOTH", 0, "Both", "Equalize both of a keyframe's handles"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+/* ------------------- */
+
+/* Equalize selected keyframes' bezier handles. */
+static void equalize_graph_keys(bAnimContext *ac, int mode, float handle_length, bool flatten)
+{
+ /* Filter data. */
+ const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* Equalize keyframes. */
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ ANIM_fcurve_equalize_keyframes_loop(ale->key_data, mode, handle_length, flatten);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static int graphkeys_equalize_handles_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ /* Get editor data. */
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Get equalize mode. */
+ int mode = RNA_enum_get(op->ptr, "side");
+ float handle_length = RNA_float_get(op->ptr, "handle_length");
+ bool flatten = RNA_boolean_get(op->ptr, "flatten");
+
+ /* Equalize graph keyframes. */
+ equalize_graph_keys(&ac, mode, handle_length, flatten);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_equalize_handles(wmOperatorType *ot)
+{
+ /* Identifiers */
+ ot->name = "Equalize Handles";
+ ot->idname = "GRAPH_OT_equalize_handles";
+ ot->description =
+ "Ensure selected keyframes' handles have equal length, optionally making them horizontal";
+
+ /* API callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = graphkeys_equalize_handles_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* Flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Properties */
+ ot->prop = RNA_def_enum(ot->srna,
+ "side",
+ prop_graphkeys_equalize_handles_sides,
+ 0,
+ "Side",
+ "Side of the keyframes' bezier handles to affect");
+ RNA_def_float(ot->srna,
+ "handle_length",
+ 5.0f,
+ 0.1f,
+ FLT_MAX,
+ "Handle Length",
+ "Length to make selected keyframes' bezier handles",
+ 1.0f,
+ 50.0f);
+ RNA_def_boolean(
+ ot->srna,
+ "flatten",
+ false,
+ "Flatten",
+ "Make the values of the selected keyframes' handles the same as their respective keyframes");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Mirror Keyframes Operator
* \{ */
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 4db1eb5214e..a59fb63dd22 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -109,8 +109,8 @@ void get_graph_keyframe_extents(struct bAnimContext *ac,
float *xmax,
float *ymin,
float *ymax,
- const bool do_sel_only,
- const bool include_handles);
+ bool do_sel_only,
+ bool include_handles);
void GRAPH_OT_previewrange_set(struct wmOperatorType *ot);
void GRAPH_OT_view_all(struct wmOperatorType *ot);
@@ -126,6 +126,8 @@ void GRAPH_OT_paste(struct wmOperatorType *ot);
void GRAPH_OT_duplicate(struct wmOperatorType *ot);
void GRAPH_OT_delete(struct wmOperatorType *ot);
void GRAPH_OT_clean(struct wmOperatorType *ot);
+void GRAPH_OT_blend_to_neighbor(struct wmOperatorType *ot);
+void GRAPH_OT_breakdown(struct wmOperatorType *ot);
void GRAPH_OT_decimate(struct wmOperatorType *ot);
void GRAPH_OT_sample(struct wmOperatorType *ot);
void GRAPH_OT_bake(struct wmOperatorType *ot);
@@ -142,6 +144,7 @@ void GRAPH_OT_easing_type(struct wmOperatorType *ot);
void GRAPH_OT_frame_jump(struct wmOperatorType *ot);
void GRAPH_OT_snap_cursor_value(struct wmOperatorType *ot);
void GRAPH_OT_snap(struct wmOperatorType *ot);
+void GRAPH_OT_equalize_handles(struct wmOperatorType *ot);
void GRAPH_OT_mirror(struct wmOperatorType *ot);
/* defines for snap keyframes
@@ -156,6 +159,15 @@ enum eGraphKeys_Snap_Mode {
GRAPHKEYS_SNAP_VALUE,
};
+/* Defines for equalize keyframe handles.
+ * NOTE: Keep in sync with eEditKeyframes_Equalize (in ED_keyframes_edit.h).
+ */
+enum eGraphKeys_Equalize_Mode {
+ GRAPHKEYS_EQUALIZE_LEFT = 1,
+ GRAPHKEYS_EQUALIZE_RIGHT,
+ GRAPHKEYS_EQUALIZE_BOTH,
+};
+
/* defines for mirror keyframes
* NOTE: keep in sync with eEditKeyframes_Mirror (in ED_keyframes_edit.h)
*/
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index ecafc75fc06..7606dcc60cf 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -456,6 +456,7 @@ void graphedit_operatortypes(void)
/* editing */
WM_operatortype_append(GRAPH_OT_snap);
+ WM_operatortype_append(GRAPH_OT_equalize_handles);
WM_operatortype_append(GRAPH_OT_mirror);
WM_operatortype_append(GRAPH_OT_frame_jump);
WM_operatortype_append(GRAPH_OT_snap_cursor_value);
@@ -470,6 +471,8 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_smooth);
WM_operatortype_append(GRAPH_OT_clean);
WM_operatortype_append(GRAPH_OT_decimate);
+ WM_operatortype_append(GRAPH_OT_blend_to_neighbor);
+ WM_operatortype_append(GRAPH_OT_breakdown);
WM_operatortype_append(GRAPH_OT_euler_filter);
WM_operatortype_append(GRAPH_OT_delete);
WM_operatortype_append(GRAPH_OT_duplicate);
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 0bb5e8b8d9c..4b8c983a761 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -99,8 +99,10 @@ typedef struct tBeztCopyData {
/** \name Utility Functions
* \{ */
-/* Construct a list with the original bezt arrays so we can restore them during modal operation.
- * The data is stored on the struct that is passed.*/
+/**
+ * Construct a list with the original bezt arrays so we can restore them during modal operation.
+ * The data is stored on the struct that is passed.
+ */
static void store_original_bezt_arrays(tGraphSliderOp *gso)
{
ListBase anim_data = {NULL, NULL};
@@ -313,8 +315,7 @@ static int graph_slider_invoke(bContext *C, wmOperator *op, const wmEvent *event
ED_slider_init(gso->slider, event);
if (gso->bezt_arr_list.first == NULL) {
- WM_report(RPT_WARNING,
- "Fcurve Slider: Can't work on baked channels. Unbake them and try again.");
+ WM_report(RPT_ERROR, "Cannot find keys to operate on.");
graph_slider_exit(C, op);
return OPERATOR_CANCELLED;
}
@@ -552,3 +553,256 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend To Neighbor Operator
+ * \{ */
+
+static void blend_to_neighbor_graph_keys(bAnimContext *ac, float factor)
+{
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
+
+ bAnimListElem *ale;
+
+ /* Loop through filtered data and blend keys. */
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ blend_to_neighbor_fcurve_segment(fcu, segment, factor);
+ }
+ BLI_freelistN(&segments);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static void blend_to_neighbor_draw_status_header(bContext *C, tGraphSliderOp *gso)
+{
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
+
+ ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
+
+ strcpy(mode_str, TIP_("Blend To Neighbor"));
+
+ if (hasNumInput(&gso->num)) {
+ char str_ofs[NUM_STR_REP_LEN];
+
+ outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ }
+
+ ED_workspace_status_text(C, status_str);
+}
+
+static void blend_to_neighbor_modal_update(bContext *C, wmOperator *op)
+{
+ tGraphSliderOp *gso = op->customdata;
+
+ blend_to_neighbor_draw_status_header(C, gso);
+
+ /* Reset keyframe data to the state at invoke. */
+ reset_bezts(gso);
+
+ const float factor = ED_slider_factor_get(gso->slider);
+ RNA_property_float_set(op->ptr, gso->factor_prop, factor);
+ blend_to_neighbor_graph_keys(&gso->ac, factor);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
+static int blend_to_neighbor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const int invoke_result = graph_slider_invoke(C, op, event);
+
+ if (invoke_result == OPERATOR_CANCELLED) {
+ return invoke_result;
+ }
+
+ tGraphSliderOp *gso = op->customdata;
+ gso->modal_update = blend_to_neighbor_modal_update;
+ gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
+ blend_to_neighbor_draw_status_header(C, gso);
+
+ return invoke_result;
+}
+
+static int blend_to_neighbor_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const float factor = RNA_float_get(op->ptr, "factor");
+
+ blend_to_neighbor_graph_keys(&ac, factor);
+
+ /* Set notifier that keyframes have changed. */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_blend_to_neighbor(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Blend To Neighbor";
+ ot->idname = "GRAPH_OT_blend_to_neighbor";
+ ot->description = "Blend selected keyframes to their left or right neighbor";
+
+ /* API callbacks. */
+ ot->invoke = blend_to_neighbor_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = blend_to_neighbor_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_factor(ot->srna,
+ "factor",
+ 1.0f / 3.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Blend",
+ "The blend factor with 0.5 being the current frame",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Breakdown Operator
+ * \{ */
+
+static void breakdown_graph_keys(bAnimContext *ac, float factor)
+{
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
+
+ bAnimListElem *ale;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ breakdown_fcurve_segment(fcu, segment, factor);
+ }
+ BLI_freelistN(&segments);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static void breakdown_draw_status_header(bContext *C, tGraphSliderOp *gso)
+{
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
+
+ ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
+
+ strcpy(mode_str, TIP_("Breakdown"));
+
+ if (hasNumInput(&gso->num)) {
+ char str_ofs[NUM_STR_REP_LEN];
+
+ outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ }
+
+ ED_workspace_status_text(C, status_str);
+}
+
+static void breakdown_modal_update(bContext *C, wmOperator *op)
+{
+ tGraphSliderOp *gso = op->customdata;
+
+ breakdown_draw_status_header(C, gso);
+
+ /* Reset keyframe data to the state at invoke. */
+ reset_bezts(gso);
+ breakdown_graph_keys(&gso->ac, ED_slider_factor_get(gso->slider));
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
+static int breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const int invoke_result = graph_slider_invoke(C, op, event);
+
+ if (invoke_result == OPERATOR_CANCELLED) {
+ return invoke_result;
+ }
+
+ tGraphSliderOp *gso = op->customdata;
+ gso->modal_update = breakdown_modal_update;
+ breakdown_draw_status_header(C, gso);
+
+ return invoke_result;
+}
+
+static int breakdown_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const float factor = RNA_float_get(op->ptr, "factor");
+
+ breakdown_graph_keys(&ac, factor);
+
+ /* Set notifier that keyframes have changed. */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_breakdown(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Breakdown";
+ ot->idname = "GRAPH_OT_breakdown";
+ ot->description = "Move selected keyframes to an inbetween position relative to adjacent keys";
+
+ /* API callbacks. */
+ ot->invoke = breakdown_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = breakdown_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_factor(ot->srna,
+ "factor",
+ 1.0f / 3.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Factor",
+ "Favor either the left or the right key",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 40c95d4f382..7d5e8836490 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -36,6 +36,7 @@
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_anim_api.h"
@@ -796,18 +797,17 @@ static void graph_refresh(const bContext *C, ScrArea *area)
graph_refresh_fcurve_colors(C);
}
-static void graph_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void graph_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceGraph *sgraph = (SpaceGraph *)slink;
-
- if (sgraph->ads) {
- if ((ID *)sgraph->ads->filter_grp == old_id) {
- sgraph->ads->filter_grp = (Collection *)new_id;
- }
- if ((ID *)sgraph->ads->source == old_id) {
- sgraph->ads->source = new_id;
- }
+ if (!sgraph->ads) {
+ return;
}
+
+ BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->source, ID_REMAP_APPLY_DEFAULT);
}
static int graph_space_subtype_get(ScrArea *area)
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index ade5993cdb9..8858df3323f 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -591,7 +591,7 @@ float ED_space_image_zoom_level(const View2D *v2d, const int grid_dimension)
* - Default grid size on startup, which is 256x256 pixels
* - How blend factor for grid lines is set up in the fragment shader `grid_frag.glsl`. */
float zoom_factor;
- zoom_factor = (xzoom + yzoom) / 2.0f; /* Average for accuracy. */
+ zoom_factor = (xzoom + yzoom) / 2.0f; /* Average for accuracy. */
zoom_factor *= 256.0f / (powf(grid_dimension, 2));
return zoom_factor;
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index f9160774c41..23d07c9b45b 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1499,6 +1499,13 @@ static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
}
}
+static void image_operator_prop_allow_tokens(wmOperatorType *ot)
+{
+ PropertyRNA *prop = RNA_def_boolean(
+ ot->srna, "allow_path_tokens", true, "", "Allow the path to contain substitution tokens");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
void IMAGE_OT_open(wmOperatorType *ot)
{
/* identifiers */
@@ -1516,6 +1523,7 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
+ image_operator_prop_allow_tokens(ot);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
@@ -1767,7 +1775,13 @@ static int image_save_options_init(Main *bmain,
opts->im_format.views_format = ima->views_format;
}
- BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
+ if (ima->source == IMA_SRC_TILED) {
+ BLI_strncpy(opts->filepath, ima->filepath, sizeof(opts->filepath));
+ BLI_path_abs(opts->filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
+ }
+ else {
+ BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
+ }
/* sanitize all settings */
@@ -1804,14 +1818,10 @@ static int image_save_options_init(Main *bmain,
BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
- /* append UDIM numbering if not present */
- if (ima->source == IMA_SRC_TILED) {
- char udim[6];
- ImageTile *tile = ima->tiles.first;
- BLI_snprintf(udim, sizeof(udim), ".%d", tile->tile_number);
-
+ /* append UDIM marker if not present */
+ if (ima->source == IMA_SRC_TILED && strstr(opts->filepath, "<UDIM>") == NULL) {
int len = strlen(opts->filepath);
- STR_CONCAT(opts->filepath, len, udim);
+ STR_CONCAT(opts->filepath, len, ".<UDIM>");
}
}
@@ -2070,6 +2080,7 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
"Copy",
"Create a new image file without modifying the current image in blender");
+ image_operator_prop_allow_tokens(ot);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
@@ -2584,6 +2595,11 @@ static int image_new_exec(bContext *C, wmOperator *op)
else if (sima) {
ED_space_image_set(bmain, sima, ima, false);
}
+ else {
+ /* #BKE_image_add_generated creates one user by default, remove it if image is not linked to
+ * anything. ref. T94599. */
+ id_us_min(&ima->id);
+ }
BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index 87bff913ff2..84b85b396fe 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -115,79 +115,17 @@ static int image_cmp_frame(const void *a, const void *b)
return 0;
}
-/*
- * Checks whether the given filepath refers to a UDIM texture.
- * If yes, the range from 1001 to the highest tile is returned, otherwise 0.
- *
- * If the result is positive, the filepath will be overwritten with that of
- * the 1001 tile.
- *
- * udim_tiles may get filled even if the result ultimately is false!
- */
-static bool image_get_udim(char *filepath, ListBase *udim_tiles, int *udim_start, int *udim_range)
-{
- char filename[FILE_MAX], dirname[FILE_MAXDIR];
- BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
-
- ushort digits;
- char base_head[FILE_MAX], base_tail[FILE_MAX];
- int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits);
-
- if (id < 1001 || id > IMA_UDIM_MAX) {
- return false;
- }
-
- bool is_udim = true;
- int min_udim = IMA_UDIM_MAX + 1;
- int max_udim = 0;
-
- struct direntry *dir;
- uint totfile = BLI_filelist_dir_contents(dirname, &dir);
- for (int i = 0; i < totfile; i++) {
- if (!(dir[i].type & S_IFREG)) {
- continue;
- }
- char head[FILE_MAX], tail[FILE_MAX];
- id = BLI_path_sequence_decode(dir[i].relname, head, tail, &digits);
-
- if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
- !(STREQLEN(base_tail, tail, FILE_MAX))) {
- continue;
- }
-
- if (id < 1001 || id > IMA_UDIM_MAX) {
- is_udim = false;
- break;
- }
-
- BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id)));
- min_udim = min_ii(min_udim, id);
- max_udim = max_ii(max_udim, id);
- }
- BLI_filelist_free(dir, totfile);
-
- if (is_udim && min_udim <= IMA_UDIM_MAX) {
- char primary_filename[FILE_MAX];
- BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, min_udim);
- BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename);
-
- *udim_start = min_udim;
- *udim_range = max_udim - min_udim + 1;
- return true;
- }
- return false;
-}
-
/**
* From a list of frames, compute the start (offset) and length of the sequence
- * of contiguous frames. If UDIM is detect, it will return UDIM tiles as well.
+ * of contiguous frames. If `detect_udim` is set, it will return UDIM tiles as well.
*/
static void image_detect_frame_range(ImageFrameRange *range, const bool detect_udim)
{
/* UDIM */
if (detect_udim) {
int udim_start, udim_range;
- bool result = image_get_udim(range->filepath, &range->udim_tiles, &udim_start, &udim_range);
+ bool result = BKE_image_get_tile_info(
+ range->filepath, &range->udim_tiles, &udim_start, &udim_range);
if (result) {
range->offset = udim_start;
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index dad494e6984..eb5b6104a79 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -37,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -297,7 +298,7 @@ static void image_refresh(const bContext *C, ScrArea *area)
ima = ED_space_image(sima);
BKE_image_user_frame_calc(ima, &sima->iuser, scene->r.cfra);
- /* check if we have to set the image from the editmesh */
+ /* Check if we have to set the image from the edit-mesh. */
if (ima && (ima->source == IMA_SRC_VIEWER && sima->mode == SI_MODE_MASK)) {
if (scene->nodetree) {
Mask *mask = ED_space_image_get_mask(sima);
@@ -983,29 +984,19 @@ static void image_header_region_listener(const wmRegionListenerParams *params)
}
}
-static void image_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void image_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceImage *simg = (SpaceImage *)slink;
- if (!ELEM(GS(old_id->name), ID_IM, ID_GD, ID_MSK)) {
+ if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_IM | FILTER_ID_GD | FILTER_ID_MSK)) {
return;
}
- if ((ID *)simg->image == old_id) {
- simg->image = (Image *)new_id;
- id_us_ensure_real(new_id);
- }
-
- if ((ID *)simg->gpd == old_id) {
- simg->gpd = (bGPdata *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
-
- if ((ID *)simg->mask_info.mask == old_id) {
- simg->mask_info.mask = (Mask *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&simg->image, ID_REMAP_APPLY_ENSURE_REAL);
+ BKE_id_remapper_apply(mappings, (ID **)&simg->gpd, ID_REMAP_APPLY_UPDATE_REFCOUNT);
+ BKE_id_remapper_apply(mappings, (ID **)&simg->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL);
}
/**
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_stats.cc b/source/blender/editors/space_info/info_stats.cc
index bcf26743030..005ae0214cd 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -43,6 +43,7 @@
#include "BLT_translation.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_blender_version.h"
#include "BKE_context.h"
@@ -351,7 +352,7 @@ static void stats_object_pose(const Object *ob, SceneStats *stats)
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
stats->totbone++;
if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
- if (pchan->bone->layer & arm->layer) {
+ if (BKE_pose_is_layer_visible(arm, pchan)) {
stats->totbonesel++;
}
}
diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h
index 96f537b4b97..38c073a328a 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -81,7 +81,7 @@ typedef struct TextViewContext {
* Use for selection.
*/
int textview_draw(struct TextViewContext *tvc,
- const bool do_draw,
+ bool do_draw,
const int mval_init[2],
void **r_mval_pick_item,
int *r_mval_pick_offset);
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 12f0011b499..7dfe0e89e90 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -324,7 +324,7 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uin
GPU_line_smooth(true);
GPU_blend(GPU_BLEND_ALPHA);
- /* Fully opaque line on selected strips. */
+ /* Fully opaque line on selected strips. */
if (strip->flag & NLASTRIP_FLAG_SELECT) {
/* TODO: Use theme setting. */
immUniformColor3f(1.0f, 1.0f, 1.0f);
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 0771153c5f5..962b5151661 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -33,6 +33,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_anim_api.h"
@@ -577,18 +578,17 @@ static void nla_listener(const wmSpaceTypeListenerParams *params)
}
}
-static void nla_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void nla_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceNla *snla = (SpaceNla *)slink;
- if (snla->ads) {
- if ((ID *)snla->ads->filter_grp == old_id) {
- snla->ads->filter_grp = (Collection *)new_id;
- }
- if ((ID *)snla->ads->source == old_id) {
- snla->ads->source = new_id;
- }
+ if (snla->ads == NULL) {
+ return;
}
+ BKE_id_remapper_apply(mappings, (ID **)&snla->ads->filter_grp, ID_REMAP_APPLY_DEFAULT);
+ BKE_id_remapper_apply(mappings, (ID **)&snla->ads->source, ID_REMAP_APPLY_DEFAULT);
}
void ED_spacetype_nla(void)
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index e88d61fe880..41d6388c947 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
@@ -50,7 +51,6 @@ set(SRC
node_relationships.cc
node_select.cc
node_templates.cc
- node_toolbar.cc
node_view.cc
space_node.cc
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index 87f7bfdafb0..94da7d55e5d 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -36,6 +36,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_scene.h"
#include "BKE_tracking.h"
@@ -50,7 +51,9 @@
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_platform.h"
+#include "GPU_shader_shared.h"
#include "GPU_state.h"
+#include "GPU_uniform_buffer.h"
#include "DRW_engine.h"
@@ -76,7 +79,7 @@
#include "NOD_texture.h"
#include "node_intern.hh" /* own include */
-using blender::float2;
+namespace blender::ed::space_node {
/* 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
@@ -135,24 +138,11 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA
static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
-#if 0
- /* XXX no context access here. */
- bNode *node = (bNode*)ptr->data;
- CurveMapping *cumap = node->storage;
-
- if (cumap) {
- cumap->flag |= CUMA_DRAW_CFRA;
- if (node->custom1 < node->custom2) {
- cumap->sample[0] = (float)(CFRA - node->custom1) / (float)(node->custom2 - node->custom1);
- }
- }
-#endif
-
uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false);
- uiLayout *row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE);
- uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE);
+ uiItemR(col, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
}
static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -170,6 +160,8 @@ static void node_buts_curvefloat(uiLayout *layout, bContext *UNUSED(C), PointerR
uiTemplateCurveMapping(layout, ptr, "mapping", 0, false, false, false, false);
}
+} // namespace blender::ed::space_node
+
#define SAMPLE_FLT_ISNONE FLT_MAX
/* Bad bad, 2.5 will do better? ... no it won't! */
static float _sample_col[4] = {SAMPLE_FLT_ISNONE};
@@ -183,6 +175,8 @@ void ED_node_sample_set(const float col[4])
}
}
+namespace blender::ed::space_node {
+
static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
@@ -228,22 +222,6 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA
}
}
-static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "clamp_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "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,
- NODE_MAP_RANGE_SMOOTHERSTEP)) {
- uiItemR(layout, ptr, "clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
@@ -392,40 +370,6 @@ static void node_buts_image_user(uiLayout *layout,
}
}
-static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_vector_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "rotation_type", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "convert_from", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "convert_to", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "attribute_type", DEFAULT_FLAGS, IFACE_("Type"), ICON_NONE);
- uiItemR(layout, ptr, "attribute_name", DEFAULT_FLAGS, IFACE_("Name"), ICON_NONE);
-}
-
-static void node_shader_buts_wireframe(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_pixel_size", DEFAULT_FLAGS, nullptr, 0);
-}
-
static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
PointerRNA imaptr = RNA_pointer_get(ptr, "image");
@@ -495,375 +439,21 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, IFACE_("Projection"), ICON_NONE);
}
-static void node_shader_buts_tex_sky(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "sky_type", DEFAULT_FLAGS, "", ICON_NONE);
-
- if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_PREETHAM) {
- uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_HOSEK) {
- uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "ground_albedo", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NISHITA) {
- Scene *scene = CTX_data_scene(C);
- if (BKE_scene_uses_blender_eevee(scene)) {
- uiItemL(layout, TIP_("Nishita not available in Eevee"), ICON_ERROR);
- }
- uiItemR(layout, ptr, "sun_disc", DEFAULT_FLAGS, nullptr, 0);
-
- uiLayout *col;
- if (RNA_boolean_get(ptr, "sun_disc")) {
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "sun_size", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sun_intensity", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "sun_elevation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "sun_rotation", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- uiItemR(layout, ptr, "altitude", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "air_density", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "dust_density", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(col, ptr, "ozone_density", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-}
-
-static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "gradient_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "turbulence_depth", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *col;
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
- uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
-
- col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE);
- uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
-}
-
-static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "wave_type", DEFAULT_FLAGS, "", ICON_NONE);
- int type = RNA_enum_get(ptr, "wave_type");
- if (type == SHD_WAVE_BANDS) {
- uiItemR(layout, ptr, "bands_direction", DEFAULT_FLAGS, "", ICON_NONE);
- }
- else { /* SHD_WAVE_RINGS */
- uiItemR(layout, ptr, "rings_direction", DEFAULT_FLAGS, "", ICON_NONE);
- }
-
- uiItemR(layout, ptr, "wave_profile", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "musgrave_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "voronoi_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "feature", DEFAULT_FLAGS, "", ICON_NONE);
- int feature = RNA_enum_get(ptr, "feature");
- if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) &&
- RNA_enum_get(ptr, "voronoi_dimensions") != 1) {
- uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, "", ICON_NONE);
- }
-}
-
-static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_tex_pointdensity(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- NodeShaderTexPointDensity *shader_point_density = (NodeShaderTexPointDensity *)node->storage;
- Object *ob = (Object *)node->id;
-
- PointerRNA ob_ptr, obdata_ptr;
- RNA_id_pointer_create((ID *)ob, &ob_ptr);
- RNA_id_pointer_create(ob ? (ID *)ob->data : nullptr, &obdata_ptr);
-
- uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "object", DEFAULT_FLAGS, nullptr, ICON_NONE);
-
- if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
- PointerRNA dataptr;
- RNA_id_pointer_create((ID *)node->id, &dataptr);
- uiItemPointerR(
- layout, ptr, "particle_system", &dataptr, "particle_systems", nullptr, ICON_NONE);
- }
-
- uiItemR(layout, ptr, "space", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "radius", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "resolution", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
- uiItemR(layout, ptr, "particle_color_source", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
- else {
- uiItemR(layout, ptr, "vertex_color_source", DEFAULT_FLAGS, nullptr, ICON_NONE);
- if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) {
- if (ob_ptr.data) {
- uiItemPointerR(
- layout, ptr, "vertex_attribute_name", &ob_ptr, "vertex_groups", "", ICON_NONE);
- }
- }
- if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTCOL) {
- if (obdata_ptr.data) {
- uiItemPointerR(
- layout, ptr, "vertex_attribute_name", &obdata_ptr, "vertex_colors", "", ICON_NONE);
- }
- }
- }
-}
-
-static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "object", DEFAULT_FLAGS, nullptr, 0);
- uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, nullptr, 0);
-
- if (!RNA_boolean_get(ptr, "from_instancer")) {
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
-
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
- }
- }
-}
-
-static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
-
- if (U.experimental.use_sculpt_vertex_colors &&
- RNA_collection_length(&dataptr, "sculpt_vertex_colors")) {
- uiItemPointerR(
- layout, ptr, "layer_name", &dataptr, "sculpt_vertex_colors", "", ICON_GROUP_VCOL);
- }
- else {
- uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL);
- }
- }
- else {
- uiItemL(layout, TIP_("No mesh in active object"), ICON_ERROR);
- }
-}
-
-static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "use_tips", DEFAULT_FLAGS, nullptr, 0);
-}
-
-static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
-
- if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) {
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
-
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
- }
- else {
- uiItemR(layout, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
- }
- }
-}
-
static void node_shader_buts_displacement(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
}
-static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiLayout *split, *row;
-
- split = uiLayoutSplit(layout, 0.0f, false);
-
- uiItemR(split, ptr, "direction_type", DEFAULT_FLAGS, "", 0);
-
- row = uiLayoutRow(split, false);
-
- if (RNA_enum_get(ptr, "direction_type") == SHD_TANGENT_UVMAP) {
- PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
-
- if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
- PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
- uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
- }
- else {
- uiItemR(row, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
- }
- }
- else {
- uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, 0);
- }
-}
-
static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(layout, ptr, "subsurface_method", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_principled_hair(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "parametrization", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
-
- if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) {
- uiItemR(row, ptr, "ies", DEFAULT_FLAGS, "", ICON_NONE);
- }
- else {
- uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
- }
-}
-
-static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row;
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- row = uiLayoutRow(layout, true);
-
- if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL) {
- uiItemR(row, ptr, "script", DEFAULT_FLAGS, "", ICON_NONE);
- }
- else {
- uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
- }
-
- uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update");
-}
-
-static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
-{
- uiItemS(layout);
-
- node_shader_buts_script(layout, C, ptr);
-
-#if 0 /* not implemented yet */
- if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL) {
- uiItemR(layout, ptr, "use_auto_update", DEFAULT_FLAGS, nullptr, ICON_NONE);
- }
-#endif
-}
-
static void node_buts_output_shader(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "target", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayout *row, *col;
-
- col = uiLayoutColumn(layout, false);
- row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE);
- uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_ambient_occlusion(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "inside", DEFAULT_FLAGS, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "only_local", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
-static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
-}
-
-static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "name", DEFAULT_FLAGS, nullptr, ICON_NONE);
-}
-
/* only once called */
static void node_shader_set_butfunc(bNodeType *ntype)
{
@@ -880,9 +470,6 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_CURVE_FLOAT:
ntype->draw_buttons = node_buts_curvefloat;
break;
- case SH_NODE_MAPPING:
- ntype->draw_buttons = node_shader_buts_mapping;
- break;
case SH_NODE_VALUE:
ntype->draw_buttons = node_buts_value;
break;
@@ -895,33 +482,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_VALTORGB:
ntype->draw_buttons = node_buts_colorramp;
break;
- case SH_NODE_CLAMP:
- ntype->draw_buttons = node_shader_buts_clamp;
- break;
- case SH_NODE_MAP_RANGE:
- ntype->draw_buttons = node_shader_buts_map_range;
- break;
case SH_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
- case SH_NODE_VECTOR_MATH:
- ntype->draw_buttons = node_shader_buts_vect_math;
- break;
- case SH_NODE_VECTOR_ROTATE:
- ntype->draw_buttons = node_shader_buts_vector_rotate;
- break;
- case SH_NODE_VECT_TRANSFORM:
- ntype->draw_buttons = node_shader_buts_vect_transform;
- break;
- case SH_NODE_ATTRIBUTE:
- ntype->draw_buttons = node_shader_buts_attribute;
- break;
- case SH_NODE_WIREFRAME:
- ntype->draw_buttons = node_shader_buts_wireframe;
- break;
- case SH_NODE_TEX_SKY:
- ntype->draw_buttons = node_shader_buts_tex_sky;
- break;
case SH_NODE_TEX_IMAGE:
ntype->draw_buttons = node_shader_buts_tex_image;
ntype->draw_buttons_ex = node_shader_buts_tex_image_ex;
@@ -930,105 +493,20 @@ static void node_shader_set_butfunc(bNodeType *ntype)
ntype->draw_buttons = node_shader_buts_tex_environment;
ntype->draw_buttons_ex = node_shader_buts_tex_environment_ex;
break;
- case SH_NODE_TEX_GRADIENT:
- ntype->draw_buttons = node_shader_buts_tex_gradient;
- break;
- case SH_NODE_TEX_MAGIC:
- ntype->draw_buttons = node_shader_buts_tex_magic;
- break;
- case SH_NODE_TEX_BRICK:
- ntype->draw_buttons = node_shader_buts_tex_brick;
- break;
- case SH_NODE_TEX_WAVE:
- ntype->draw_buttons = node_shader_buts_tex_wave;
- break;
- case SH_NODE_TEX_MUSGRAVE:
- ntype->draw_buttons = node_shader_buts_tex_musgrave;
- break;
- case SH_NODE_TEX_VORONOI:
- ntype->draw_buttons = node_shader_buts_tex_voronoi;
- break;
- case SH_NODE_TEX_NOISE:
- ntype->draw_buttons = node_shader_buts_tex_noise;
- break;
- case SH_NODE_TEX_POINTDENSITY:
- ntype->draw_buttons = node_shader_buts_tex_pointdensity;
- break;
- case SH_NODE_TEX_COORD:
- ntype->draw_buttons = node_shader_buts_tex_coord;
- break;
- case SH_NODE_BUMP:
- ntype->draw_buttons = node_shader_buts_bump;
- break;
- case SH_NODE_NORMAL_MAP:
- ntype->draw_buttons = node_shader_buts_normal_map;
- break;
case SH_NODE_DISPLACEMENT:
case SH_NODE_VECTOR_DISPLACEMENT:
ntype->draw_buttons = node_shader_buts_displacement;
break;
- case SH_NODE_TANGENT:
- ntype->draw_buttons = node_shader_buts_tangent;
- break;
case SH_NODE_BSDF_GLOSSY:
case SH_NODE_BSDF_GLASS:
case SH_NODE_BSDF_REFRACTION:
ntype->draw_buttons = node_shader_buts_glossy;
break;
- case SH_NODE_BSDF_PRINCIPLED:
- ntype->draw_buttons = node_shader_buts_principled;
- break;
- case SH_NODE_BSDF_ANISOTROPIC:
- ntype->draw_buttons = node_shader_buts_anisotropic;
- break;
- case SH_NODE_SUBSURFACE_SCATTERING:
- ntype->draw_buttons = node_shader_buts_subsurface;
- break;
- case SH_NODE_BSDF_TOON:
- ntype->draw_buttons = node_shader_buts_toon;
- break;
- case SH_NODE_BSDF_HAIR:
- ntype->draw_buttons = node_shader_buts_hair;
- break;
- case SH_NODE_BSDF_HAIR_PRINCIPLED:
- ntype->draw_buttons = node_shader_buts_principled_hair;
- break;
- case SH_NODE_SCRIPT:
- ntype->draw_buttons = node_shader_buts_script;
- ntype->draw_buttons_ex = node_shader_buts_script_ex;
- break;
- case SH_NODE_UVMAP:
- ntype->draw_buttons = node_shader_buts_uvmap;
- break;
- case SH_NODE_VERTEX_COLOR:
- ntype->draw_buttons = node_shader_buts_vertex_color;
- break;
- case SH_NODE_UVALONGSTROKE:
- ntype->draw_buttons = node_shader_buts_uvalongstroke;
- break;
case SH_NODE_OUTPUT_MATERIAL:
case SH_NODE_OUTPUT_LIGHT:
case SH_NODE_OUTPUT_WORLD:
ntype->draw_buttons = node_buts_output_shader;
break;
- case SH_NODE_OUTPUT_LINESTYLE:
- ntype->draw_buttons = node_buts_output_linestyle;
- break;
- case SH_NODE_TEX_IES:
- ntype->draw_buttons = node_shader_buts_ies;
- break;
- case SH_NODE_BEVEL:
- ntype->draw_buttons = node_shader_buts_bevel;
- break;
- case SH_NODE_AMBIENT_OCCLUSION:
- ntype->draw_buttons = node_shader_buts_ambient_occlusion;
- break;
- case SH_NODE_TEX_WHITE_NOISE:
- ntype->draw_buttons = node_shader_buts_white_noise;
- break;
- case SH_NODE_OUTPUT_AOV:
- ntype->draw_buttons = node_shader_buts_output_aov;
- break;
}
}
@@ -1095,763 +573,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;
@@ -1873,260 +594,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)
{
@@ -2246,221 +713,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_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)
@@ -2536,31 +788,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)
{
@@ -2569,15 +796,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;
@@ -2587,210 +805,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_SUNBEAMS:
- ntype->draw_buttons = node_composit_buts_sunbeams;
- break;
case CMP_NODE_CRYPTOMATTE:
ntype->draw_buttons = node_composit_buts_cryptomatte;
break;
@@ -2798,11 +840,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;
}
}
@@ -2997,7 +1036,8 @@ static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), Poin
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
static void node_socket_template_properties_update(bNodeType *ntype, bNodeSocketTemplate *stemp)
@@ -3065,8 +1105,12 @@ static void node_socket_undefined_interface_draw_color(bContext *UNUSED(C),
/** \} */
+} // namespace blender::ed::space_node
+
void ED_node_init_butfuncs()
{
+ using namespace blender::ed::space_node;
+
/* Fallback types for undefined tree, nodes, sockets
* Defined in blenkernel, but not registered in type hashes.
*/
@@ -3091,12 +1135,6 @@ void ED_node_init_butfuncs()
node_template_properties_update(ntype);
}
NODE_TYPES_END;
-
- /* tree type icons */
- ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING;
- ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL;
- ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE;
- ntreeType_Geometry->ui_icon = ICON_NODETREE;
}
void ED_init_custom_node_type(bNodeType *UNUSED(ntype))
@@ -3105,9 +1143,11 @@ void ED_init_custom_node_type(bNodeType *UNUSED(ntype))
void ED_init_custom_node_socket_type(bNodeSocketType *stype)
{
- stype->draw = node_socket_button_label;
+ stype->draw = blender::ed::space_node::node_socket_button_label;
}
+namespace blender::ed::space_node {
+
static const float virtual_node_socket_color[4] = {0.2, 0.2, 0.2, 1.0};
/* maps standard socket integer type to a color */
@@ -3390,14 +1430,6 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout
uiItemR(layout, ptr, "hide_value", DEFAULT_FLAGS, nullptr, 0);
}
-void ED_init_standard_node_socket_type(bNodeSocketType *stype)
-{
- stype->draw = std_node_socket_draw;
- stype->draw_color = std_node_socket_draw_color;
- stype->interface_draw = std_node_socket_interface_draw;
- stype->interface_draw_color = std_node_socket_interface_draw_color;
-}
-
static void node_socket_virtual_draw_color(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PointerRNA *UNUSED(node_ptr),
@@ -3406,12 +1438,26 @@ static void node_socket_virtual_draw_color(bContext *UNUSED(C),
copy_v4_v4(r_color, virtual_node_socket_color);
}
+} // namespace blender::ed::space_node
+
+void ED_init_standard_node_socket_type(bNodeSocketType *stype)
+{
+ using namespace blender::ed::space_node;
+ stype->draw = std_node_socket_draw;
+ stype->draw_color = std_node_socket_draw_color;
+ stype->interface_draw = std_node_socket_interface_draw;
+ stype->interface_draw_color = std_node_socket_interface_draw_color;
+}
+
void ED_init_node_socket_type_virtual(bNodeSocketType *stype)
{
+ using namespace blender::ed::space_node;
stype->draw = node_socket_button_label;
stype->draw_color = node_socket_virtual_draw_color;
}
+namespace blender::ed::space_node {
+
/* ************** Generic drawing ************** */
void draw_nodespace_back_pix(const bContext &C,
@@ -3845,23 +1891,29 @@ static void nodelink_batch_draw(const SpaceNode &snode)
}
GPU_blend(GPU_BLEND_ALPHA);
+ NodeLinkInstanceData node_link_data;
+
+ UI_GetThemeColor4fv(TH_WIRE_INNER, node_link_data.colors[nodelink_get_color_id(TH_WIRE_INNER)]);
+ UI_GetThemeColor4fv(TH_WIRE, node_link_data.colors[nodelink_get_color_id(TH_WIRE)]);
+ UI_GetThemeColor4fv(TH_ACTIVE, node_link_data.colors[nodelink_get_color_id(TH_ACTIVE)]);
+ UI_GetThemeColor4fv(TH_EDGE_SELECT,
+ node_link_data.colors[nodelink_get_color_id(TH_EDGE_SELECT)]);
+ UI_GetThemeColor4fv(TH_REDALERT, node_link_data.colors[nodelink_get_color_id(TH_REDALERT)]);
+ node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH;
+ node_link_data.arrowSize = ARROW_SIZE;
- float colors[6][4] = {{0.0f}};
- UI_GetThemeColor4fv(TH_WIRE_INNER, colors[nodelink_get_color_id(TH_WIRE_INNER)]);
- UI_GetThemeColor4fv(TH_WIRE, colors[nodelink_get_color_id(TH_WIRE)]);
- UI_GetThemeColor4fv(TH_ACTIVE, colors[nodelink_get_color_id(TH_ACTIVE)]);
- UI_GetThemeColor4fv(TH_EDGE_SELECT, colors[nodelink_get_color_id(TH_EDGE_SELECT)]);
- UI_GetThemeColor4fv(TH_REDALERT, colors[nodelink_get_color_id(TH_REDALERT)]);
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(sizeof(node_link_data), &node_link_data, __func__);
GPU_vertbuf_data_len_set(g_batch_link.inst_vbo, g_batch_link.count);
GPU_vertbuf_use(g_batch_link.inst_vbo); /* force update. */
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, "arrowSize", ARROW_SIZE);
+ GPU_batch_uniformbuf_bind(g_batch_link.batch, "node_link_data", ubo);
GPU_batch_draw(g_batch_link.batch);
+ GPU_uniformbuf_unbind(ubo);
+ GPU_uniformbuf_free(ubo);
+
nodelink_batch_reset();
GPU_blend(GPU_BLEND_NONE);
@@ -4032,19 +2084,32 @@ void node_draw_link_bezier(const bContext &C,
copy_v4_v4(colors[2], link_preselection_highlight_color);
}
+ NodeLinkData node_link_data;
+ for (int i = 0; i < 4; i++) {
+ copy_v2_v2(node_link_data.bezierPts[i], vec[i]);
+ }
+ for (int i = 0; i < 3; i++) {
+ copy_v4_v4(node_link_data.colors[i], colors[i]);
+ }
+ node_link_data.doArrow = drawarrow;
+ node_link_data.doMuted = drawmuted;
+ node_link_data.dim_factor = dim_factor;
+ node_link_data.thickness = thickness;
+ node_link_data.dash_factor = dash_factor;
+ node_link_data.dash_alpha = dash_alpha;
+ node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH;
+ node_link_data.arrowSize = ARROW_SIZE;
+
GPUBatch *batch = g_batch_link.batch_single;
+ GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(
+ sizeof(NodeLinkData), &node_link_data, __func__);
+
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, "arrowSize", ARROW_SIZE);
- GPU_batch_uniform_1i(batch, "doArrow", drawarrow);
- GPU_batch_uniform_1i(batch, "doMuted", drawmuted);
- GPU_batch_uniform_1f(batch, "dim_factor", dim_factor);
- GPU_batch_uniform_1f(batch, "thickness", thickness);
- GPU_batch_uniform_1f(batch, "dash_factor", dash_factor);
- GPU_batch_uniform_1f(batch, "dash_alpha", dash_alpha);
+ GPU_batch_uniformbuf_bind(batch, "node_link_data", ubo);
GPU_batch_draw(batch);
+
+ GPU_uniformbuf_unbind(ubo);
+ GPU_uniformbuf_free(ubo);
}
}
}
@@ -4099,6 +2164,8 @@ void node_draw_link(const bContext &C,
node_draw_link_bezier(C, v2d, snode, link, th_col1, th_col2, th_col3);
}
+} // namespace blender::ed::space_node
+
void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border, uint pos)
{
immBegin(GPU_PRIM_LINES, 4);
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..45126e9cee0
--- /dev/null
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -0,0 +1,327 @@
+/*
+ * 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 "ED_node.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. */
+ ED_node_tree_propagate_change(&params.C, CTX_data_main(&params.C), &params.node_tree);
+
+ /* Hide the new input in all other group input nodes, to avoid making them taller. */
+ LISTBASE_FOREACH (bNode *, node, &params.node_tree.nodes) {
+ 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);
+}
+
+static void add_existing_group_input_fn(nodes::LinkSearchOpParams &params,
+ const bNodeSocket &interface_socket)
+{
+ const int group_input_index = BLI_findindex(&params.node_tree.inputs, &interface_socket);
+ bNode &group_input = params.add_node("NodeGroupInput");
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &group_input.outputs) {
+ socket->flag |= SOCK_HIDDEN;
+ }
+
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&group_input.outputs, group_input_index);
+ if (socket == nullptr) {
+ /* Adding sockets can fail in some cases. There's no good reason not to be safe here. */
+ return;
+ }
+
+ socket->flag &= ~SOCK_HIDDEN;
+ nodeAddLink(&params.node_tree, &group_input, socket, &params.node, &params.socket);
+}
+
+/**
+ * Call the callback to gather compatible socket connections for all node types, and the operations
+ * that will actually make the connections. Also add some custom operations like connecting a group
+ * 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});
+
+ int weight = -1;
+ LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &node_tree.inputs) {
+ eNodeSocketDatatype from = (eNodeSocketDatatype)interface_socket->type;
+ eNodeSocketDatatype to = (eNodeSocketDatatype)socket.type;
+ if (node_tree.typeinfo->validate_link && !node_tree.typeinfo->validate_link(from, to)) {
+ continue;
+ }
+ search_link_ops.append(
+ {std::string(IFACE_("Group Input ")) + UI_MENU_ARROW_SEP + interface_socket->name,
+ [interface_socket](nodes::LinkSearchOpParams &params) {
+ add_existing_group_input_fn(params, *interface_socket);
+ },
+ weight});
+ weight--;
+ }
+ }
+}
+
+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. */
+ ED_node_tree_propagate_change(C, &bmain, snode.edittree);
+
+ /* Start translation operator with the new node. */
+ wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_translate", true);
+ 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
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index c6a5e8e68c0..8e88f1fad5a 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -36,6 +36,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
@@ -61,6 +62,8 @@
/** \name Utilities
* \{ */
+namespace blender::ed::space_node {
+
bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy)
{
SpaceNode &snode = *CTX_wm_space_node(&C);
@@ -83,15 +86,8 @@ bNode *node_add_node(const bContext &C, const char *idname, int type, float locx
nodeSetSelected(node, true);
- ntreeUpdateTree(&bmain, snode.edittree);
ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr);
-
- snode_update(snode, node);
-
- if (snode.nodetree->type == NTREE_TEXTURE) {
- ntreeTexCheckCyclics(snode.edittree);
- }
-
+ ED_node_tree_propagate_change(&C, &bmain, snode.edittree);
return node;
}
@@ -136,7 +132,7 @@ static bNodeSocketLink *add_reroute_insert_socket_link(ListBase *lb,
{
bNodeSocketLink *socklink, *prev;
- socklink = (bNodeSocketLink *)MEM_callocN(sizeof(bNodeSocketLink), "socket link");
+ socklink = MEM_cnew<bNodeSocketLink>("socket link");
socklink->sock = sock;
socklink->link = link;
copy_v2_v2(socklink->point, point);
@@ -281,10 +277,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
BLI_freelistN(&input_links);
/* always last */
- ntreeUpdateTree(CTX_data_main(C), &ntree);
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
return OPERATOR_FINISHED;
}
@@ -383,14 +376,10 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
group_node->id = &node_group->id;
id_us_plus(group_node->id);
+ BKE_ntree_update_tag_node_property(snode->edittree, group_node);
nodeSetActive(ntree, group_node);
- ntreeUpdateTree(bmain, node_group);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
-
+ ED_node_tree_propagate_change(C, bmain, nullptr);
return OPERATOR_FINISHED;
}
@@ -479,12 +468,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
id_us_plus(&object->id);
nodeSetActive(ntree, object_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
-
- ED_node_tag_update_nodetree(bmain, ntree, object_node);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -517,6 +501,8 @@ static bool node_add_object_poll(bContext *C)
void NODE_OT_add_object(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Node Object";
ot->description = "Add an object info node to the current node editor";
@@ -531,15 +517,16 @@ void NODE_OT_add_object(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_string(ot->srna, "name", "Object", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -587,14 +574,9 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
id_us_plus(&texture->id);
nodeSetActive(ntree, texture_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
- ED_node_tag_update_nodetree(bmain, ntree, texture_node);
-
return OPERATOR_FINISHED;
}
@@ -625,6 +607,8 @@ static bool node_add_texture_poll(bContext *C)
void NODE_OT_add_texture(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Node Texture";
ot->description = "Add a texture to the current node editor";
@@ -640,15 +624,16 @@ void NODE_OT_add_texture(wmOperatorType *ot)
RNA_def_string(
ot->srna, "name", "Texture", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -701,14 +686,9 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
id_us_plus(&collection->id);
nodeSetActive(ntree, collection_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
- ED_node_tag_update_nodetree(bmain, ntree, collection_node);
-
return OPERATOR_FINISHED;
}
@@ -739,6 +719,8 @@ static bool node_add_collection_poll(bContext *C)
void NODE_OT_add_collection(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Node Collection";
ot->description = "Add an collection info node to the current node editor";
@@ -754,15 +736,16 @@ void NODE_OT_add_collection(wmOperatorType *ot)
RNA_def_string(
ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -834,8 +817,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
}
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, snode.edittree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -937,8 +919,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
node->id = mask;
id_us_plus(mask);
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, snode.edittree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -946,6 +927,8 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
void NODE_OT_add_mask(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add Mask Node";
ot->description = "Add a mask node to the current node editor";
@@ -959,15 +942,16 @@ void NODE_OT_add_mask(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
+ prop = RNA_def_int(ot->srna,
+ "session_uuid",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Session UUID",
+ "Session UUID of the data-block to assign",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/** \} */
@@ -1064,3 +1048,5 @@ void NODE_OT_new_node_tree(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc
index 2f3855fd654..cab7cbf10be 100644
--- a/source/blender/editors/space_node/node_context_path.cc
+++ b/source/blender/editors/space_node/node_context_path.cc
@@ -45,11 +45,11 @@
#include "node_intern.hh"
-struct Mesh;
struct Curve;
struct Light;
-struct World;
struct Material;
+struct Mesh;
+struct World;
namespace blender::ed::space_node {
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index d68f16f6197..82da890fa9b 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -88,13 +88,6 @@
#include "node_intern.hh" /* own include */
-using blender::Array;
-using blender::float2;
-using blender::Map;
-using blender::Set;
-using blender::Span;
-using blender::Vector;
-using blender::VectorSet;
using blender::fn::CPPType;
using blender::fn::FieldCPPType;
using blender::fn::FieldInput;
@@ -115,6 +108,8 @@ float ED_node_grid_size()
void ED_node_tree_update(const bContext *C)
{
+ using namespace blender::ed::space_node;
+
SpaceNode *snode = CTX_wm_space_node(C);
if (snode) {
snode_set_context(*C);
@@ -176,34 +171,7 @@ void ED_node_tag_update_id(ID *id)
}
}
-void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node)
-{
- if (!ntree) {
- return;
- }
-
- bool do_tag_update = true;
- if (node != nullptr) {
- if (!node_connected_to_output(*bmain, *ntree, *node)) {
- do_tag_update = false;
- }
- }
-
- /* Look through all datablocks to support groups. */
- if (do_tag_update) {
- FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
- /* Check if nodetree uses the group. */
- if (ntreeHasTree(tntree, ntree)) {
- ED_node_tag_update_id(id);
- }
- }
- FOREACH_NODETREE_END;
- }
-
- if (ntree->type == NTREE_TEXTURE) {
- ntreeTexCheckCyclics(ntree);
- }
-}
+namespace blender::ed::space_node {
static bool compare_nodes(const bNode *a, const bNode *b)
{
@@ -261,14 +229,14 @@ static bool compare_nodes(const bNode *a, const bNode *b)
return false;
}
-void ED_node_sort(bNodeTree *ntree)
+void node_sort(bNodeTree &ntree)
{
/* Merge sort is the algorithm of choice here. */
- int totnodes = BLI_listbase_count(&ntree->nodes);
+ int totnodes = BLI_listbase_count(&ntree.nodes);
int k = 1;
while (k < totnodes) {
- bNode *first_a = (bNode *)ntree->nodes.first;
+ bNode *first_a = (bNode *)ntree.nodes.first;
bNode *first_b = first_a;
do {
@@ -295,8 +263,8 @@ void ED_node_sort(bNodeTree *ntree)
bNode *tmp = node_b;
node_b = node_b->next;
b++;
- BLI_remlink(&ntree->nodes, tmp);
- BLI_insertlinkbefore(&ntree->nodes, node_a, tmp);
+ BLI_remlink(&ntree.nodes, tmp);
+ BLI_insertlinkbefore(&ntree.nodes, node_a, tmp);
}
}
@@ -365,6 +333,10 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
PointerRNA nodeptr;
RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr);
+ const bool node_options = node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS);
+ const bool inputs_first = node.inputs.first &&
+ !(node.outputs.first || (node.flag & NODE_PREVIEW) || node_options);
+
/* Get "global" coordinates. */
float2 loc = node_to_view(node, float2(0));
/* Round the node origin because text contents are always pixel-aligned. */
@@ -377,7 +349,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
dy -= NODE_DY;
/* Add a little bit of padding above the top socket. */
- if (node.outputs.first || node.inputs.first) {
+ if (node.outputs.first || inputs_first) {
dy -= NODE_DYS / 2;
}
@@ -478,7 +450,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
}
/* Buttons rect? */
- if (node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS)) {
+ if (node_options) {
dy -= NODE_DYS / 2;
uiLayout *layout = UI_block_layout(&block,
@@ -1096,8 +1068,12 @@ static void node_socket_draw_nested(const bContext &C,
UI_block_emboss_set(&block, old_emboss);
}
+} // namespace blender::ed::space_node
+
void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
{
+ using namespace blender::ed::space_node;
+
const float size = 2.25f * NODE_SOCKSIZE * scale;
rcti draw_rect = *rect;
float outline_color[4] = {0};
@@ -1144,6 +1120,8 @@ void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[
GPU_blend(state);
}
+namespace blender::ed::space_node {
+
/* ************** Socket callbacks *********** */
static void node_draw_preview_background(rctf *rect)
@@ -1194,17 +1172,17 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
GPU_blend(GPU_BLEND_ALPHA);
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(&state,
- draw_rect.xmin,
- draw_rect.ymin,
- preview->xsize,
- preview->ysize,
- GPU_RGBA8,
- true,
- preview->rect,
- scale,
- scale,
- nullptr);
+ immDrawPixelsTexTiled(&state,
+ draw_rect.xmin,
+ draw_rect.ymin,
+ preview->xsize,
+ preview->ysize,
+ GPU_RGBA8,
+ true,
+ preview->rect,
+ scale,
+ scale,
+ nullptr);
GPU_blend(GPU_BLEND_NONE);
@@ -2405,7 +2383,6 @@ static void node_update_nodetree(const bContext &C,
{
/* Make sure socket "used" tags are correct, for displaying value buttons. */
SpaceNode *snode = CTX_wm_space_node(&C);
- ntreeTagUsedSockets(&ntree);
count_multi_input_socket_links(ntree, *snode);
@@ -2414,9 +2391,11 @@ static void node_update_nodetree(const bContext &C,
bNode &node = *nodes[i];
uiBlock &block = *blocks[i];
if (node.type == NODE_FRAME) {
- frame_node_prepare_for_draw(node, nodes);
+ /* Frame sizes are calculated after all other nodes have calculating their #totr. */
+ continue;
}
- else if (node.type == NODE_REROUTE) {
+
+ if (node.type == NODE_REROUTE) {
reroute_node_prepare_for_draw(node);
}
else {
@@ -2428,6 +2407,13 @@ static void node_update_nodetree(const bContext &C,
}
}
}
+
+ /* Now calculate the size of frame nodes, which can depend on the size of other nodes. */
+ for (const int i : nodes.index_range()) {
+ if (nodes[i]->type == NODE_FRAME) {
+ frame_node_prepare_for_draw(*nodes[i], nodes);
+ }
+ }
}
static void frame_node_draw_label(const bNodeTree &ntree,
@@ -2469,7 +2455,7 @@ static void frame_node_draw_label(const bNodeTree &ntree,
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);
+ BLF_draw(fontid, label, sizeof(label));
}
/* draw text body */
@@ -2896,3 +2882,5 @@ void node_draw_space(const bContext &C, ARegion &region)
/* Scrollers. */
UI_view2d_scrollers_draw(&v2d, nullptr);
}
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index fb90e2bfe50..6275e7e4656 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -38,6 +38,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_workspace.h"
@@ -75,9 +76,9 @@
#include "NOD_texture.h"
#include "node_intern.hh" /* own include */
-#define USE_ESC_COMPO
+namespace blender::ed::space_node {
-using blender::float2;
+#define USE_ESC_COMPO
/* ***************** composite job manager ********************** */
@@ -318,8 +319,12 @@ static void compo_startjob(void *cjv,
ntree->progress = nullptr;
}
+} // namespace blender::ed::space_node
+
void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner)
{
+ using namespace blender::ed::space_node;
+
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -342,7 +347,7 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
"Compositing",
WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS,
WM_JOB_TYPE_COMPOSITE);
- CompoJob *cj = (CompoJob *)MEM_callocN(sizeof(CompoJob), "compo job");
+ CompoJob *cj = MEM_cnew<CompoJob>("compo job");
/* customdata for preview thread */
cj->bmain = bmain;
@@ -359,6 +364,8 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
+namespace blender::ed::space_node {
+
/* ***************************************** */
bool composite_node_active(bContext *C)
@@ -383,31 +390,11 @@ bool composite_node_editable(bContext *C)
return false;
}
-void snode_dag_update(bContext &C, SpaceNode &snode)
-{
- Main *bmain = CTX_data_main(&C);
-
- /* for groups, update all ID's using this */
- if ((snode.edittree->id.flag & LIB_EMBEDDED_DATA) == 0) {
- FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
- if (ntreeHasTree(tntree, snode.edittree)) {
- DEG_id_tag_update(id, 0);
- }
- }
- FOREACH_NODETREE_END;
- }
-
- DEG_id_tag_update(snode.id, 0);
- DEG_id_tag_update(&snode.nodetree->id, 0);
-}
-
-void snode_notify(bContext &C, SpaceNode &snode)
+static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree)
{
- ID *id = snode.id;
+ WM_main_add_notifier(NC_NODE | NA_EDITED, nullptr);
- WM_event_add_notifier(&C, NC_NODE | NA_EDITED, nullptr);
-
- if (ED_node_is_shader(&snode)) {
+ if (ntree->type == NTREE_SHADER) {
if (GS(id->name) == ID_MA) {
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
}
@@ -418,17 +405,40 @@ void snode_notify(bContext &C, SpaceNode &snode)
WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
}
}
- else if (ED_node_is_compositor(&snode)) {
- WM_event_add_notifier(&C, NC_SCENE | ND_NODES, id);
+ else if (ntree->type == NTREE_COMPOSIT) {
+ WM_main_add_notifier(NC_SCENE | ND_NODES, id);
}
- else if (ED_node_is_texture(&snode)) {
- WM_event_add_notifier(&C, NC_TEXTURE | ND_NODES, id);
+ else if (ntree->type == NTREE_TEXTURE) {
+ WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
}
- else if (ED_node_is_geometry(&snode)) {
+ else if (ntree->type == NTREE_GEOMETRY) {
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
}
}
+} // namespace blender::ed::space_node
+
+void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *root_ntree)
+{
+ if (C != nullptr) {
+ SpaceNode *snode = CTX_wm_space_node(C);
+ if (snode != nullptr && root_ntree != nullptr) {
+ blender::ed::space_node::send_notifiers_after_tree_change(snode->id, root_ntree);
+ }
+ }
+
+ NodeTreeUpdateExtraParams params = {nullptr};
+ params.tree_changed_fn = [](ID *id, bNodeTree *ntree, void *UNUSED(user_data)) {
+ blender::ed::space_node::send_notifiers_after_tree_change(id, ntree);
+ DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE);
+ };
+ params.tree_output_changed_fn = [](ID *UNUSED(id), bNodeTree *ntree, void *UNUSED(user_data)) {
+ DEG_id_tag_update(&ntree->id, ID_RECALC_NTREE_OUTPUT);
+ };
+
+ BKE_ntree_update_main_tree(bmain, root_ntree, &params);
+}
+
void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
{
if (typeinfo) {
@@ -477,7 +487,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
}
ma->nodetree = ntreeCopyTree(bmain, ma_default->nodetree);
- ntreeUpdateTree(bmain, ma->nodetree);
+ BKE_ntree_update_main_tree(bmain, ma->nodetree, nullptr);
}
else if (ELEM(GS(id->name), ID_WO, ID_LA)) {
/* Emission */
@@ -517,7 +527,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
output->locx = 300.0f;
output->locy = 300.0f;
nodeSetActive(ntree, output);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, nullptr);
}
else {
printf("ED_node_shader_default called on wrong ID type.\n");
@@ -555,7 +565,7 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
bNodeSocket *tosock = (bNodeSocket *)out->inputs.first;
nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
- ntreeUpdateTree(CTX_data_main(C), sce->nodetree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), sce->nodetree, nullptr);
}
void ED_node_texture_default(const bContext *C, Tex *tex)
@@ -583,9 +593,11 @@ void ED_node_texture_default(const bContext *C, Tex *tex)
bNodeSocket *tosock = (bNodeSocket *)out->inputs.first;
nodeAddLink(tex->nodetree, in, fromsock, out, tosock);
- ntreeUpdateTree(CTX_data_main(C), tex->nodetree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), tex->nodetree, nullptr);
}
+namespace blender::ed::space_node {
+
/**
* Here we set the active tree(s), even called for each redraw now, so keep it fast :)
*/
@@ -628,27 +640,7 @@ void snode_set_context(const bContext &C)
}
}
-void snode_update(SpaceNode &snode, bNode *node)
-{
- /* XXX this only updates nodes in the current node space tree path.
- * The function supposedly should update any potential group node linking to changed tree,
- * this really requires a working depsgraph ...
- */
-
- /* update all edited group nodes */
- bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
- if (path) {
- bNodeTree *ngroup = path->nodetree;
- for (path = path->prev; path; path = path->prev) {
- nodeUpdateID(path->nodetree, (ID *)ngroup);
- ngroup = path->nodetree;
- }
- }
-
- if (node) {
- nodeUpdate(snode.edittree, node);
- }
-}
+} // namespace blender::ed::space_node
void ED_node_set_active(
Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
@@ -680,11 +672,6 @@ void ED_node_set_active(
/* tree specific activate calls */
if (ntree->type == NTREE_SHADER) {
- /* when we select a material, active texture is cleared, for buttons */
- if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO)) {
- nodeClearActiveID(ntree, ID_TE);
- }
-
if (ELEM(node->type,
SH_NODE_OUTPUT_MATERIAL,
SH_NODE_OUTPUT_WORLD,
@@ -697,14 +684,10 @@ void ED_node_set_active(
}
node->flag |= NODE_DO_OUTPUT;
- if (was_output == 0) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
- }
- }
- else if (do_update) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
}
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
+
if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
/* If active texture changed, free glsl materials. */
LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
@@ -750,7 +733,7 @@ void ED_node_set_active(
if (r_active_texture_changed) {
*r_active_texture_changed = true;
}
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
WM_main_add_notifier(NC_IMAGE, nullptr);
}
@@ -767,7 +750,7 @@ void ED_node_set_active(
node->flag |= NODE_DO_OUTPUT;
if (was_output == 0) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* Adding a node doesn't link this yet. */
@@ -782,11 +765,11 @@ void ED_node_set_active(
}
node->flag |= NODE_DO_OUTPUT;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
}
else if (do_update) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
}
else if (ntree->type == NTREE_TEXTURE) {
@@ -824,6 +807,8 @@ void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
// node_update_nodetree(C, ntree, 0.0f, 0.0f);
}
+namespace blender::ed::space_node {
+
/* ***************** generic operator functions for nodes ***************** */
#if 0 /* UNUSED */
@@ -931,7 +916,7 @@ static void node_resize_init(bContext *C,
{
SpaceNode *snode = CTX_wm_space_node(C);
- NodeSizeWidget *nsw = (NodeSizeWidget *)MEM_callocN(sizeof(NodeSizeWidget), __func__);
+ NodeSizeWidget *nsw = MEM_cnew<NodeSizeWidget>(__func__);
op->customdata = nsw;
nsw->mxstart = snode->runtime->cursor[0] * UI_DPI_FAC;
@@ -1274,7 +1259,8 @@ bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
/* ****************** Duplicate *********************** */
-static void node_duplicate_reparent_recursive(bNode *node)
+static void node_duplicate_reparent_recursive(const Map<const bNode *, bNode *> &node_map,
+ bNode *node)
{
bNode *parent;
@@ -1284,15 +1270,15 @@ static void node_duplicate_reparent_recursive(bNode *node)
for (parent = node->parent; parent; parent = parent->parent) {
if (parent->flag & SELECT) {
if (!(parent->flag & NODE_TEST)) {
- node_duplicate_reparent_recursive(parent);
+ node_duplicate_reparent_recursive(node_map, parent);
}
break;
}
}
/* reparent node copy to parent copy */
if (parent) {
- nodeDetachNode(node->new_node);
- nodeAttachNode(node->new_node, parent->new_node);
+ nodeDetachNode(node_map.lookup(node));
+ nodeAttachNode(node_map.lookup(node), node_map.lookup(parent));
}
}
@@ -1302,17 +1288,18 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
bNode *lastnode = (bNode *)ntree->nodes.last;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
- BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT);
-
- /* To ensure redraws or re-renders happen. */
- ED_node_tag_update_id(snode->id);
+ bNode *new_node = blender::bke::node_copy_with_mapping(
+ ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, new_node);
}
/* make sure we don't copy new nodes again! */
@@ -1321,8 +1308,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
}
}
- /* Copy links between selected nodes.
- * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */
+ /* Copy links between selected nodes. */
bNodeLink *lastlink = (bNodeLink *)ntree->links.last;
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
/* This creates new links between copied nodes.
@@ -1330,13 +1316,13 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
*/
if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
(keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) {
- bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink");
+ bNodeLink *newlink = MEM_cnew<bNodeLink>("bNodeLink");
newlink->flag = link->flag;
- newlink->tonode = link->tonode->new_node;
- newlink->tosock = link->tosock->new_sock;
+ newlink->tonode = node_map.lookup(link->tonode);
+ newlink->tosock = socket_map.lookup(link->tosock);
if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
- newlink->fromnode = link->fromnode->new_node;
- newlink->fromsock = link->fromsock->new_sock;
+ newlink->fromnode = node_map.lookup(link->fromnode);
+ newlink->fromsock = socket_map.lookup(link->fromsock);
}
else {
/* input node not copied, this keeps the original input linked */
@@ -1360,7 +1346,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
/* reparent copied nodes */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if ((node->flag & SELECT) && !(node->flag & NODE_TEST)) {
- node_duplicate_reparent_recursive(node);
+ node_duplicate_reparent_recursive(node_map, node);
}
/* only has to check old nodes */
@@ -1373,13 +1359,11 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
/* has been set during copy above */
- bNode *newnode = node->new_node;
+ bNode *newnode = node_map.lookup(node);
nodeSetSelected(node, false);
node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
nodeSetSelected(newnode, true);
-
- do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, *ntree, *newnode));
}
/* make sure we don't copy new nodes again! */
@@ -1388,13 +1372,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- if (do_tag_update) {
- snode_dag_update(*C, *snode);
- }
-
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1416,7 +1394,7 @@ void NODE_OT_duplicate(wmOperatorType *ot)
ot->srna, "keep_inputs", false, "Keep Inputs", "Keep the input links to duplicated nodes");
}
-bool ED_node_select_check(const ListBase *lb)
+static bool node_select_check(const ListBase *lb)
{
LISTBASE_FOREACH (const bNode *, node, lb) {
if (node->flag & NODE_SELECT) {
@@ -1427,10 +1405,10 @@ bool ED_node_select_check(const ListBase *lb)
return false;
}
-void ED_node_select_all(ListBase *lb, int action)
+void node_select_all(ListBase *lb, int action)
{
if (action == SEL_TOGGLE) {
- if (ED_node_select_check(lb)) {
+ if (node_select_check(lb)) {
action = SEL_DESELECT;
}
else {
@@ -1485,8 +1463,7 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1653,7 +1630,7 @@ static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
node_flag_toggle_exec(snode, NODE_PREVIEW);
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1732,7 +1709,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -1760,23 +1737,17 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
if ((node->flag & SELECT) && !node->typeinfo->no_muting) {
node->flag ^= NODE_MUTED;
- snode_update(*snode, node);
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(*bmain, *snode->edittree, *node));
+ BKE_ntree_update_tag_node_mute(snode->edittree, node);
}
}
- snode_notify(*C, *snode);
- if (do_tag_update) {
- snode_dag_update(*C, *snode);
- }
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1802,24 +1773,16 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) {
if (node->flag & SELECT) {
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(*bmain, *snode->edittree, *node));
nodeRemoveNode(bmain, snode->edittree, node, true);
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- if (do_tag_update) {
- snode_dag_update(*C, *snode);
- }
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1863,10 +1826,7 @@ static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1901,10 +1861,7 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1951,7 +1908,7 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "file_path", file_path);
ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format);
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -2000,7 +1957,7 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *U
return OPERATOR_CANCELLED;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
@@ -2067,7 +2024,7 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
nimf->active_input++;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -2096,18 +2053,15 @@ void NODE_OT_output_file_move_active_socket(wmOperatorType *ot)
static int node_copy_color_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;
- if (!ntree) {
- return OPERATOR_CANCELLED;
- }
- bNode *node = nodeGetActive(ntree);
+ bNode *node = nodeGetActive(&ntree);
if (!node) {
return OPERATOR_CANCELLED;
}
- LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node_iter, &ntree.nodes) {
if (node_iter->flag & NODE_SELECT && node_iter != node) {
if (node->flag & NODE_CUSTOM_COLOR) {
node_iter->flag |= NODE_CUSTOM_COLOR;
@@ -2119,7 +2073,7 @@ static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2153,47 +2107,48 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
BKE_node_clipboard_clear();
BKE_node_clipboard_init(ntree);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
/* No ID refcounting, this node is virtual,
* detached from any actual Blender data currently. */
- bNode *new_node = BKE_node_copy_store_new_pointers(
- nullptr, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN);
- BKE_node_clipboard_add_node(new_node);
+ bNode *new_node = blender::bke::node_copy_with_mapping(nullptr,
+ *node,
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_MAIN,
+ false,
+ socket_map);
+ node_map.add_new(node, new_node);
}
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->flag & SELECT) {
- bNode *new_node = node->new_node;
-
- /* ensure valid pointers */
- if (new_node->parent) {
- /* parent pointer must be redirected to new node or detached if parent is
- * not copied */
- if (new_node->parent->flag & NODE_SELECT) {
- new_node->parent = new_node->parent->new_node;
- }
- else {
- nodeDetachNode(new_node);
- }
+ for (bNode *new_node : node_map.values()) {
+ BKE_node_clipboard_add_node(new_node);
+
+ /* Parent pointer must be redirected to new node or detached if parent is not copied. */
+ if (new_node->parent) {
+ if (node_map.contains(new_node->parent)) {
+ new_node->parent = node_map.lookup(new_node->parent);
+ }
+ else {
+ nodeDetachNode(new_node);
}
}
}
- /* Copy links between selected nodes.
- * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */
-
+ /* Copy links between selected nodes. */
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- /* This creates new links between copied nodes. */
- if (link->tonode && (link->tonode->flag & NODE_SELECT) && link->fromnode &&
- (link->fromnode->flag & NODE_SELECT)) {
- bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink");
+ BLI_assert(link->tonode);
+ BLI_assert(link->fromnode);
+ if (link->tonode->flag & NODE_SELECT && link->fromnode->flag & NODE_SELECT) {
+ bNodeLink *newlink = MEM_cnew<bNodeLink>(__func__);
newlink->flag = link->flag;
- newlink->tonode = link->tonode->new_node;
- newlink->tosock = link->tosock->new_sock;
- newlink->fromnode = link->fromnode->new_node;
- newlink->fromsock = link->fromsock->new_sock;
+ newlink->tonode = node_map.lookup(link->tonode);
+ newlink->tosock = socket_map.lookup(link->tosock);
+ newlink->fromnode = node_map.lookup(link->fromnode);
+ newlink->fromsock = socket_map.lookup(link->fromsock);
BKE_node_clipboard_add_link(newlink);
}
@@ -2288,35 +2243,38 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
}
mul_v2_fl(center, 1.0 / num_nodes);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
/* copy nodes from clipboard */
LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) {
- bNode *new_node = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT);
+ bNode *new_node = blender::bke::node_copy_with_mapping(
+ ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, new_node);
+ }
+ for (bNode *new_node : node_map.values()) {
/* pasted nodes are selected */
nodeSetSelected(new_node, true);
- }
- /* reparent copied nodes */
- LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) {
- bNode *new_node = node->new_node;
+ /* The parent pointer must be redirected to new node. */
if (new_node->parent) {
- new_node->parent = new_node->parent->new_node;
+ if (node_map.contains(new_node->parent)) {
+ new_node->parent = node_map.lookup(new_node->parent);
+ }
}
}
LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) {
nodeAddLink(ntree,
- link->fromnode->new_node,
- link->fromsock->new_sock,
- link->tonode->new_node,
- link->tosock->new_sock);
+ node_map.lookup(link->fromnode),
+ socket_map.lookup(link->fromsock),
+ node_map.lookup(link->tonode),
+ socket_map.lookup(link->tosock));
}
Main *bmain = CTX_data_main(C);
- ntreeUpdateTree(bmain, snode->edittree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
/* Pasting nodes can create arbitrary new relations, because nodes can reference IDs. */
DEG_relations_tag_update(bmain);
@@ -2384,10 +2342,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op)
/* make the new socket active */
sock->flag |= SELECT;
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2434,10 +2389,7 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *op)
active_sock->flag |= SELECT;
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2488,7 +2440,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
/* Need the extra update here because the loop above does not check for valid links in the node
* group we're currently editing. */
- ntree->update |= NTREE_UPDATE_GROUP | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_interface(ntree);
/* Deactivate sockets. */
LISTBASE_FOREACH (bNodeSocket *, socket_iter, sockets) {
@@ -2497,10 +2449,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
/* Make the new socket active. */
iosock->flag |= SELECT;
- ntreeUpdateTree(main, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, main, ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2611,11 +2560,8 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op)
}
}
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2846,7 +2792,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op)
btree->flag |= NTREE_VIEWER_BORDER;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, btree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
}
else {
@@ -2886,7 +2832,7 @@ static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op))
bNodeTree *btree = snode->nodetree;
btree->flag &= ~NTREE_VIEWER_BORDER;
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), btree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2931,7 +2877,7 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
ntreeCompositCryptomatteAddSocket(ntree, node);
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
@@ -2977,7 +2923,7 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(o
return OPERATOR_CANCELLED;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
@@ -2996,3 +2942,4 @@ void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index 4890c3e39cf..542e6fd748f 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -46,13 +46,11 @@
#include "node_intern.hh"
-using blender::IndexRange;
-using blender::Map;
-using blender::Set;
-using blender::StringRef;
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
using geo_log::GeometryAttributeInfo;
+namespace blender::ed::space_node {
+
struct AttributeSearchData {
const bNodeTree *tree;
const bNode *node;
@@ -125,8 +123,8 @@ void node_geometry_add_attribute_search_button(const bContext &UNUSED(C),
0.0f,
"");
- AttributeSearchData *data = OBJECT_GUARDED_NEW(
- AttributeSearchData, {&node_tree, &node, (bNodeSocket *)socket_ptr.data});
+ AttributeSearchData *data = MEM_new<AttributeSearchData>(
+ __func__, AttributeSearchData{&node_tree, &node, (bNodeSocket *)socket_ptr.data});
UI_but_func_search_set_results_are_suggestions(but, true);
UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
@@ -139,3 +137,5 @@ void node_geometry_add_attribute_search_button(const bContext &UNUSED(C),
attribute_search_exec_fn,
nullptr);
}
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_gizmo.cc b/source/blender/editors/space_node/node_gizmo.cc
index 717f4d2f4f9..8c60d100b26 100644
--- a/source/blender/editors/space_node/node_gizmo.cc
+++ b/source/blender/editors/space_node/node_gizmo.cc
@@ -43,6 +43,8 @@
#include "node_intern.hh"
+namespace blender::ed::space_node {
+
/* -------------------------------------------------------------------- */
/** \name Local Utilities
* \{ */
@@ -292,7 +294,11 @@ static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz,
const bool ny = rct.ymin > rct.ymax;
BLI_rctf_resize(&rct, fabsf(matrix[0][0]), fabsf(matrix[1][1]));
BLI_rctf_recenter(&rct, (matrix[3][0] / dims[0]) + 0.5f, (matrix[3][1] / dims[1]) + 0.5f);
- const rctf rct_isect{0, 0, 1, 1};
+ rctf rct_isect{};
+ rct_isect.xmin = 0;
+ rct_isect.xmax = 1;
+ rct_isect.ymin = 0;
+ rct_isect.ymax = 1;
BLI_rctf_isect(&rct_isect, &rct, &rct);
if (nx) {
SWAP(float, rct.xmin, rct.xmax);
@@ -380,7 +386,7 @@ static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgro
params.value_get_fn = gizmo_node_crop_prop_matrix_get;
params.value_set_fn = gizmo_node_crop_prop_matrix_set;
params.range_get_fn = nullptr;
- params.user_data = snode;
+ params.user_data = node;
WM_gizmo_target_property_def_func(gz, "matrix", &params);
}
else {
@@ -632,3 +638,5 @@ void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc
index 704ffe1e478..73e419d667a 100644
--- a/source/blender/editors/space_node/node_group.cc
+++ b/source/blender/editors/space_node/node_group.cc
@@ -28,10 +28,11 @@
#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_vec_types.hh"
#include "BLI_string.h"
+#include "BLI_vector.hh"
#include "BLT_translation.h"
@@ -40,6 +41,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "DEG_depsgraph_build.h"
@@ -60,7 +62,7 @@
#include "NOD_socket.h"
#include "node_intern.hh" /* own include */
-using blender::float2;
+namespace blender::ed::space_node {
/* -------------------------------------------------------------------- */
/** \name Local Utilities
@@ -216,38 +218,34 @@ static void animation_basepath_change_free(AnimationBasePathChange *basepath_cha
MEM_freeN(basepath_change);
}
-/* returns 1 if its OK */
-static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
+/**
+ * \return True if successful.
+ */
+static bool node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
{
- /* Clear new pointers, set in #ntreeCopyTree_ex_new_pointers. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node->new_node = nullptr;
- }
-
ListBase anim_basepaths = {nullptr, nullptr};
- LinkNode *nodes_delayed_free = nullptr;
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
+ Vector<bNode *> nodes_delayed_free;
+ const bNodeTree *ngroup = reinterpret_cast<const bNodeTree *>(gnode->id);
- /* wgroup is a temporary copy of the NodeTree we're merging in
- * - all of wgroup's nodes are copied across to their new home
- * - ngroup (i.e. the source NodeTree) is left unscathed
- * - temp copy. do change ID usercount for the copies
+ /* `wgroup` is a temporary copy of the #NodeTree we're merging in
+ * - All of wgroup's nodes are copied across to their new home.
+ * - `ngroup` (i.e. the source NodeTree) is left unscathed.
+ * - Temp copy. do change ID user-count for the copies.
*/
- bNodeTree *wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, true);
+ bNodeTree *wgroup = ntreeCopyTree(bmain, ngroup);
- /* Add the nodes into the ntree */
+ /* Add the nodes into the `ntree`. */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &wgroup->nodes) {
/* Remove interface nodes.
* This also removes remaining links to and from interface nodes.
*/
if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
/* We must delay removal since sockets will reference this node. see: T52092 */
- BLI_linklist_prepend(&nodes_delayed_free, node);
+ nodes_delayed_free.append(node);
}
- /* keep track of this node's RNA "base" path (the part of the path identifying the node)
- * if the old nodetree has animation data which potentially covers this node
- */
+ /* Keep track of this node's RNA "base" path (the part of the path identifying the node)
+ * if the old node-tree has animation data which potentially covers this node. */
const char *old_animation_basepath = nullptr;
if (wgroup->adt) {
PointerRNA ptr;
@@ -258,6 +256,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
/* migrate node */
BLI_remlink(&wgroup->nodes, node);
BLI_addtail(&ntree->nodes, node);
+ BKE_ntree_update_tag_node_new(ntree, node);
/* ensure unique node name in the node tree */
nodeUniqueName(ntree, node);
@@ -284,6 +283,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &wgroup->links) {
BLI_remlink(&wgroup->links, link);
BLI_addtail(&ntree->links, link);
+ BKE_ntree_update_tag_link_added(ntree, link);
}
bNodeLink *glinks_last = (bNodeLink *)ntree->links.last;
@@ -385,17 +385,14 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
}
}
- while (nodes_delayed_free) {
- bNode *node = (bNode *)BLI_linklist_pop(&nodes_delayed_free);
+ for (bNode *node : nodes_delayed_free) {
nodeRemoveNode(bmain, ntree, node, false);
}
/* delete the group instance and dereference group tree */
nodeRemoveNode(bmain, ntree, gnode, true);
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
-
- return 1;
+ return true;
}
static int node_group_ungroup_exec(bContext *C, wmOperator *op)
@@ -412,16 +409,13 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op)
}
if (gnode->id && node_group_ungroup(bmain, snode->edittree, gnode)) {
- ntreeUpdateTree(bmain, snode->nodetree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr);
}
else {
BKE_report(op->reports, RPT_WARNING, "Cannot ungroup");
return OPERATOR_CANCELLED;
}
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
-
return OPERATOR_FINISHED;
}
@@ -457,13 +451,11 @@ static bool node_group_separate_selected(
nodeSetSelected(node, false);
}
- /* clear new pointers, set in BKE_node_copy_ex(). */
- LISTBASE_FOREACH (bNode *, node, &ngroup.nodes) {
- node->new_node = nullptr;
- }
-
ListBase anim_basepaths = {nullptr, nullptr};
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
/* add selected nodes into the ntree */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup.nodes) {
if (!(node->flag & NODE_SELECT)) {
@@ -479,16 +471,17 @@ static bool node_group_separate_selected(
bNode *newnode;
if (make_copy) {
/* make a copy */
- newnode = BKE_node_copy_store_new_pointers(&ngroup, node, LIB_ID_COPY_DEFAULT);
+ newnode = blender::bke::node_copy_with_mapping(
+ &ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, newnode);
}
else {
/* use the existing node */
newnode = node;
}
- /* 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
- */
+ /* Keep track of this node's RNA "base" path (the part of the path identifying the node)
+ * if the old node-tree has animation data which potentially covers this node. */
if (ngroup.adt) {
PointerRNA ptr;
char *path;
@@ -528,10 +521,10 @@ static bool node_group_separate_selected(
/* make a copy of internal links */
if (fromselect && toselect) {
nodeAddLink(&ntree,
- link->fromnode->new_node,
- link->fromsock->new_sock,
- link->tonode->new_node,
- link->tosock->new_sock);
+ node_map.lookup(link->fromnode),
+ socket_map.lookup(link->fromsock),
+ node_map.lookup(link->tonode),
+ socket_map.lookup(link->tosock));
}
}
else {
@@ -558,9 +551,9 @@ static bool node_group_separate_selected(
}
}
- ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(&ntree);
if (!make_copy) {
- ngroup.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(&ngroup);
}
return true;
@@ -614,10 +607,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
/* switch to parent tree */
ED_node_tree_pop(snode);
- ntreeUpdateTree(CTX_data_main(C), snode->nodetree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr);
return OPERATOR_FINISHED;
}
@@ -789,9 +779,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
/* move nodes over */
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
- */
+ /* Keep track of this node's RNA "base" path (the part of the pat identifying the node)
+ * if the old node-tree has animation data which potentially covers this node. */
if (ntree.adt) {
PointerRNA ptr;
char *path;
@@ -812,6 +801,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
/* change node-collection membership */
BLI_remlink(&ntree.nodes, node);
BLI_addtail(&ngroup->nodes, node);
+ BKE_ntree_update_tag_node_removed(&ntree);
+ BKE_ntree_update_tag_node_new(ngroup, node);
/* ensure unique node name in the ngroup */
nodeUniqueName(ngroup, node);
@@ -983,11 +974,6 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
}
}
}
-
- /* update of the group tree */
- ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS;
- /* update of the tree containing the group instance node */
- ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
}
static bNode *node_group_make_from_selected(const bContext &C,
@@ -1004,7 +990,7 @@ static bNode *node_group_make_from_selected(const bContext &C,
return nullptr;
}
- /* new nodetree */
+ /* New node-tree. */
bNodeTree *ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype);
/* make group node */
@@ -1016,9 +1002,6 @@ static bNode *node_group_make_from_selected(const bContext &C,
node_group_make_insert_selected(C, ntree, gnode);
- /* update of the tree containing the group instance node */
- ntree.update |= NTREE_UPDATE_NODES;
-
return gnode;
}
@@ -1047,14 +1030,10 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
sort_multi_input_socket_links(snode, *node, nullptr, nullptr);
}
- ntreeUpdateTree(bmain, ngroup);
}
}
- ntreeUpdateTree(bmain, &ntree);
-
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, nullptr);
/* We broke relations in node tree, need to rebuild them in the graphs. */
DEG_relations_tag_update(bmain);
@@ -1107,12 +1086,7 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, gnode);
ED_node_tree_push(snode, ngroup, gnode);
- ntreeUpdateTree(bmain, ngroup);
-
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, nullptr);
return OPERATOR_FINISHED;
}
@@ -1133,3 +1107,5 @@ void NODE_OT_group_insert(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index f3ba405c6d0..c161fc70402 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -23,7 +23,7 @@
#pragma once
-#include "BLI_float2.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_vector.hh"
#include "BKE_node.h"
@@ -45,19 +45,39 @@ struct wmGizmoGroupType;
struct wmKeyConfig;
struct wmWindow;
+/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */
+extern const char *node_context_dir[];
+
+namespace blender::ed::space_node {
+
/** Temporary data used in node link drag modal operator. */
struct bNodeLinkDrag {
/** Links dragged by the operator. */
- blender::Vector<bNodeLink *> links;
+ 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. */
- struct bNode *last_node_hovered_while_dragging_a_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;
+
+ /** 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;
@@ -67,7 +87,7 @@ struct SpaceNode_Runtime {
float aspect;
/** Mouse position for drawing socket-less links and adding nodes. */
- blender::float2 cursor;
+ float2 cursor;
/** For auto compositing. */
bool recalc;
@@ -92,15 +112,15 @@ ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT);
/**
* Transform between View2Ds in the tree path.
*/
-blender::float2 space_node_group_offset(const SpaceNode &snode);
+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);
+float2 node_link_calculate_multi_input_position(const 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);
+NodeResizeDirection node_get_resize_direction(const bNode *node, int x, int y);
/**
* Usual convention here would be #node_socket_get_color(),
* but that's already used (for setting a color property socket).
@@ -112,22 +132,26 @@ void node_socket_color_get(const bContext &C,
float r_color[4]);
void node_draw_space(const bContext &C, ARegion &region);
-void node_set_cursor(wmWindow &win, SpaceNode &snode, const blender::float2 &cursor);
+/**
+ * Sort nodes by selection: unselected nodes first, then selected,
+ * then the active node at the very end. Relative order is kept intact.
+ */
+void node_sort(bNodeTree &ntree);
+
+void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor);
/* DPI scaled coords */
-blender::float2 node_to_view(const bNode &node, const blender::float2 &co);
+float2 node_to_view(const bNode &node, const 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);
-
-void node_toolbar_register(ARegionType *art);
+float2 node_from_view(const bNode &node, const float2 &co);
-void node_operatortypes(void);
+void node_operatortypes();
void node_keymap(wmKeyConfig *keyconf);
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_socket_deselect(bNode *node, bNodeSocket &sock, bool deselect_node);
+void node_deselect_all_input_sockets(SpaceNode &snode, bool deselect_nodes);
+void node_deselect_all_output_sockets(SpaceNode &snode, bool deselect_nodes);
void node_select_single(bContext &C, bNode &node);
void NODE_OT_select(wmOperatorType *ot);
@@ -178,7 +202,7 @@ bool node_link_bezier_points(const View2D *v2d,
const SpaceNode *snode,
const bNodeLink &link,
float coord_array[][2],
- const int resol);
+ int resol);
/**
* Return quadratic beziers points for a given nodelink and clip if v2d is not nullptr.
*/
@@ -191,6 +215,8 @@ void draw_nodespace_back_pix(const bContext &C,
SpaceNode &snode,
bNodeInstanceKey parent_key);
+void node_select_all(ListBase *lb, int action);
+
/**
* XXX Does some additional initialization on top of #nodeAddNode
* Can be used with both custom and static nodes,
@@ -216,8 +242,7 @@ void NODE_OT_group_edit(wmOperatorType *ot);
void sort_multi_input_socket_links(SpaceNode &snode,
bNode &node,
bNodeLink *drag_link,
- const blender::float2 *cursor);
-bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node);
+ const float2 *cursor);
void NODE_OT_link(wmOperatorType *ot);
void NODE_OT_link_make(wmOperatorType *ot);
@@ -234,12 +259,8 @@ void NODE_OT_link_viewer(wmOperatorType *ot);
void NODE_OT_insert_offset(wmOperatorType *ot);
-void snode_notify(bContext &C, SpaceNode &snode);
-void snode_dag_update(bContext &C, SpaceNode &snode);
void snode_set_context(const bContext &C);
-void snode_update(SpaceNode &snode, bNode *node);
-/** Operator poll callback. */
bool composite_node_active(bContext *C);
/** Operator poll callback. */
bool composite_node_editable(bContext *C);
@@ -251,7 +272,7 @@ int node_render_changed_exec(bContext *, wmOperator *);
bool node_find_indicated_socket(SpaceNode &snode,
bNode **nodep,
bNodeSocket **sockp,
- const blender::float2 &cursor,
+ const 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);
@@ -307,8 +328,6 @@ void node_geometry_add_attribute_search_button(const bContext &C,
PointerRNA &socket_ptr,
uiLayout &layout);
-extern const char *node_context_dir[];
-
/* 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)
@@ -323,8 +342,11 @@ extern const char *node_context_dir[];
#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit)
#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 a6264f151e4..2ca475f6948 100644
--- a/source/blender/editors/space_node/node_ops.cc
+++ b/source/blender/editors/space_node/node_ops.cc
@@ -35,6 +35,8 @@
#include "node_intern.hh" /* own include */
+namespace blender::ed::space_node {
+
void node_operatortypes()
{
WM_operatortype_append(NODE_OT_select);
@@ -127,6 +129,17 @@ void node_operatortypes()
WM_operatortype_append(NODE_OT_cryptomatte_layer_remove);
}
+void node_keymap(struct wmKeyConfig *keyconf)
+{
+ /* Entire Editor only ----------------- */
+ WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0);
+
+ /* Main Region only ----------------- */
+ WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0);
+}
+
+} // namespace blender::ed::space_node
+
void ED_operatormacros_node()
{
wmOperatorType *ot;
@@ -203,12 +216,3 @@ void ED_operatormacros_node()
WM_operatortype_macro_define(ot, "NODE_OT_links_detach");
WM_operatortype_macro_define(ot, "NODE_OT_translate_attach");
}
-
-void node_keymap(struct wmKeyConfig *keyconf)
-{
- /* Entire Editor only ----------------- */
- WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0);
-
- /* Main Region only ----------------- */
- WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0);
-}
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index ce07496068d..fd9420b173d 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -34,11 +34,13 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_screen.h"
#include "ED_node.h" /* own include */
#include "ED_render.h"
#include "ED_screen.h"
+#include "ED_space_api.h"
#include "ED_spreadsheet.h"
#include "ED_util.h"
@@ -50,6 +52,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"
@@ -57,127 +62,12 @@
#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::Vector;
-
-/* -------------------------------------------------------------------- */
-/** \name Relations Helpers
- * \{ */
-
-static bool ntree_has_drivers(bNodeTree &ntree)
-{
- const AnimData *adt = BKE_animdata_from_id(&ntree.id);
- if (adt == nullptr) {
- return false;
- }
- return !BLI_listbase_is_empty(&adt->drivers);
-}
-
-static bool ntree_check_nodes_connected_dfs(bNodeTree &ntree, bNode &from, bNode &to)
-{
- if (from.flag & NODE_TEST) {
- return false;
- }
- from.flag |= NODE_TEST;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
- if (link->fromnode == &from) {
- if (link->tonode == &to) {
- return true;
- }
-
- if (ntree_check_nodes_connected_dfs(ntree, *link->tonode, to)) {
- return true;
- }
- }
- }
- return false;
-}
-
-static bool ntree_check_nodes_connected(bNodeTree &ntree, bNode &from, bNode &to)
-{
- if (&from == &to) {
- return true;
- }
- ntreeNodeFlagSet(&ntree, NODE_TEST, false);
- return ntree_check_nodes_connected_dfs(ntree, from, to);
-}
-
-static bool node_group_has_output_dfs(bNode &node)
-{
- bNodeTree *ntree = (bNodeTree *)node.id;
- if (ntree->id.tag & LIB_TAG_DOIT) {
- return false;
- }
- ntree->id.tag |= LIB_TAG_DOIT;
- LISTBASE_FOREACH (bNode *, current_node, &ntree->nodes) {
- if (current_node->type == NODE_GROUP) {
- if (current_node->id && node_group_has_output_dfs(*current_node)) {
- return true;
- }
- }
- if (current_node->flag & NODE_DO_OUTPUT && current_node->type != NODE_GROUP_OUTPUT) {
- return true;
- }
- }
- return false;
-}
-
-static bool node_group_has_output(Main &bmain, bNode &node)
-{
- BLI_assert(ELEM(node.type, NODE_GROUP, NODE_CUSTOM_GROUP));
- bNodeTree *ntree = (bNodeTree *)node.id;
- if (ntree == nullptr) {
- return false;
- }
- BKE_main_id_tag_listbase(&bmain.nodetrees, LIB_TAG_DOIT, false);
- return node_group_has_output_dfs(node);
-}
-
-bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node)
-{
- /* Special case for drivers: if node tree has any drivers we assume it is
- * always to be tagged for update when node changes. Otherwise we will be
- * doomed to do some deep and nasty deep search of indirect dependencies,
- * which will be too complicated without real benefit.
- */
- if (ntree_has_drivers(ntree)) {
- return true;
- }
- LISTBASE_FOREACH (bNode *, current_node, &ntree.nodes) {
- /* Special case for group nodes -- if modified node connected to a group
- * with active output inside we consider refresh is needed.
- *
- * We could make check more grained here by taking which socket the node
- * is connected to and so eventually.
- */
- if (ELEM(current_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
- if (current_node->id != nullptr && ntree_has_drivers((bNodeTree &)current_node->id)) {
- return true;
- }
- if (ntree_check_nodes_connected(ntree, node, *current_node) &&
- node_group_has_output(bmain, *current_node)) {
- return true;
- }
- }
- if (current_node->flag & NODE_DO_OUTPUT) {
- if (ntree_check_nodes_connected(ntree, node, *current_node)) {
- return true;
- }
- }
- if (current_node->type == GEO_NODE_VIEWER) {
- if (ntree_check_nodes_connected(ntree, node, *current_node)) {
- return true;
- }
- }
- }
- return false;
-}
-
-/** \} */
/* -------------------------------------------------------------------- */
/** \name Add Node
@@ -206,9 +96,11 @@ static void clear_picking_highlight(ListBase *links)
}
}
-static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, bNodeSocket &sock)
+namespace blender::ed::space_node {
+
+static bNodeLink *create_drag_link(bNode &node, bNodeSocket &sock)
{
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), __func__);
+ bNodeLink *oplink = MEM_cnew<bNodeLink>(__func__);
if (sock.in_out == SOCK_OUT) {
oplink->fromnode = &node;
oplink->fromsock = &sock;
@@ -218,27 +110,17 @@ static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, b
oplink->tosock = &sock;
}
oplink->flag |= NODE_LINK_VALID;
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, *snode.edittree, node)) {
- oplink->flag |= NODE_LINK_TEST;
- }
oplink->flag |= NODE_LINK_DRAGGED;
return oplink;
}
-static void pick_link(const bContext &C,
- wmOperator &op,
- bNodeLinkDrag &nldrag,
- SpaceNode &snode,
- bNode *node,
- bNodeLink &link_to_pick)
+static void pick_link(
+ wmOperator &op, bNodeLinkDrag &nldrag, SpaceNode &snode, bNode *node, bNodeLink &link_to_pick)
{
clear_picking_highlight(&snode.edittree->links);
RNA_boolean_set(op.ptr, "has_link_picked", true);
- Main *bmain = CTX_data_main(&C);
- bNodeLink *link = create_drag_link(
- *bmain, snode, *link_to_pick.fromnode, *link_to_pick.fromsock);
+ bNodeLink *link = create_drag_link(*link_to_pick.fromnode, *link_to_pick.fromsock);
nldrag.links.append(link);
nodeRemLink(snode.edittree, &link_to_pick);
@@ -250,7 +132,7 @@ static void pick_link(const bContext &C,
/* Send changed event to original link->tonode. */
if (node) {
- snode_update(snode, node);
+ BKE_ntree_update_tag_node_property(snode.edittree, node);
}
}
@@ -316,7 +198,7 @@ static void pick_input_link_by_link_intersect(const bContext &C,
ED_area_tag_redraw(CTX_wm_area(&C));
if (!node_find_indicated_socket(*snode, &node, &socket, cursor, SOCK_IN)) {
- pick_link(C, op, nldrag, *snode, node, *link_to_pick);
+ pick_link(op, nldrag, *snode, node, *link_to_pick);
}
}
}
@@ -328,7 +210,10 @@ static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, con
}
if (!allow_used && (sock->flag & SOCK_IN_USE)) {
- return false;
+ /* Multi input sockets are available (even if used). */
+ if (!(sock->flag & SOCK_MULTI_INPUT)) {
+ return false;
+ }
}
return true;
@@ -558,7 +443,7 @@ static void snode_autoconnect(Main &bmain,
}
if (numlinks > 0) {
- ntreeUpdateTree(&bmain, ntree);
+ BKE_ntree_update_main_tree(&bmain, ntree, nullptr);
}
}
@@ -568,7 +453,7 @@ static void snode_autoconnect(Main &bmain,
/** \name Link Viewer Operator
* \{ */
-namespace blender::ed::nodes::viewer_linking {
+namespace viewer_linking {
/* Depending on the node tree type, different socket types are supported by viewer nodes. */
static bool socket_can_be_viewed(const OutputSocketRef &socket)
@@ -632,7 +517,7 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
(eNodeSocketDatatype)src_socket.type);
BLI_assert(data_type != CD_AUTO_FROM_NAME);
storage->data_type = data_type;
- nodeUpdate(&ntree, &viewer_node);
+ viewer_node.typeinfo->updatefunc(&ntree, &viewer_node);
return viewer_socket;
}
}
@@ -802,7 +687,7 @@ static int link_socket_to_viewer(const bContext &C,
else {
link_to_change->fromnode = &bnode_to_view;
link_to_change->fromsock = &bsocket_to_view;
- btree.update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_changed(&btree);
}
remove_links_to_unavailable_viewer_sockets(btree, *viewer_bnode);
@@ -811,10 +696,7 @@ static int link_socket_to_viewer(const bContext &C,
ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(&C), &snode, viewer_bnode);
}
- ntreeUpdateTree(CTX_data_main(&C), &btree);
- snode_update(snode, viewer_bnode);
- DEG_id_tag_update(&btree.id, 0);
-
+ ED_node_tree_propagate_change(&C, CTX_data_main(&C), &btree);
return OPERATOR_FINISHED;
}
@@ -838,7 +720,7 @@ static int node_link_viewer(const bContext &C, bNode &bnode_to_view)
return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view);
}
-} // namespace blender::ed::nodes::viewer_linking
+} // namespace viewer_linking
static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -851,11 +733,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 (viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) {
return OPERATOR_CANCELLED;
}
- snode_notify(*C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -890,6 +772,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];
@@ -952,22 +911,14 @@ static void node_remove_extra_links(SpaceNode &snode, bNodeLink &link)
static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
{
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;
for (bNodeLink *link : nldrag->links) {
- /* See note below, but basically TEST flag means that the link
- * was connected to output (or to a node which affects the
- * output).
- */
- do_tag_update |= (link->flag & NODE_LINK_TEST) != 0;
-
link->flag &= ~NODE_LINK_DRAGGED;
if (apply_links && link->tosock && link->fromsock) {
@@ -983,20 +934,10 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
/* add link to the node tree */
BLI_addtail(&ntree.links, link);
-
- ntree.update |= NTREE_UPDATE_LINKS;
-
- /* tag tonode for update */
- link->tonode->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_link_added(&ntree, link);
/* we might need to remove a link */
node_remove_extra_links(snode, *link);
-
- if (link->tonode) {
- do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, ntree, *link->tonode));
- }
-
- reset_view = false;
}
else {
nodeRemLink(&ntree, link);
@@ -1004,15 +945,14 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
}
ntree.is_updating = false;
- ntreeUpdateTree(bmain, &ntree);
- snode_notify(C, snode);
- if (do_tag_update) {
- snode_dag_update(C, snode);
- }
+ ED_node_tree_propagate_change(&C, bmain, &ntree);
- 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);
snode.runtime->linkdrag.reset();
}
@@ -1099,12 +1039,15 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur
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);
UI_view2d_edge_pan_apply_event(C, &nldrag->pan_data, event);
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:
@@ -1117,29 +1060,50 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
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) {
+ invoke_node_link_drag_add_menu(*C, *link.fromnode, *link.fromsock, cursor);
+ }
+ else {
+ 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);
return OPERATOR_FINISHED;
}
break;
}
+ case EVT_ESCKEY: {
+ node_link_exit(*C, *op, true);
+ return OPERATOR_FINISHED;
+ }
}
return OPERATOR_RUNNING_MODAL;
}
-static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
- SpaceNode &snode,
+static std::unique_ptr<bNodeLinkDrag> node_link_init(SpaceNode &snode,
float2 cursor,
const bool detach)
{
@@ -1148,32 +1112,22 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
bNodeSocket *sock;
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) {
std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>();
-
- const int num_links = nodeCountSocketLinks(snode.edittree, sock);
+ 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) {
if (link->fromsock == sock) {
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
+ bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link");
*oplink = *link;
oplink->next = oplink->prev = nullptr;
oplink->flag |= NODE_LINK_VALID;
oplink->flag |= NODE_LINK_DRAGGED;
- /* The link could be disconnected and in that case we
- * wouldn't be able to check whether tag update is
- * needed or not when releasing mouse button. So we
- * cache whether the link affects output or not here
- * using TEST flag.
- */
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, *snode.edittree, *link->tonode)) {
- oplink->flag |= NODE_LINK_TEST;
- }
-
nldrag->links.append(oplink);
nodeRemLink(snode.edittree, link);
}
@@ -1183,7 +1137,7 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
/* dragged links are fixed on output side */
nldrag->in_out = SOCK_OUT;
/* create a new link */
- nldrag->links.append(create_drag_link(bmain, snode, *node, *sock));
+ nldrag->links.append(create_drag_link(*node, *sock));
}
return nldrag;
}
@@ -1192,9 +1146,11 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
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 */
@@ -1209,22 +1165,18 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
}
if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) {
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
+ bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link");
*oplink = *link_to_pick;
oplink->next = oplink->prev = nullptr;
oplink->flag |= NODE_LINK_VALID;
oplink->flag |= NODE_LINK_DRAGGED;
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, *snode.edittree, *link_to_pick->tonode)) {
- oplink->flag |= NODE_LINK_TEST;
- }
nldrag->links.append(oplink);
nodeRemLink(snode.edittree, link_to_pick);
/* send changed event to original link->tonode */
if (node) {
- snode_update(snode, node);
+ BKE_ntree_update_tag_node_property(snode.edittree, node);
}
}
}
@@ -1232,7 +1184,7 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
/* dragged links are fixed on input side */
nldrag->in_out = SOCK_IN;
/* create a new link */
- nldrag->links.append(create_drag_link(bmain, snode, *node, *sock));
+ nldrag->links.append(create_drag_link(*node, *sock));
}
return nldrag;
}
@@ -1255,11 +1207,15 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
- std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(bmain, snode, cursor, detach);
+ std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(snode, cursor, detach);
if (nldrag) {
UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op);
+ /* 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();
@@ -1354,9 +1310,7 @@ static int node_make_link_exec(bContext *C, wmOperator *op)
node_deselect_all_input_sockets(snode, false);
node_deselect_all_output_sockets(snode, false);
- ntreeUpdateTree(CTX_data_main(C), snode.edittree);
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -1413,7 +1367,6 @@ static int cut_links_exec(bContext *C, wmOperator *op)
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
ARegion &region = *CTX_wm_region(C);
- bool do_tag_update = false;
int i = 0;
float mcoords[256][2];
@@ -1448,23 +1401,14 @@ static int cut_links_exec(bContext *C, wmOperator *op)
found = true;
}
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, *snode.edittree, *link->tonode));
-
- snode_update(snode, link->tonode);
bNode *to_node = link->tonode;
nodeRemLink(snode.edittree, link);
sort_multi_input_socket_links(snode, *to_node, nullptr, nullptr);
}
}
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
if (found) {
- ntreeUpdateTree(CTX_data_main(C), snode.edittree);
- snode_notify(*C, snode);
- if (do_tag_update) {
- snode_dag_update(*C, snode);
- }
-
return OPERATOR_FINISHED;
}
@@ -1510,7 +1454,6 @@ static int mute_links_exec(bContext *C, wmOperator *op)
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
ARegion &region = *CTX_wm_region(C);
- bool do_tag_update = false;
int i = 0;
float mcoords[256][2];
@@ -1552,10 +1495,6 @@ static int mute_links_exec(bContext *C, wmOperator *op)
}
if (node_links_intersect(*link, mcoords, i)) {
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, *snode.edittree, *link->tonode));
-
- snode_update(snode, link->tonode);
nodeMuteLinkToggle(snode.edittree, link);
}
}
@@ -1568,12 +1507,7 @@ static int mute_links_exec(bContext *C, wmOperator *op)
link->flag &= ~NODE_LINK_TEST;
}
- ntreeUpdateTree(CTX_data_main(C), snode.edittree);
- snode_notify(*C, snode);
- if (do_tag_update) {
- snode_dag_update(*C, snode);
- }
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -1624,11 +1558,7 @@ static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), &ntree);
-
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
return OPERATOR_FINISHED;
}
@@ -1654,14 +1584,14 @@ void NODE_OT_links_detach(wmOperatorType *ot)
static int node_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
- bNode *frame = nodeGetActive(ntree);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
+ bNode *frame = nodeGetActive(&ntree);
if (!frame || frame->type != NODE_FRAME) {
return OPERATOR_CANCELLED;
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (node == frame) {
continue;
}
@@ -1671,7 +1601,7 @@ static int node_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -1768,7 +1698,7 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ED_node_sort(&ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -1795,15 +1725,15 @@ void NODE_OT_join(wmOperatorType *ot)
/** \name Attach Operator
* \{ */
-static bNode *node_find_frame_to_attach(ARegion *region,
- const bNodeTree *ntree,
+static bNode *node_find_frame_to_attach(ARegion &region,
+ const bNodeTree &ntree,
const int mouse_xy[2])
{
/* convert mouse coordinates to v2d space */
float cursor[2];
- UI_view2d_region_to_view(&region->v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]);
+ UI_view2d_region_to_view(&region.v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]);
- LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree->nodes) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree.nodes) {
/* skip selected, those are the nodes we want to attach */
if ((frame->type != NODE_FRAME) || (frame->flag & NODE_SELECT)) {
continue;
@@ -1818,13 +1748,13 @@ static bNode *node_find_frame_to_attach(ARegion *region,
static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- ARegion *region = CTX_wm_region(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
+ ARegion &region = *CTX_wm_region(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
bNode *frame = node_find_frame_to_attach(region, ntree, event->mval);
if (frame) {
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) {
if (node->flag & NODE_SELECT) {
if (node->parent == nullptr) {
/* disallow moving a parent into its child */
@@ -1854,7 +1784,7 @@ static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -1914,23 +1844,23 @@ static void node_detach_recursive(bNode *node)
/* detach the root nodes in the current selection */
static int node_detach_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;
/* reset tags */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
node->done = 0;
}
/* detach nodes recursively
* relative order is preserved here!
*/
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
if (!(node->done & NODE_DETACH_DONE)) {
node_detach_recursive(node);
}
}
- ED_node_sort(ntree);
+ node_sort(ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2015,8 +1945,12 @@ static bool ed_node_link_conditions(ScrArea *area,
return true;
}
+} // namespace blender::ed::space_node
+
void ED_node_link_intersect_test(ScrArea *area, int test)
{
+ using namespace blender::ed::space_node;
+
bNode *select;
SpaceNode *snode;
if (!ed_node_link_conditions(area, test, &snode, &select)) {
@@ -2076,6 +2010,8 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
}
}
+namespace blender::ed::space_node {
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2115,20 +2051,17 @@ static int get_main_socket_priority(const bNodeSocket *socket)
/** Get the "main" socket based on the node declaration or an heuristic. */
static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out)
{
- using namespace blender;
- using namespace blender::nodes;
-
ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs;
/* Try to get the main socket based on the socket declaration. */
nodeDeclarationEnsure(&ntree, &node);
- const NodeDeclaration *node_decl = node.declaration;
+ const nodes::NodeDeclaration *node_decl = node.declaration;
if (node_decl != nullptr) {
- Span<SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() :
- node_decl->outputs();
+ Span<nodes::SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() :
+ node_decl->outputs();
int index;
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) {
- const SocketDeclaration &socket_decl = *socket_decls[index];
+ const nodes::SocketDeclaration &socket_decl = *socket_decls[index];
if (nodeSocketIsHidden(socket)) {
continue;
}
@@ -2305,7 +2238,7 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd,
/* 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)
@@ -2492,12 +2425,16 @@ void NODE_OT_insert_offset(wmOperatorType *ot)
/** \} */
+} // namespace blender::ed::space_node
+
/* -------------------------------------------------------------------- */
/** \name Note Link Insert
* \{ */
void ED_node_link_insert(Main *bmain, ScrArea *area)
{
+ using namespace blender::ed::space_node;
+
bNode *select;
SpaceNode *snode;
if (!ed_node_link_conditions(area, true, &snode, &select)) {
@@ -2534,8 +2471,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
/* set up insert offset data, it needs stuff from here */
if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
- NodeInsertOfsData *iofsd = (NodeInsertOfsData *)MEM_callocN(sizeof(NodeInsertOfsData),
- __func__);
+ NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__);
iofsd->insert = select;
iofsd->prev = link->fromnode;
@@ -2544,10 +2480,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
snode->runtime->iofsd = iofsd;
}
- ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */
- snode_update(*snode, select);
- ED_node_tag_update_id((ID *)snode->edittree);
- ED_node_tag_update_id(snode->id);
+ ED_node_tree_propagate_change(nullptr, bmain, snode->edittree);
}
}
}
diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc
index 334ca1f76ee..2751a53e8af 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -62,7 +62,7 @@
#include "node_intern.hh" /* own include */
-using blender::float2;
+namespace blender::ed::space_node {
/**
* Function to detect if there is a visible view3d that uses workbench in texture mode.
@@ -111,11 +111,13 @@ static bNode *node_under_mouse_select(bNodeTree &ntree, int mx, int my)
static bNode *node_under_mouse_tweak(bNodeTree &ntree, const float2 &mouse)
{
+ using namespace blender::math;
+
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) {
+ if (distance(mouse, location) < 24.0f) {
return node;
}
}
@@ -278,57 +280,51 @@ void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_node
/* Return true if we need redraw, otherwise false. */
-static bool node_select_grouped_type(SpaceNode *snode, bNode *node_act)
+static bool node_select_grouped_type(bNodeTree &node_tree, bNode &node_act)
{
- bNode *node;
bool changed = false;
-
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if ((node->flag & SELECT) == 0) {
- if (node->type == node_act->type) {
+ if (node->type == node_act.type) {
nodeSetSelected(node, true);
changed = true;
}
}
}
-
return changed;
}
-static bool node_select_grouped_color(SpaceNode *snode, bNode *node_act)
+static bool node_select_grouped_color(bNodeTree &node_tree, bNode &node_act)
{
bool changed = false;
-
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if ((node->flag & SELECT) == 0) {
- if (compare_v3v3(node->color, node_act->color, 0.005f)) {
+ if (compare_v3v3(node->color, node_act.color, 0.005f)) {
nodeSetSelected(node, true);
changed = true;
}
}
}
-
return changed;
}
-static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bool from_right)
+static bool node_select_grouped_name(bNodeTree &node_tree, bNode &node_act, const bool from_right)
{
- bNode *node;
bool changed = false;
const uint delims[] = {'.', '-', '_', '\0'};
size_t pref_len_act, pref_len_curr;
const char *sep, *suf_act, *suf_curr;
pref_len_act = BLI_str_partition_ex_utf8(
- node_act->name, nullptr, delims, &sep, &suf_act, from_right);
+ node_act.name, nullptr, delims, &sep, &suf_act, from_right);
/* NOTE: in case we are searching for suffix, and found none, use whole name as suffix. */
if (from_right && !(sep && suf_act)) {
pref_len_act = 0;
- suf_act = node_act->name;
+ suf_act = node_act.name;
}
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if (node->flag & SELECT) {
continue;
}
@@ -343,7 +339,7 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo
if ((from_right && STREQ(suf_act, suf_curr)) ||
(!from_right && (pref_len_act == pref_len_curr) &&
- STREQLEN(node_act->name, node->name, pref_len_act))) {
+ STREQLEN(node_act.name, node->name, pref_len_act))) {
nodeSetSelected(node, true);
changed = true;
}
@@ -361,20 +357,20 @@ enum {
static int node_select_grouped_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNode *node_act = nodeGetActive(snode->edittree);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
+ bNode *node_act = nodeGetActive(snode.edittree);
if (node_act == nullptr) {
return OPERATOR_CANCELLED;
}
- bNode *node;
bool changed = false;
const bool extend = RNA_boolean_get(op->ptr, "extend");
const int type = RNA_enum_get(op->ptr, "type");
if (!extend) {
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
nodeSetSelected(node, false);
}
}
@@ -382,23 +378,23 @@ static int node_select_grouped_exec(bContext *C, wmOperator *op)
switch (type) {
case NODE_SELECT_GROUPED_TYPE:
- changed = node_select_grouped_type(snode, node_act);
+ changed = node_select_grouped_type(node_tree, *node_act);
break;
case NODE_SELECT_GROUPED_COLOR:
- changed = node_select_grouped_color(snode, node_act);
+ changed = node_select_grouped_color(node_tree, *node_act);
break;
case NODE_SELECT_GROUPED_PREFIX:
- changed = node_select_grouped_name(snode, node_act, false);
+ changed = node_select_grouped_name(node_tree, *node_act, false);
break;
case NODE_SELECT_GROUPED_SUFIX:
- changed = node_select_grouped_name(snode, node_act, true);
+ changed = node_select_grouped_name(node_tree, *node_act, true);
break;
default:
break;
}
if (changed) {
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
}
@@ -449,26 +445,26 @@ void NODE_OT_select_grouped(wmOperatorType *ot)
void node_select_single(bContext &C, bNode &node)
{
Main *bmain = CTX_data_main(&C);
- SpaceNode *snode = CTX_wm_space_node(&C);
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ bNodeTree &node_tree = *snode.edittree;
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) {
- nodeSetSelected(tnode, false);
+ LISTBASE_FOREACH (bNode *, node_iter, &node_tree.nodes) {
+ if (node_iter != &node) {
+ nodeSetSelected(node_iter, false);
}
}
nodeSetSelected(&node, true);
- ED_node_set_active(bmain, snode, snode->edittree, &node, &active_texture_changed);
- ED_node_set_active_viewer_key(snode);
+ ED_node_set_active(bmain, &snode, &node_tree, &node, &active_texture_changed);
+ ED_node_set_active_viewer_key(&snode);
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) {
- DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&node_tree.id, ID_RECALC_COPY_ON_WRITE);
}
WM_event_add_notifier(&C, NC_NODE | NA_SELECTED, nullptr);
@@ -609,7 +605,7 @@ static int node_mouse_select(bContext *C,
ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node);
}
ED_node_set_active_viewer_key(&snode);
- ED_node_sort(snode.edittree);
+ 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);
@@ -676,20 +672,21 @@ void NODE_OT_select(wmOperatorType *ot)
static int node_box_select_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- ARegion *region = CTX_wm_region(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
+ const ARegion &region = *CTX_wm_region(C);
rctf rectf;
WM_operator_properties_border_to_rctf(op, &rectf);
- UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
+ UI_view2d_region_to_view_rctf(&region.v2d, &rectf, &rectf);
const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT);
+ node_select_all(&node_tree.nodes, SEL_DESELECT);
}
- LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
bool is_inside;
if (node->type == NODE_FRAME) {
is_inside = BLI_rctf_inside_rctf(&rectf, &node->totr);
@@ -703,7 +700,7 @@ static int node_box_select_exec(bContext *C, wmOperator *op)
}
}
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
@@ -773,7 +770,7 @@ static int node_circleselect_exec(bContext *C, wmOperator *op)
WM_gesture_is_modal_first((const wmGesture *)op->customdata));
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT);
+ node_select_all(&snode->edittree->nodes, SEL_DESELECT);
}
/* get operator properties */
@@ -848,7 +845,7 @@ static bool do_lasso_select_node(bContext *C,
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT);
+ node_select_all(&snode->edittree->nodes, SEL_DESELECT);
changed = true;
}
@@ -935,13 +932,13 @@ void NODE_OT_select_lasso(wmOperatorType *ot)
static int node_select_all_exec(bContext *C, wmOperator *op)
{
- SpaceNode *snode = CTX_wm_space_node(C);
- ListBase *node_lb = &snode->edittree->nodes;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ ListBase *node_lb = &snode.edittree->nodes;
int action = RNA_enum_get(op->ptr, "action");
- ED_node_select_all(node_lb, action);
+ node_select_all(node_lb, action);
- ED_node_sort(snode->edittree);
+ node_sort(*snode.edittree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
@@ -972,15 +969,14 @@ void NODE_OT_select_all(wmOperatorType *ot)
static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeLink *link;
- bNode *node;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
node->flag &= ~NODE_TEST;
}
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
+ LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
if (nodeLinkIsHidden(link)) {
continue;
}
@@ -989,13 +985,13 @@ static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if (node->flag & NODE_TEST) {
nodeSetSelected(node, true);
}
}
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
@@ -1024,15 +1020,14 @@ void NODE_OT_select_linked_to(wmOperatorType *ot)
static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeLink *link;
- bNode *node;
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &node_tree = *snode.edittree;
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
node->flag &= ~NODE_TEST;
}
- for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) {
+ LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) {
if (nodeLinkIsHidden(link)) {
continue;
}
@@ -1041,13 +1036,13 @@ static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
if (node->flag & NODE_TEST) {
nodeSetSelected(node, true);
}
}
- ED_node_sort(snode->edittree);
+ node_sort(node_tree);
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
return OPERATOR_FINISHED;
@@ -1314,3 +1309,5 @@ void NODE_OT_find_node(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc
index 386178596af..113e2bd3bb3 100644
--- a/source/blender/editors/space_node/node_templates.cc
+++ b/source/blender/editors/space_node/node_templates.cc
@@ -37,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_node_tree_update.h"
#include "RNA_access.h"
@@ -52,9 +53,10 @@
#include "ED_undo.h"
-using blender::Vector;
using blender::nodes::NodeDeclaration;
+namespace blender::ed::space_node {
+
/************************* Node Socket Manipulation **************************/
/* describes an instance of a node type and a specific socket to link */
@@ -84,7 +86,7 @@ static void node_link_item_apply(Main *bmain, bNode *node, NodeLinkItem *item)
{
if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
node->id = (ID *)item->ngroup;
- ntreeUpdateTree(bmain, item->ngroup);
+ BKE_ntree_update_main_tree(bmain, item->ngroup, nullptr);
}
else {
/* nothing to do for now */
@@ -179,10 +181,8 @@ static void node_socket_disconnect(Main *bmain,
nodeRemLink(ntree, sock_to->link);
sock_to->flag |= SOCK_COLLAPSED;
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* remove all nodes connected to this socket, if they aren't connected to other nodes */
@@ -195,10 +195,8 @@ static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bN
node_remove_linked(bmain, ntree, sock_to->link->fromnode);
sock_to->flag |= SOCK_COLLAPSED;
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* add new node connected to this socket, or replace an existing one */
@@ -299,11 +297,9 @@ static void node_socket_add_replace(const bContext *C,
node_remove_linked(bmain, ntree, node_prev);
}
- nodeUpdate(ntree, node_from);
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- ED_node_tag_update_nodetree(CTX_data_main(C), ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_from);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/****************************** Node Link Menu *******************************/
@@ -386,17 +382,42 @@ static Vector<NodeLinkItem> ui_node_link_items(NodeLinkArg *arg,
const SocketDeclaration &socket_decl = *socket_decl_ptr;
NodeLinkItem item;
item.socket_index = index++;
- /* A socket declaration does not necessarily map to exactly one built-in socket type. So only
- * check for the types that matter here. */
- if (dynamic_cast<const decl::Color *>(&socket_decl)) {
- item.socket_type = SOCK_RGBA;
- }
- else if (dynamic_cast<const decl::Float *>(&socket_decl)) {
+ if (dynamic_cast<const decl::Float *>(&socket_decl)) {
item.socket_type = SOCK_FLOAT;
}
+ else if (dynamic_cast<const decl::Int *>(&socket_decl)) {
+ item.socket_type = SOCK_INT;
+ }
+ else if (dynamic_cast<const decl::Bool *>(&socket_decl)) {
+ item.socket_type = SOCK_BOOLEAN;
+ }
else if (dynamic_cast<const decl::Vector *>(&socket_decl)) {
item.socket_type = SOCK_VECTOR;
}
+ else if (dynamic_cast<const decl::Color *>(&socket_decl)) {
+ item.socket_type = SOCK_RGBA;
+ }
+ else if (dynamic_cast<const decl::String *>(&socket_decl)) {
+ item.socket_type = SOCK_STRING;
+ }
+ else if (dynamic_cast<const decl::Image *>(&socket_decl)) {
+ item.socket_type = SOCK_IMAGE;
+ }
+ else if (dynamic_cast<const decl::Texture *>(&socket_decl)) {
+ item.socket_type = SOCK_TEXTURE;
+ }
+ else if (dynamic_cast<const decl::Material *>(&socket_decl)) {
+ item.socket_type = SOCK_MATERIAL;
+ }
+ else if (dynamic_cast<const decl::Shader *>(&socket_decl)) {
+ item.socket_type = SOCK_SHADER;
+ }
+ else if (dynamic_cast<const decl::Collection *>(&socket_decl)) {
+ item.socket_type = SOCK_COLLECTION;
+ }
+ else if (dynamic_cast<const decl::Object *>(&socket_decl)) {
+ item.socket_type = SOCK_OBJECT;
+ }
else {
item.socket_type = SOCK_CUSTOM;
}
@@ -696,15 +717,19 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
}
+} // namespace blender::ed::space_node
+
void uiTemplateNodeLink(
uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
{
+ using namespace blender::ed::space_node;
+
uiBlock *block = uiLayoutGetBlock(layout);
NodeLinkArg *arg;
uiBut *but;
float socket_col[4];
- arg = (NodeLinkArg *)MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
+ arg = MEM_new<NodeLinkArg>("NodeLinkArg");
arg->ntree = ntree;
arg->node = node;
arg->sock = input;
@@ -740,6 +765,8 @@ void uiTemplateNodeLink(
}
}
+namespace blender::ed::space_node {
+
/**************************** Node Tree Layout *******************************/
static void ui_node_draw_input(
@@ -892,9 +919,13 @@ static void ui_node_draw_input(
node->flag &= ~NODE_TEST;
}
+} // namespace blender::ed::space_node
+
void uiTemplateNodeView(
uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
{
+ using namespace blender::ed::space_node;
+
bNode *tnode;
if (!ntree) {
diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc
index df629a983e3..9d99709a780 100644
--- a/source/blender/editors/space_node/node_view.cc
+++ b/source/blender/editors/space_node/node_view.cc
@@ -55,7 +55,7 @@
#include "node_intern.hh" /* own include */
-using blender::StringRef;
+namespace blender::ed::space_node {
/* -------------------------------------------------------------------- */
/** \name View All Operator
@@ -255,7 +255,7 @@ static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *
return OPERATOR_CANCELLED;
}
- nvm = (NodeViewMove *)MEM_callocN(sizeof(NodeViewMove), "NodeViewMove struct");
+ nvm = MEM_cnew<NodeViewMove>("NodeViewMove struct");
op->customdata = nvm;
nvm->mvalo[0] = event->mval[0];
nvm->mvalo[1] = event->mval[1];
@@ -444,6 +444,8 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
}
}
+} // namespace blender::ed::space_node
+
bool ED_space_node_get_position(
Main *bmain, SpaceNode *snode, struct ARegion *region, const int mval[2], float fpos[2])
{
@@ -526,6 +528,8 @@ bool ED_space_node_color_sample(
return ret;
}
+namespace blender::ed::space_node {
+
static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
@@ -643,7 +647,7 @@ static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- info = (ImageSampleInfo *)MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
+ info = MEM_cnew<ImageSampleInfo>("ImageSampleInfo");
info->art = region->type;
info->draw_handle = ED_region_draw_cb_activate(
region->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
@@ -783,3 +787,5 @@ void NODE_OT_geometry_node_view_legacy(wmOperatorType *ot)
}
/** \} */
+
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index f3b95ca2024..00fd328b2ed 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -31,6 +31,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_node.h"
#include "BKE_screen.h"
@@ -63,7 +64,7 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
BLI_listbase_clear(&snode->treepath);
if (ntree) {
- bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path");
+ bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path");
path->nodetree = ntree;
path->parent_key = NODE_INSTANCE_KEY_BASE;
@@ -96,7 +97,7 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
{
- bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path");
+ bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path");
bNodeTreePath *prev_path = (bNodeTreePath *)snode->treepath.last;
path->nodetree = ntree;
if (gnode) {
@@ -206,6 +207,18 @@ void ED_node_set_active_viewer_key(SpaceNode *snode)
}
}
+void ED_node_cursor_location_get(const SpaceNode *snode, float value[2])
+{
+ copy_v2_v2(value, snode->runtime->cursor);
+}
+
+void ED_node_cursor_location_set(SpaceNode *snode, const float value[2])
+{
+ copy_v2_v2(snode->runtime->cursor, value);
+}
+
+namespace blender::ed::space_node {
+
float2 space_node_group_offset(const SpaceNode &snode)
{
const bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
@@ -220,7 +233,7 @@ float2 space_node_group_offset(const SpaceNode &snode)
static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
- SpaceNode *snode = (SpaceNode *)MEM_callocN(sizeof(SpaceNode), "initnode");
+ SpaceNode *snode = MEM_cnew<SpaceNode>("initnode");
snode->spacetype = SPACE_NODE;
snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA;
@@ -238,21 +251,21 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
NODE_TREE_TYPES_END;
/* header */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "header for node");
+ ARegion *region = MEM_cnew<ARegion>("header for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
/* buttons/list view */
- region = (ARegion *)MEM_callocN(sizeof(ARegion), "buttons for node");
+ region = MEM_cnew<ARegion>("buttons for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
/* toolbar */
- region = (ARegion *)MEM_callocN(sizeof(ARegion), "node tools");
+ region = MEM_cnew<ARegion>("node tools");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_TOOLS;
@@ -261,7 +274,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
region->flag = RGN_FLAG_HIDDEN;
/* main region */
- region = (ARegion *)MEM_callocN(sizeof(ARegion), "main region for node");
+ region = MEM_cnew<ARegion>("main region for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
@@ -309,8 +322,21 @@ static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area)
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
if (snode->runtime == nullptr) {
- snode->runtime = (SpaceNode_Runtime *)MEM_callocN(sizeof(SpaceNode_Runtime), __func__);
+ snode->runtime = MEM_new<SpaceNode_Runtime>(__func__);
+ }
+}
+
+static bool any_node_uses_id(const bNodeTree *ntree, const ID *id)
+{
+ if (ELEM(nullptr, ntree, id)) {
+ return false;
}
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == id) {
+ return true;
+ }
+ }
+ return false;
}
static void node_area_listener(const wmSpaceTypeListenerParams *params)
@@ -370,9 +396,6 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
else if (wmn->data == ND_SHADING_LINKS) {
ED_area_tag_refresh(area);
}
- else if (wmn->action == NA_ADDED && snode->edittree) {
- nodeSetActiveID(snode->edittree, ID_MA, (ID *)wmn->reference);
- }
}
break;
case NC_TEXTURE:
@@ -436,10 +459,9 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
case NC_IMAGE:
if (wmn->action == NA_EDITED) {
if (ED_node_is_compositor(snode)) {
- /* note that nodeUpdateID is already called by BKE_image_signal() on all
- * scenes so really this is just to know if the images is used in the compo else
- * painting on images could become very slow when the compositor is open. */
- if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) {
+ /* Without this check drawing on an image could become very slow when the compositor is
+ * open. */
+ if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) {
ED_area_tag_refresh(area);
}
}
@@ -449,7 +471,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
case NC_MOVIECLIP:
if (wmn->action == NA_EDITED) {
if (ED_node_is_compositor(snode)) {
- if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) {
+ if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) {
ED_area_tag_refresh(area);
}
}
@@ -482,27 +504,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area)
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 */
@@ -515,12 +517,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);
- }
- }
}
}
@@ -573,16 +569,6 @@ static void node_toolbar_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-void ED_node_cursor_location_get(const SpaceNode *snode, float value[2])
-{
- copy_v2_v2(value, snode->runtime->cursor);
-}
-
-void ED_node_cursor_location_set(SpaceNode *snode, const float value[2])
-{
- copy_v2_v2(snode->runtime->cursor, value);
-}
-
static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region)
{
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
@@ -831,8 +817,14 @@ static void node_region_listener(const wmRegionListenerParams *params)
}
}
+} // namespace blender::ed::space_node
+
+/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */
const char *node_context_dir[] = {
"selected_nodes", "active_node", "light", "material", "world", nullptr};
+
+namespace blender::ed::space_node {
+
static int /*eContextResult*/ node_context(const bContext *C,
const char *member,
bContextDataResult *result)
@@ -905,9 +897,9 @@ static void node_widgets()
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_corner_pin);
}
-static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void node_id_remap_cb(ID *old_id, ID *new_id, void *user_data)
{
- SpaceNode *snode = (SpaceNode *)slink;
+ SpaceNode *snode = static_cast<SpaceNode *>(user_data);
if (snode->id == old_id) {
/* nasty DNA logic for SpaceNode:
@@ -973,6 +965,24 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I
}
}
+static void node_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
+{
+ /* Although we should be able to perform all the mappings in a single go this lead to issues when
+ * running the python test cases. Somehow the nodetree/edittree weren't updated to the new
+ * pointers that generated a SEGFAULT.
+ *
+ * To move forward we should perhaps remove snode->edittree and snode->nodetree as they are just
+ * copies of pointers. All usages should be calling a function that will receive the appropriate
+ * instance.
+ *
+ * We could also move a remap address at a time to ise the IDRemapper as that should get closer
+ * to cleaner code. See {D13615} for more information about this topic.
+ */
+ BKE_id_remapper_iter(mappings, node_id_remap_cb, slink);
+}
+
static int node_space_subtype_get(ScrArea *area)
{
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
@@ -995,9 +1005,13 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
}
}
+} // namespace blender::ed::space_node
+
void ED_spacetype_node()
{
- SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype node");
+ using namespace blender::ed::space_node;
+
+ SpaceType *st = MEM_cnew<SpaceType>("spacetype node");
ARegionType *art;
st->spaceid = SPACE_NODE;
@@ -1020,7 +1034,7 @@ void ED_spacetype_node()
st->space_subtype_set = node_space_subtype_set;
/* regions: main window */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_WINDOW;
art->init = node_main_region_init;
art->draw = node_main_region_draw;
@@ -1034,7 +1048,7 @@ void ED_spacetype_node()
BLI_addhead(&st->regiontypes, art);
/* regions: header */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
@@ -1045,7 +1059,7 @@ void ED_spacetype_node()
BLI_addhead(&st->regiontypes, art);
/* regions: listview/buttons */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
@@ -1056,7 +1070,7 @@ void ED_spacetype_node()
BLI_addhead(&st->regiontypes, art);
/* regions: toolbar */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region");
+ art = MEM_cnew<ARegionType>("spacetype view3d tools region");
art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = 58; /* XXX */
art->prefsizey = 50; /* XXX */
@@ -1068,7 +1082,5 @@ void ED_spacetype_node()
art->draw = node_toolbar_region_draw;
BLI_addhead(&st->regiontypes, art);
- node_toolbar_register(art);
-
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index c31239f0e9c..bc6db978a4f 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -34,18 +34,18 @@ set(INC
set(SRC
- outliner_collections.c
- outliner_context.c
- outliner_dragdrop.c
- outliner_draw.c
- outliner_edit.c
- outliner_ops.c
- outliner_select.c
- outliner_sync.c
- outliner_tools.c
- outliner_tree.c
- outliner_utils.c
- space_outliner.c
+ outliner_collections.cc
+ outliner_context.cc
+ outliner_dragdrop.cc
+ outliner_draw.cc
+ outliner_edit.cc
+ outliner_ops.cc
+ outliner_select.cc
+ outliner_sync.cc
+ outliner_tools.cc
+ outliner_tree.cc
+ outliner_utils.cc
+ space_outliner.cc
tree/common.cc
tree/tree_display.cc
tree/tree_display_data.cc
@@ -65,13 +65,14 @@ set(SRC
tree/tree_element_id_scene.cc
tree/tree_element_nla.cc
tree/tree_element_overrides.cc
+ tree/tree_element_rna.cc
tree/tree_element_scene_objects.cc
+ tree/tree_element_seq.cc
tree/tree_element_view_layer.cc
- outliner_intern.h
- tree/tree_display.h
+ outliner_intern.hh
+ tree/common.hh
tree/tree_display.hh
- tree/tree_element.h
tree/tree_element.hh
tree/tree_element_anim_data.hh
tree/tree_element_collection.hh
@@ -82,7 +83,9 @@ set(SRC
tree/tree_element_id_scene.hh
tree/tree_element_nla.hh
tree/tree_element_overrides.hh
+ tree/tree_element_rna.hh
tree/tree_element_scene_objects.hh
+ tree/tree_element_seq.hh
tree/tree_element_view_layer.hh
)
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.cc
index 946d7a0538d..8d60a6088d3 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.cc
@@ -18,7 +18,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -49,7 +49,7 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-#include "outliner_intern.h" /* own include */
+#include "outliner_intern.hh" /* own include */
/* -------------------------------------------------------------------- */
/** \name Utility API
@@ -81,11 +81,11 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
TreeStoreElem *tselem = TREESTORE(te);
if (!tselem) {
- return NULL;
+ return nullptr;
}
if (tselem->type == TSE_LAYER_COLLECTION) {
- LayerCollection *lc = te->directdata;
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
return lc->collection;
}
if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
@@ -96,12 +96,12 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te)
return (Collection *)tselem->id;
}
- return NULL;
+ return nullptr;
}
TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata)
{
- struct IDsSelectedData *data = customdata;
+ struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (outliner_is_collection_tree_element(te)) {
@@ -118,14 +118,15 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu
TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata)
{
- struct IDsSelectedData *data = customdata;
+ struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (outliner_is_collection_tree_element(te)) {
return TRAVERSE_CONTINUE;
}
- if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id == nullptr) ||
+ (GS(tselem->id->name) != ID_OB)) {
return TRAVERSE_SKIP_CHILDS;
}
@@ -137,7 +138,7 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom
void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct IDsSelectedData data = {{NULL}};
+ struct IDsSelectedData data = {{nullptr}};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
0,
@@ -161,14 +162,14 @@ void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
bool ED_outliner_collections_editor_poll(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- return (space_outliner != NULL) &&
+ return (space_outliner != nullptr) &&
ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES);
}
static bool outliner_view_layer_collections_editor_poll(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- return (space_outliner != NULL) && (space_outliner->outlinevis == SO_VIEW_LAYER);
+ return (space_outliner != nullptr) && (space_outliner->outlinevis == SO_VIEW_LAYER);
}
static bool collection_edit_in_active_scene_poll(bContext *C)
@@ -196,14 +197,14 @@ struct CollectionNewData {
static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
{
- struct CollectionNewData *data = customdata;
+ struct CollectionNewData *data = reinterpret_cast<CollectionNewData *>(customdata);
Collection *collection = outliner_collection_from_tree_element(te);
if (!collection) {
return TRAVERSE_SKIP_CHILDS;
}
- if (data->collection != NULL) {
+ if (data->collection != nullptr) {
data->error = true;
return TRAVERSE_BREAK;
}
@@ -220,10 +221,7 @@ static int collection_new_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- struct CollectionNewData data = {
- .error = false,
- .collection = NULL,
- };
+ CollectionNewData data{};
if (RNA_boolean_get(op->ptr, "nested")) {
outliner_build_tree(bmain, scene, view_layer, space_outliner, region);
@@ -241,7 +239,7 @@ static int collection_new_exec(bContext *C, wmOperator *op)
}
}
- if (data.collection == NULL || ID_IS_LINKED(data.collection) ||
+ if (data.collection == nullptr || ID_IS_LINKED(data.collection) ||
ID_IS_OVERRIDE_LIBRARY(data.collection)) {
data.collection = scene->master_collection;
}
@@ -251,13 +249,13 @@ static int collection_new_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_collection_add(bmain, data.collection, NULL);
+ BKE_collection_add(bmain, data.collection, nullptr);
DEG_id_tag_update(&data.collection->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
outliner_cleanup_tree(space_outliner);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -295,7 +293,7 @@ struct CollectionEditData {
static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata)
{
- struct CollectionEditData *data = customdata;
+ CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata);
Collection *collection = outliner_collection_from_tree_element(te);
if (!collection) {
@@ -321,10 +319,9 @@ void outliner_collection_delete(
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
@@ -336,7 +333,8 @@ void outliner_collection_delete(
/* Effectively delete the collections. */
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
/* Test in case collection got deleted as part of another one. */
if (BLI_findindex(&bmain->collections, collection) != -1) {
@@ -358,7 +356,7 @@ void outliner_collection_delete(
BLI_assert(parent->id.flag & LIB_EMBEDDED_DATA);
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id);
- BLI_assert(id_type->owner_get != NULL);
+ BLI_assert(id_type->owner_get != nullptr);
ID *scene_owner = id_type->owner_get(bmain, &parent->id);
BLI_assert(GS(scene_owner->name) == ID_SCE);
@@ -384,9 +382,11 @@ void outliner_collection_delete(
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -400,7 +400,7 @@ static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
if (basact_prev != BASACT(view_layer)) {
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
@@ -410,6 +410,7 @@ static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+}
void OUTLINER_OT_collection_hierarchy_delete(wmOperatorType *ot)
{
@@ -440,12 +441,12 @@ struct CollectionObjectsSelectData {
static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te,
void *customdata)
{
- struct CollectionObjectsSelectData *data = customdata;
+ CollectionObjectsSelectData *data = reinterpret_cast<CollectionObjectsSelectData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
switch (tselem->type) {
case TSE_LAYER_COLLECTION:
- data->layer_collection = te->directdata;
+ data->layer_collection = reinterpret_cast<LayerCollection *>(te->directdata);
return TRAVERSE_BREAK;
case TSE_R_LAYER:
case TSE_SCENE_COLLECTION_BASE:
@@ -460,9 +461,7 @@ static LayerCollection *outliner_active_layer_collection(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionObjectsSelectData data = {
- .layer_collection = NULL,
- };
+ CollectionObjectsSelectData data{};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -479,7 +478,7 @@ static int collection_objects_select_exec(bContext *C, wmOperator *op)
LayerCollection *layer_collection = outliner_active_layer_collection(C);
bool deselect = STREQ(op->idname, "OUTLINER_OT_collection_objects_deselect");
- if (layer_collection == NULL) {
+ if (layer_collection == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -536,7 +535,7 @@ struct CollectionDuplicateData {
static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te,
void *customdata)
{
- struct CollectionDuplicateData *data = customdata;
+ CollectionDuplicateData *data = reinterpret_cast<CollectionDuplicateData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
switch (tselem->type) {
@@ -555,9 +554,7 @@ static TreeElement *outliner_active_collection(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionDuplicateData data = {
- .te = NULL,
- };
+ CollectionDuplicateData data = {};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -572,38 +569,38 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
TreeElement *te = outliner_active_collection(C);
- const bool linked = strstr(op->idname, "linked") != NULL;
+ const bool linked = strstr(op->idname, "linked") != nullptr;
/* Can happen when calling from a key binding. */
- if (te == NULL) {
+ if (te == nullptr) {
BKE_report(op->reports, RPT_ERROR, "No active collection");
return OPERATOR_CANCELLED;
}
Collection *collection = outliner_collection_from_tree_element(te);
- Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : NULL;
+ Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : nullptr;
/* We are allowed to duplicated linked collections (they will become local IDs then),
* but we should not allow its parent to be a linked ID, ever.
* This can happen when a whole scene is linked e.g. */
- if (parent != NULL && (ID_IS_LINKED(parent) || ID_IS_OVERRIDE_LIBRARY(parent))) {
+ if (parent != nullptr && (ID_IS_LINKED(parent) || ID_IS_OVERRIDE_LIBRARY(parent))) {
Scene *scene = CTX_data_scene(C);
- parent = (ID_IS_LINKED(scene) || ID_IS_OVERRIDE_LIBRARY(scene)) ? NULL :
+ parent = (ID_IS_LINKED(scene) || ID_IS_OVERRIDE_LIBRARY(scene)) ? nullptr :
scene->master_collection;
}
- else if (parent != NULL && (parent->flag & COLLECTION_IS_MASTER) != 0) {
+ else if (parent != nullptr && (parent->flag & COLLECTION_IS_MASTER) != 0) {
BLI_assert(parent->id.flag & LIB_EMBEDDED_DATA);
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id);
- BLI_assert(id_type->owner_get != NULL);
+ BLI_assert(id_type->owner_get != nullptr);
Scene *scene_owner = (Scene *)id_type->owner_get(bmain, &parent->id);
- BLI_assert(scene_owner != NULL);
+ BLI_assert(scene_owner != nullptr);
BLI_assert(GS(scene_owner->id.name) == ID_SCE);
if (ID_IS_LINKED(scene_owner) || ID_IS_OVERRIDE_LIBRARY(scene_owner)) {
scene_owner = CTX_data_scene(C);
- parent = ID_IS_LINKED(scene_owner) ? NULL : scene_owner->master_collection;
+ parent = ID_IS_LINKED(scene_owner) ? nullptr : scene_owner->master_collection;
}
}
@@ -612,14 +609,15 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (parent == NULL) {
+ if (parent == nullptr) {
BKE_report(op->reports,
RPT_WARNING,
"Could not find a valid parent collection for the new duplicate, "
"it won't be linked to any view layer");
}
- const eDupli_ID_Flags dupli_flags = USER_DUP_OBJECT | (linked ? 0 : U.dupflag);
+ const eDupli_ID_Flags dupli_flags = (eDupli_ID_Flags)(USER_DUP_OBJECT |
+ (linked ? 0 : U.dupflag));
BKE_collection_duplicate(bmain, parent, collection, dupli_flags, LIB_ID_DUPLICATE_IS_ROOT_ID);
DEG_relations_tag_update(bmain);
@@ -674,10 +672,10 @@ static int collection_link_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Collection *active_collection = CTX_data_layer_collection(C)->collection;
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
if ((ID_IS_LINKED(active_collection) || ID_IS_OVERRIDE_LIBRARY(active_collection)) ||
((active_collection->flag & COLLECTION_IS_MASTER) &&
@@ -696,17 +694,18 @@ static int collection_link_exec(bContext *C, wmOperator *op)
/* Effectively link the collections. */
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_collection_child_add(bmain, active_collection, collection);
id_fake_user_clear(&collection->id);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
DEG_id_tag_update(&active_collection->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -738,10 +737,9 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
@@ -755,7 +753,8 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
while (BKE_collection_cycle_find(active_lc->collection, collection)) {
active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
@@ -764,20 +763,21 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
/* Effectively instance the collections. */
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
Object *ob = ED_object_add_type(
- C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, NULL, false, 0);
+ C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, nullptr, false, 0);
ob->instance_collection = collection;
ob->transflag |= OB_DUPLICOLLECTION;
id_lib_extern(&collection->id);
id_us_plus(&collection->id);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -805,14 +805,14 @@ void OUTLINER_OT_collection_instance(wmOperatorType *ot)
static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata)
{
- struct CollectionEditData *data = customdata;
+ CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) {
return TRAVERSE_CONTINUE;
}
- LayerCollection *lc = te->directdata;
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
if (lc->collection->flag & COLLECTION_IS_MASTER) {
/* skip - showing warning/error message might be misleading
@@ -836,10 +836,9 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
}
Scene *scene = CTX_data_scene(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
bool result = false;
@@ -852,7 +851,8 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (clear && (lc->flag & flag)) {
result = true;
@@ -862,7 +862,7 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag)
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
return result;
}
@@ -902,11 +902,10 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
- bool clear = strstr(op->idname, "clear") != NULL;
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
+ bool clear = strstr(op->idname, "clear") != nullptr;
int flag = strstr(op->idname, "holdout") ? LAYER_COLLECTION_HOLDOUT :
strstr(op->idname, "indirect_only") ? LAYER_COLLECTION_INDIRECT_ONLY :
LAYER_COLLECTION_EXCLUDE;
@@ -922,16 +921,17 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_flag(lc, flag, !clear);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_relations_tag_update(bmain);
- WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr);
return OPERATOR_FINISHED;
}
@@ -1040,10 +1040,9 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const bool extend = RNA_boolean_get(op->ptr, "extend");
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -1054,7 +1053,8 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (extend) {
BKE_layer_collection_isolate_global(scene, view_layer, layer_collection, true);
@@ -1069,16 +1069,16 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
* was called. */
const bool value = !RNA_property_boolean_get(&ptr, prop);
outliner_collection_isolate_flag(
- scene, view_layer, layer_collection, NULL, prop, "hide_viewport", value);
+ scene, view_layer, layer_collection, nullptr, prop, "hide_viewport", value);
break;
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1127,7 +1127,7 @@ static bool collection_inside_poll(bContext *C)
if (!ED_outliner_collections_editor_poll(C)) {
return false;
}
- return outliner_active_layer_collection(C) != NULL;
+ return outliner_active_layer_collection(C) != nullptr;
}
static int collection_visibility_exec(bContext *C, wmOperator *op)
@@ -1135,12 +1135,11 @@ static int collection_visibility_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- const bool is_inside = strstr(op->idname, "inside") != NULL;
- const bool show = strstr(op->idname, "show") != NULL;
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ const bool is_inside = strstr(op->idname, "inside") != nullptr;
+ const bool show = strstr(op->idname, "show") != nullptr;
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
outliner_tree_traverse(space_outliner,
@@ -1152,15 +1151,16 @@ static int collection_visibility_exec(bContext *C, wmOperator *op)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_visible(view_layer, layer_collection, show, is_inside);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1237,12 +1237,12 @@ static bool collection_flag_poll(bContext *C, bool clear, int flag)
}
TreeElement *te = outliner_active_collection(C);
- if (te == NULL) {
+ if (te == nullptr) {
return false;
}
Collection *collection = outliner_collection_from_tree_element(te);
- if (collection == NULL) {
+ if (collection == nullptr) {
return false;
}
@@ -1284,10 +1284,9 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
const bool is_render = strstr(op->idname, "render");
const bool clear = strstr(op->idname, "show") || strstr(op->idname, "enable");
int flag = is_render ? COLLECTION_HIDE_RENDER : COLLECTION_HIDE_VIEWPORT;
- struct CollectionEditData data = {
- .scene = scene,
- .space_outliner = space_outliner,
- };
+ CollectionEditData data{};
+ data.scene = scene;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new(__func__);
const bool has_layer_collection = space_outliner->outlinevis == SO_VIEW_LAYER;
@@ -1300,7 +1299,8 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
Collection *collection = layer_collection->collection;
if (ID_IS_LINKED(collection)) {
continue;
@@ -1317,7 +1317,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
layer_collection->flag &= ~LAYER_COLLECTION_HIDE;
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
}
else {
outliner_tree_traverse(space_outliner,
@@ -1328,7 +1328,8 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
&data);
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ Collection *collection = reinterpret_cast<Collection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
if (ID_IS_LINKED(collection)) {
continue;
}
@@ -1340,7 +1341,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
collection->flag |= flag;
}
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
}
BKE_layer_collection_sync(scene, view_layer);
@@ -1350,7 +1351,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(CTX_data_main(C));
}
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1430,15 +1431,15 @@ struct OutlinerHideEditData {
static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void *customdata)
{
- struct OutlinerHideEditData *data = customdata;
+ OutlinerHideEditData *data = reinterpret_cast<OutlinerHideEditData *>(customdata);
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem == NULL) {
+ if (tselem == nullptr) {
return TRAVERSE_CONTINUE;
}
if (tselem->type == TSE_LAYER_COLLECTION) {
- LayerCollection *lc = te->directdata;
+ LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata);
if (lc->collection->flag & COLLECTION_IS_MASTER) {
/* Skip - showing warning/error message might be misleading
@@ -1464,11 +1465,10 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- struct OutlinerHideEditData data = {
- .scene = scene,
- .view_layer = view_layer,
- .space_outliner = space_outliner,
- };
+ OutlinerHideEditData data{};
+ data.scene = scene;
+ data.view_layer = view_layer;
+ data.space_outliner = space_outliner;
data.collections_to_edit = BLI_gset_ptr_new("outliner_hide_exec__collections_to_edit");
data.bases_to_edit = BLI_gset_ptr_new("outliner_hide_exec__bases_to_edit");
@@ -1481,22 +1481,23 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op))
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
- LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ BLI_gsetIterator_getKey(&collections_to_edit_iter));
BKE_layer_collection_set_visible(view_layer, layer_collection, false, false);
}
- BLI_gset_free(data.collections_to_edit, NULL);
+ BLI_gset_free(data.collections_to_edit, nullptr);
GSetIterator bases_to_edit_iter;
GSET_ITER (bases_to_edit_iter, data.bases_to_edit) {
- Base *base = BLI_gsetIterator_getKey(&bases_to_edit_iter);
+ Base *base = reinterpret_cast<Base *>(BLI_gsetIterator_getKey(&bases_to_edit_iter));
base->flag |= BASE_HIDDEN;
}
- BLI_gset_free(data.bases_to_edit, NULL);
+ BLI_gset_free(data.bases_to_edit, nullptr);
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1521,7 +1522,8 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op))
ViewLayer *view_layer = CTX_data_view_layer(C);
/* Unhide all the collections. */
- LayerCollection *lc_master = view_layer->layer_collections.first;
+ LayerCollection *lc_master = reinterpret_cast<LayerCollection *>(
+ view_layer->layer_collections.first);
LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
BKE_layer_collection_set_flag(lc_iter, LAYER_COLLECTION_HIDE, false);
}
@@ -1534,7 +1536,7 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op))
BKE_layer_collection_sync(scene, view_layer);
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -1565,9 +1567,7 @@ static int outliner_color_tag_set_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const short color_tag = RNA_enum_get(op->ptr, "color");
- struct IDsSelectedData selected = {
- .selected_array = {NULL, NULL},
- };
+ IDsSelectedData selected{};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
@@ -1593,7 +1593,7 @@ static int outliner_color_tag_set_exec(bContext *C, wmOperator *op)
BLI_freelistN(&selected.selected_array);
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, nullptr);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.cc
index d61bb17f661..d3b99928ec1 100644
--- a/source/blender/editors/space_outliner/outliner_context.c
+++ b/source/blender/editors/space_outliner/outliner_context.cc
@@ -27,7 +27,7 @@
#include "DNA_space_types.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
static void outliner_context_selected_ids_recursive(const ListBase *subtree,
bContextDataResult *result)
@@ -48,7 +48,7 @@ static void outliner_context_selected_ids(const SpaceOutliner *space_outliner,
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
}
-static const char *outliner_context_dir[] = {"selected_ids", NULL};
+static const char *outliner_context_dir[] = {"selected_ids", nullptr};
int /*eContextResult*/ outliner_context(const bContext *C,
const char *member,
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.cc
index a4d5f2635d4..3745894d630 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -58,7 +58,7 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
static Collection *collection_parent_from_ID(ID *id);
@@ -83,7 +83,7 @@ static TreeElement *outliner_dropzone_element(TreeElement *te,
}
}
}
- return NULL;
+ return nullptr;
}
/* Find tree element to drop into. */
@@ -97,7 +97,7 @@ static TreeElement *outliner_dropzone_find(const SpaceOutliner *space_outliner,
return te_valid;
}
}
- return NULL;
+ return nullptr;
}
static TreeElement *outliner_drop_find(bContext *C, const wmEvent *event)
@@ -113,17 +113,17 @@ static TreeElement *outliner_drop_find(bContext *C, const wmEvent *event)
static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode)
{
TreeElement *te = outliner_drop_find(C, event);
- TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL;
+ TreeStoreElem *tselem = (te) ? TREESTORE(te) : nullptr;
if (te && (te->idcode == idcode) && (tselem->type == TSE_SOME_ID)) {
return tselem->id;
}
- return NULL;
+ return nullptr;
}
/* Find tree element to drop into, with additional before and after reorder support. */
static TreeElement *outliner_drop_insert_find(bContext *C,
- const wmEvent *event,
+ const int xy[2],
TreeElementInsertType *r_insert_type)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
@@ -133,11 +133,14 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
/* Empty tree, e.g. while filtered. */
if (BLI_listbase_is_empty(&space_outliner->tree)) {
- return NULL;
+ return nullptr;
}
- UI_view2d_region_to_view(
- &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+ int mval[2];
+ mval[0] = xy[0] - region->winrct.xmin;
+ mval[1] = xy[1] - region->winrct.ymin;
+
+ UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
te_hovered = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
if (te_hovered) {
@@ -154,7 +157,7 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
return te_hovered;
}
*r_insert_type = TE_INSERT_BEFORE;
- return te_hovered->subtree.first;
+ return reinterpret_cast<TreeElement *>(te_hovered->subtree.first);
}
*r_insert_type = TE_INSERT_AFTER;
return te_hovered;
@@ -169,8 +172,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
/* Mouse doesn't hover any item (ignoring x-axis),
* so it's either above list bounds or below. */
- TreeElement *first = space_outliner->tree.first;
- TreeElement *last = space_outliner->tree.last;
+ TreeElement *first = reinterpret_cast<TreeElement *>(space_outliner->tree.first);
+ TreeElement *last = reinterpret_cast<TreeElement *>(space_outliner->tree.last);
if (view_mval[1] < last->ys) {
*r_insert_type = TE_INSERT_AFTER;
@@ -181,21 +184,21 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
return first;
}
BLI_assert(0);
- return NULL;
+ return nullptr;
}
-typedef bool (*CheckTypeFn)(TreeElement *te);
+using CheckTypeFn = bool (*)(TreeElement *te);
static TreeElement *outliner_data_from_tree_element_and_parents(CheckTypeFn check_type,
TreeElement *te)
{
- while (te != NULL) {
+ while (te != nullptr) {
if (check_type(te)) {
return te;
}
te = te->parent;
}
- return NULL;
+ return nullptr;
}
static bool is_collection_element(TreeElement *te)
@@ -216,18 +219,18 @@ static bool is_pchan_element(TreeElement *te)
}
static TreeElement *outliner_drop_insert_collection_find(bContext *C,
- const wmEvent *event,
+ const int xy[2],
TreeElementInsertType *r_insert_type)
{
- TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type);
+ TreeElement *te = outliner_drop_insert_find(C, xy, r_insert_type);
if (!te) {
- return NULL;
+ return nullptr;
}
TreeElement *collection_te = outliner_data_from_tree_element_and_parents(is_collection_element,
te);
if (!collection_te) {
- return NULL;
+ return nullptr;
}
Collection *collection = outliner_collection_from_tree_element(collection_te);
@@ -260,7 +263,7 @@ static int outliner_get_insert_index(TreeElement *drag_te,
}
}
- if (drop_te == NULL) {
+ if (drop_te == nullptr) {
return 0;
}
@@ -364,7 +367,7 @@ static void parent_drop_set_parents(bContext *C,
TreeElement *te = outliner_find_id(space_outliner, &space_outliner->tree, &parent->id);
Scene *scene = (Scene *)outliner_search_back(te, ID_SCE);
- if (scene == NULL) {
+ if (scene == nullptr) {
/* currently outliner organized in a way, that if there's no parent scene
* element for object it means that all displayed objects belong to
* active scene and parenting them is allowed (sergey)
@@ -387,7 +390,7 @@ static void parent_drop_set_parents(bContext *C,
}
if (ED_object_parent_set(
- reports, C, scene, object, parent, parent_type, false, keep_transform, NULL)) {
+ reports, C, scene, object, parent, parent_type, false, keep_transform, nullptr)) {
parent_set = true;
}
}
@@ -399,15 +402,15 @@ static void parent_drop_set_parents(bContext *C,
if (parent_set) {
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, nullptr);
}
}
static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
TreeElement *te = outliner_drop_find(C, event);
- TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
+ TreeStoreElem *tselem = te ? TREESTORE(te) : nullptr;
if (!(te && (te->idcode == ID_OB) && (tselem->type == TSE_SOME_ID))) {
return OPERATOR_CANCELLED;
@@ -416,7 +419,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Object *par = (Object *)tselem->id;
Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB);
- if (ELEM(NULL, ob, par)) {
+ if (ELEM(nullptr, ob, par)) {
return OPERATOR_CANCELLED;
}
if (ob == par) {
@@ -427,10 +430,11 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
- parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT, event->alt);
+ parent_drop_set_parents(
+ C, op->reports, reinterpret_cast<wmDragID *>(drag->ids.first), par, PAR_OBJECT, event->alt);
return OPERATOR_FINISHED;
}
@@ -501,8 +505,8 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
if (GS(drag_id->id->name) == ID_OB) {
@@ -513,8 +517,8 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
}
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, nullptr);
return OPERATOR_FINISHED;
}
@@ -540,7 +544,7 @@ static bool scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
/* Ensure item under cursor is valid drop target */
Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB);
- return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL));
+ return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != nullptr));
}
static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -549,7 +553,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
Scene *scene = (Scene *)outliner_ID_drop_find(C, event, ID_SCE);
Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB);
- if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) {
+ if (ELEM(nullptr, ob, scene) || ID_IS_LINKED(scene)) {
return OPERATOR_CANCELLED;
}
@@ -605,7 +609,7 @@ static bool material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
/* Ensure item under cursor is valid drop target */
Material *ma = (Material *)WM_drag_get_local_ID(drag, ID_MA);
- return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL));
+ return (ma && (outliner_ID_drop_find(C, event, ID_OB) != nullptr));
}
static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -614,19 +618,19 @@ static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB);
Material *ma = (Material *)WM_drag_get_local_ID_from_event(event, ID_MA);
- if (ELEM(NULL, ob, ma)) {
+ if (ELEM(nullptr, ob, ma)) {
return OPERATOR_CANCELLED;
}
/* only drop grease pencil material on grease pencil objects */
- if ((ma->gp_style != NULL) && (ob->type != OB_GPENCIL)) {
+ if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL)) {
return OPERATOR_CANCELLED;
}
BKE_object_material_assign(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
return OPERATOR_FINISHED;
@@ -658,13 +662,13 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot)
* - Copying a single modifier/constraint/effect to another object.
* - Copying (linking) an object's modifiers/constraints/effects to another. */
-typedef enum eDataStackDropAction {
+enum eDataStackDropAction {
DATA_STACK_DROP_REORDER,
DATA_STACK_DROP_COPY,
DATA_STACK_DROP_LINK,
-} eDataStackDropAction;
+};
-typedef struct StackDropData {
+struct StackDropData {
Object *ob_parent;
bPoseChannel *pchan_parent;
TreeStoreElem *drag_tselem;
@@ -674,7 +678,7 @@ typedef struct StackDropData {
eDataStackDropAction drop_action;
TreeElement *drop_te;
TreeElementInsertType insert_type;
-} StackDropData;
+};
static void datastack_drop_data_init(wmDrag *drag,
Object *ob,
@@ -683,7 +687,7 @@ static void datastack_drop_data_init(wmDrag *drag,
TreeStoreElem *tselem,
void *directdata)
{
- StackDropData *drop_data = MEM_callocN(sizeof(*drop_data), "datastack drop data");
+ StackDropData *drop_data = MEM_cnew<StackDropData>("datastack drop data");
drop_data->ob_parent = ob;
drop_data->pchan_parent = pchan;
@@ -707,7 +711,7 @@ static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData
return false;
}
- TreeElement *te_target = outliner_drop_insert_find(C, event, &drop_data->insert_type);
+ TreeElement *te_target = outliner_drop_insert_find(C, event->xy, &drop_data->insert_type);
if (!te_target) {
return false;
}
@@ -717,20 +721,20 @@ static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData
return false;
}
- Object *ob = NULL;
+ Object *ob = nullptr;
TreeElement *object_te = outliner_data_from_tree_element_and_parents(is_object_element,
te_target);
if (object_te) {
ob = (Object *)TREESTORE(object_te)->id;
}
- bPoseChannel *pchan = NULL;
+ bPoseChannel *pchan = nullptr;
TreeElement *pchan_te = outliner_data_from_tree_element_and_parents(is_pchan_element, te_target);
if (pchan_te) {
pchan = (bPoseChannel *)pchan_te->directdata;
}
if (pchan) {
- ob = NULL;
+ ob = nullptr;
}
if (ob && ID_IS_LINKED(&ob->id)) {
@@ -833,7 +837,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
bool changed = outliner_flag_set(
&space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
- StackDropData *drop_data = drag->poin;
+ StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
if (!drop_data) {
return false;
}
@@ -871,7 +875,7 @@ static char *datastack_drop_tooltip(bContext *UNUSED(C),
const int UNUSED(xy[2]),
struct wmDropBox *UNUSED(drop))
{
- StackDropData *drop_data = drag->poin;
+ StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
switch (drop_data->drop_action) {
case DATA_STACK_DROP_REORDER:
return BLI_strdup(TIP_("Reorder"));
@@ -893,7 +897,7 @@ static char *datastack_drop_tooltip(bContext *UNUSED(C),
}
break;
}
- return NULL;
+ return nullptr;
}
static void datastack_drop_link(bContext *C, StackDropData *drop_data)
@@ -948,20 +952,28 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data)
switch (drop_data->drag_tselem->type) {
case TSE_MODIFIER:
if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) {
- ED_object_gpencil_modifier_copy_to_object(ob_dst, drop_data->drag_directdata);
+ ED_object_gpencil_modifier_copy_to_object(
+ ob_dst, reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata));
}
else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) {
ED_object_modifier_copy_to_object(
- C, ob_dst, drop_data->ob_parent, drop_data->drag_directdata);
+ C,
+ ob_dst,
+ drop_data->ob_parent,
+ reinterpret_cast<ModifierData *>(drop_data->drag_directdata));
}
break;
case TSE_CONSTRAINT:
if (tselem->type == TSE_POSE_CHANNEL) {
ED_object_constraint_copy_for_pose(
- bmain, ob_dst, drop_data->drop_te->directdata, drop_data->drag_directdata);
+ bmain,
+ ob_dst,
+ reinterpret_cast<bPoseChannel *>(drop_data->drop_te->directdata),
+ reinterpret_cast<bConstraint *>(drop_data->drag_directdata));
}
else {
- ED_object_constraint_copy_for_object(bmain, ob_dst, drop_data->drag_directdata);
+ ED_object_constraint_copy_for_object(
+ bmain, ob_dst, reinterpret_cast<bConstraint *>(drop_data->drag_directdata));
}
break;
case TSE_GPENCIL_EFFECT: {
@@ -969,7 +981,8 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data)
return;
}
- ED_object_shaderfx_copy(ob_dst, drop_data->drag_directdata);
+ ED_object_shaderfx_copy(ob_dst,
+ reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata));
break;
}
}
@@ -995,11 +1008,16 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa
if (ob->type == OB_GPENCIL) {
index = outliner_get_insert_index(
drag_te, drop_te, insert_type, &ob->greasepencil_modifiers);
- ED_object_gpencil_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
+ ED_object_gpencil_modifier_move_to_index(
+ reports,
+ ob,
+ reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata),
+ index);
}
else {
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers);
- ED_object_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
+ ED_object_modifier_move_to_index(
+ reports, ob, reinterpret_cast<ModifierData *>(drop_data->drag_directdata), index);
}
break;
case TSE_CONSTRAINT:
@@ -1010,12 +1028,14 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa
else {
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->constraints);
}
- ED_object_constraint_move_to_index(ob, drop_data->drag_directdata, index);
+ ED_object_constraint_move_to_index(
+ ob, reinterpret_cast<bConstraint *>(drop_data->drag_directdata), index);
break;
case TSE_GPENCIL_EFFECT:
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->shader_fx);
- ED_object_shaderfx_move_to_index(reports, ob, drop_data->drag_directdata, index);
+ ED_object_shaderfx_move_to_index(
+ reports, ob, reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata), index);
}
}
@@ -1025,9 +1045,9 @@ static int datastack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *eve
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
- StackDropData *drop_data = drag->poin;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
+ StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin);
switch (drop_data->drop_action) {
case DATA_STACK_DROP_LINK:
@@ -1062,19 +1082,19 @@ void OUTLINER_OT_datastack_drop(wmOperatorType *ot)
/* ******************** Collection Drop Operator *********************** */
-typedef struct CollectionDrop {
+struct CollectionDrop {
Collection *from;
Collection *to;
TreeElement *te;
TreeElementInsertType insert_type;
-} CollectionDrop;
+};
static Collection *collection_parent_from_ID(ID *id)
{
/* Can't change linked parent collections. */
if (!id || ID_IS_LINKED(id)) {
- return NULL;
+ return nullptr;
}
/* Also support dropping into/from scene collection. */
@@ -1085,17 +1105,15 @@ static Collection *collection_parent_from_ID(ID *id)
return (Collection *)id;
}
- return NULL;
+ return nullptr;
}
-static bool collection_drop_init(bContext *C,
- wmDrag *drag,
- const wmEvent *event,
- CollectionDrop *data)
+static bool collection_drop_init(
+ bContext *C, wmDrag *drag, const int xy[2], const bool is_link, CollectionDrop *data)
{
/* Get collection to drop into. */
TreeElementInsertType insert_type;
- TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type);
+ TreeElement *te = outliner_drop_insert_collection_find(C, xy, &insert_type);
if (!te) {
return false;
}
@@ -1110,8 +1128,8 @@ static bool collection_drop_init(bContext *C,
return false;
}
- wmDragID *drag_id = drag->ids.first;
- if (drag_id == NULL) {
+ wmDragID *drag_id = reinterpret_cast<wmDragID *>(drag->ids.first);
+ if (drag_id == nullptr) {
return false;
}
@@ -1123,12 +1141,12 @@ static bool collection_drop_init(bContext *C,
/* Get collection to drag out of. */
ID *parent = drag_id->from_parent;
Collection *from_collection = collection_parent_from_ID(parent);
- if (event->ctrl) {
- from_collection = NULL;
+ if (is_link) {
+ from_collection = nullptr;
}
/* Currently this should not be allowed, cannot edit items in an override of a Collection. */
- if (from_collection != NULL && ID_IS_OVERRIDE_LIBRARY(from_collection)) {
+ if (from_collection != nullptr && ID_IS_OVERRIDE_LIBRARY(from_collection)) {
return false;
}
@@ -1164,7 +1182,7 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
&space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
CollectionDrop data;
- if (!event->shift && collection_drop_init(C, drag, event, &data)) {
+ if (!event->shift && collection_drop_init(C, drag, event->xy, event->ctrl, &data)) {
TreeElement *te = data.te;
TreeStoreElem *tselem = TREESTORE(te);
if (!data.from || event->ctrl) {
@@ -1201,13 +1219,14 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
static char *collection_drop_tooltip(bContext *C,
wmDrag *drag,
- const int UNUSED(xy[2]),
+ const int xy[2],
wmDropBox *UNUSED(drop))
{
- wmWindowManager *wm = CTX_wm_manager(C);
- const wmEvent *event = wm->winactive ? wm->winactive->eventstate : NULL;
+ wmWindow *win = CTX_wm_window(C);
+ const wmEvent *event = win ? win->eventstate : nullptr;
+
CollectionDrop data;
- if (event && !event->shift && collection_drop_init(C, drag, event, &data)) {
+ if (event && !event->shift && collection_drop_init(C, drag, xy, event->ctrl, &data)) {
TreeElement *te = data.te;
if (!data.from || event->ctrl) {
return BLI_strdup(TIP_("Link inside Collection"));
@@ -1244,7 +1263,7 @@ static char *collection_drop_tooltip(bContext *C,
}
}
}
- return NULL;
+ return nullptr;
}
static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
@@ -1256,16 +1275,16 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
return OPERATOR_CANCELLED;
}
- ListBase *lb = event->customdata;
- wmDrag *drag = lb->first;
+ ListBase *lb = reinterpret_cast<ListBase *>(event->customdata);
+ wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
CollectionDrop data;
- if (!collection_drop_init(C, drag, event, &data)) {
+ if (!collection_drop_init(C, drag, event->xy, event->ctrl, &data)) {
return OPERATOR_CANCELLED;
}
/* Before/after insert handling. */
- Collection *relative = NULL;
+ Collection *relative = nullptr;
bool relative_after = false;
if (ELEM(data.insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) {
@@ -1274,8 +1293,8 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
relative = data.to;
relative_after = (data.insert_type == TE_INSERT_AFTER);
- TreeElement *parent_te = outliner_find_parent_element(&space_outliner->tree, NULL, data.te);
- data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : NULL;
+ TreeElement *parent_te = outliner_find_parent_element(&space_outliner->tree, nullptr, data.te);
+ data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : nullptr;
}
if (!data.to) {
@@ -1288,7 +1307,7 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
/* Ctrl enables linking, so we don't need a from collection then. */
- Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent);
+ Collection *from = (event->ctrl) ? nullptr : collection_parent_from_ID(drag_id->from_parent);
if (GS(drag_id->id->name) == ID_OB) {
/* Move/link object into collection. */
@@ -1400,10 +1419,10 @@ static int outliner_item_drag_drop_invoke(bContext *C,
TSE_GPENCIL_EFFECT_BASE);
const int wm_drag_type = use_datastack_drag ? WM_DRAG_DATASTACK : WM_DRAG_ID;
- wmDrag *drag = WM_event_start_drag(C, data.icon, wm_drag_type, NULL, 0.0, WM_DRAG_NOP);
+ wmDrag *drag = WM_event_start_drag(C, data.icon, wm_drag_type, nullptr, 0.0, WM_DRAG_NOP);
if (use_datastack_drag) {
- TreeElement *te_bone = NULL;
+ TreeElement *te_bone = nullptr;
bPoseChannel *pchan = outliner_find_parent_bone(te, &te_bone);
datastack_drop_data_init(drag, (Object *)tselem->id, pchan, te, tselem, te->directdata);
}
@@ -1417,9 +1436,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
}
/* Gather all selected elements. */
- struct IDsSelectedData selected = {
- .selected_array = {NULL, NULL},
- };
+ IDsSelectedData selected{};
if (GS(data.drag_id->name) == ID_OB) {
outliner_tree_traverse(space_outliner,
@@ -1466,7 +1483,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
}
/* Find parent collection. */
- Collection *parent = NULL;
+ Collection *parent = nullptr;
if (te_selected->parent) {
for (TreeElement *te_parent = te_selected->parent; te_parent;
@@ -1519,16 +1536,20 @@ void outliner_dropboxes(void)
{
ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW);
- WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, NULL, NULL, NULL);
- WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, NULL, NULL, NULL);
- WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, NULL, NULL, NULL);
- WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, NULL, NULL, NULL);
- WM_dropbox_add(
- lb, "OUTLINER_OT_datastack_drop", datastack_drop_poll, NULL, NULL, datastack_drop_tooltip);
+ WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, nullptr, nullptr, nullptr);
+ WM_dropbox_add(lb,
+ "OUTLINER_OT_datastack_drop",
+ datastack_drop_poll,
+ nullptr,
+ nullptr,
+ datastack_drop_tooltip);
WM_dropbox_add(lb,
"OUTLINER_OT_collection_drop",
collection_drop_poll,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
collection_drop_tooltip);
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.cc
index a586f268128..5fd7559370f 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -78,7 +78,12 @@
#include "RNA_access.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
+#include "tree/tree_display.hh"
+#include "tree/tree_element.hh"
+#include "tree/tree_element_rna.hh"
+
+using namespace blender::ed::outliner;
/* Disable - this is far too slow - campbell. */
/* #define USE_GROUP_SELECT */
@@ -93,7 +98,7 @@ static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner,
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
*width = MAX2(*width, te->xend);
- if (height != NULL) {
+ if (height != nullptr) {
*height += UI_UNIT_Y;
}
@@ -102,7 +107,7 @@ static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner,
outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, height);
}
else {
- outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, NULL);
+ outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, nullptr);
}
}
}
@@ -119,7 +124,7 @@ void outliner_tree_dimensions(SpaceOutliner *space_outliner, int *r_width, int *
*/
static bool is_object_data_in_editmode(const ID *id, const Object *obact)
{
- if (id == NULL) {
+ if (id == nullptr) {
return false;
}
@@ -141,9 +146,7 @@ static void restrictbutton_recursive_ebone(bArmature *arm,
int flag,
bool set_flag)
{
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
if (set_flag) {
ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
@@ -158,8 +161,7 @@ static void restrictbutton_recursive_ebone(bArmature *arm,
static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_flag)
{
- Bone *bone;
- for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) {
if (set_flag) {
bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
bone->flag |= flag;
@@ -196,7 +198,7 @@ static void restrictbutton_bone_select_fn(bContext *C, void *UNUSED(poin), void
restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
}
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2)
@@ -213,7 +215,7 @@ static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2)
arm, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
}
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *poin2)
@@ -228,7 +230,7 @@ static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *po
restrictbutton_recursive_ebone(arm, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0);
}
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
static void restrictbutton_gp_layer_flag_fn(bContext *C, void *poin, void *UNUSED(poin2))
@@ -236,14 +238,14 @@ static void restrictbutton_gp_layer_flag_fn(bContext *C, void *poin, void *UNUSE
ID *id = (ID *)poin;
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, nullptr);
}
static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2))
{
ID *id = (ID *)poin;
- BLI_assert(id != NULL);
+ BLI_assert(id != nullptr);
if (id->flag & LIB_FAKEUSER) {
id_us_plus(id);
@@ -281,7 +283,8 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
Object *ob_parent = ob ? ob : base->object;
- for (Object *ob_iter = bmain->objects.first; ob_iter; ob_iter = ob_iter->id.next) {
+ for (Object *ob_iter = reinterpret_cast<Object *>(bmain->objects.first); ob_iter;
+ ob_iter = reinterpret_cast<Object *>(ob_iter->id.next)) {
if (BKE_object_is_child_recursive(ob_parent, ob_iter)) {
if (ob) {
RNA_id_pointer_create(&ob_iter->id, &ptr);
@@ -290,7 +293,7 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
else {
Base *base_iter = BKE_view_layer_base_find(view_layer, ob_iter);
/* Child can be in a collection excluded from viewlayer. */
- if (base_iter == NULL) {
+ if (base_iter == nullptr) {
continue;
}
RNA_pointer_create(&scene->id, &RNA_ObjectBase, base_iter, &ptr);
@@ -315,9 +318,9 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
*/
static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Object *ob = poin;
- char *propname = poin2;
- outliner_object_set_flag_recursive_fn(C, NULL, ob, propname);
+ Object *ob = reinterpret_cast<Object *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_object_set_flag_recursive_fn(C, nullptr, ob, propname);
}
/**
@@ -325,9 +328,9 @@ static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void
*/
static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Base *base = poin;
- char *propname = poin2;
- outliner_object_set_flag_recursive_fn(C, base, NULL, propname);
+ Base *base = reinterpret_cast<Base *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_object_set_flag_recursive_fn(C, base, nullptr, propname);
}
/** Create either a RNA_LayerCollection or a RNA_Collection pointer. */
@@ -392,9 +395,9 @@ static void outliner_collection_set_flag_recursive(Scene *scene,
/* Keep going recursively. */
ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
LISTBASE_FOREACH (Link *, link, lb) {
- LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL;
+ LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
Collection *collection_iter = layer_collection ?
- (collection ? layer_collection_iter->collection : NULL) :
+ (collection ? layer_collection_iter->collection : nullptr) :
((CollectionChild *)link)->collection;
outliner_collection_set_flag_recursive(scene,
view_layer,
@@ -458,9 +461,9 @@ static bool outliner_collection_is_isolated(Scene *scene,
/* Keep going recursively. */
ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
LISTBASE_FOREACH (Link *, link, lb) {
- LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL;
+ LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr;
Collection *collection_iter = layer_collection ?
- (collection ? layer_collection_iter->collection : NULL) :
+ (collection ? layer_collection_iter->collection : nullptr) :
((CollectionChild *)link)->collection;
if (layer_collection_iter && layer_collection_iter->flag & LAYER_COLLECTION_EXCLUDE) {
continue;
@@ -488,11 +491,13 @@ void outliner_collection_isolate_flag(Scene *scene,
const bool value)
{
PointerRNA ptr;
- const bool is_hide = strstr(propname, "hide_") != NULL;
+ const bool is_hide = strstr(propname, "hide_") != nullptr;
- LayerCollection *top_layer_collection = layer_collection ? view_layer->layer_collections.first :
- NULL;
- Collection *top_collection = collection ? scene->master_collection : NULL;
+ LayerCollection *top_layer_collection = layer_collection ?
+ reinterpret_cast<LayerCollection *>(
+ view_layer->layer_collections.first) :
+ nullptr;
+ Collection *top_collection = collection ? scene->master_collection : nullptr;
bool was_isolated = (value == is_hide);
was_isolated &= outliner_collection_is_isolated(scene,
@@ -504,14 +509,14 @@ void outliner_collection_isolate_flag(Scene *scene,
top_collection);
if (was_isolated) {
- const bool default_value = RNA_property_boolean_get_default(NULL, layer_or_collection_prop);
+ const bool default_value = RNA_property_boolean_get_default(nullptr, layer_or_collection_prop);
/* Make every collection go back to its default "visibility" state. */
outliner_collection_set_flag_recursive(scene,
view_layer,
top_layer_collection,
top_collection,
layer_or_collection_prop,
- NULL,
+ nullptr,
default_value);
return;
}
@@ -522,12 +527,17 @@ void outliner_collection_isolate_flag(Scene *scene,
top_layer_collection,
top_collection,
layer_or_collection_prop,
- NULL,
+ nullptr,
is_hide);
/* Make this collection and its children collections the only "visible". */
- outliner_collection_set_flag_recursive(
- scene, view_layer, layer_collection, collection, layer_or_collection_prop, NULL, !is_hide);
+ outliner_collection_set_flag_recursive(scene,
+ view_layer,
+ layer_collection,
+ collection,
+ layer_or_collection_prop,
+ nullptr,
+ !is_hide);
/* Make this collection direct parents also "visible". */
if (layer_collection) {
@@ -541,7 +551,7 @@ void outliner_collection_isolate_flag(Scene *scene,
while (lc_parent != layer_collection) {
outliner_layer_or_collection_pointer_create(
- scene, lc_parent, collection ? lc_parent->collection : NULL, &ptr);
+ scene, lc_parent, collection ? lc_parent->collection : nullptr, &ptr);
RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide);
LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
@@ -555,7 +565,7 @@ void outliner_collection_isolate_flag(Scene *scene,
else {
CollectionParent *parent;
Collection *child = collection;
- while ((parent = child->parents.first)) {
+ while ((parent = reinterpret_cast<CollectionParent *>(child->parents.first))) {
if (parent->collection->flag & COLLECTION_IS_MASTER) {
break;
}
@@ -594,8 +604,8 @@ static void outliner_collection_set_flag_recursive_fn(bContext *C,
PropertyRNA *layer_or_collection_prop = RNA_struct_type_find_property(struct_rna, propname);
const bool value = RNA_property_boolean_get(&ptr, layer_or_collection_prop);
- PropertyRNA *base_or_object_prop = NULL;
- if (layer_collection != NULL) {
+ PropertyRNA *base_or_object_prop = nullptr;
+ if (layer_collection != nullptr) {
/* If we are toggling Layer collections we still want to change the properties of the base
* or the objects. If we have a matching property, toggle it as well, it can be NULL. */
struct_rna = collection ? &RNA_Object : &RNA_ObjectBase;
@@ -634,9 +644,9 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C,
void *poin,
void *poin2)
{
- LayerCollection *layer_collection = poin;
- char *propname = poin2;
- outliner_collection_set_flag_recursive_fn(C, layer_collection, NULL, propname);
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_collection_set_flag_recursive_fn(C, layer_collection, nullptr, propname);
}
/**
@@ -645,8 +655,8 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C,
*/
static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- LayerCollection *layer_collection = poin;
- char *propname = poin2;
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
outliner_collection_set_flag_recursive_fn(
C, layer_collection, layer_collection->collection, propname);
}
@@ -657,18 +667,20 @@ static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin
*/
static void scenes__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2)
{
- Collection *collection = poin;
- char *propname = poin2;
- outliner_collection_set_flag_recursive_fn(C, NULL, collection, propname);
+ Collection *collection = reinterpret_cast<Collection *>(poin);
+ char *propname = reinterpret_cast<char *>(poin2);
+ outliner_collection_set_flag_recursive_fn(C, nullptr, collection, propname);
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static void namebutton_fn(bContext *C, void *tsep, char *oldname)
{
Main *bmain = CTX_data_main(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
BLI_mempool *ts = space_outliner->treestore;
- TreeStoreElem *tselem = tsep;
+ TreeStoreElem *tselem = reinterpret_cast<TreeStoreElem *>(tsep);
if (ts && tselem) {
TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
@@ -680,16 +692,16 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
switch (GS(tselem->id->name)) {
case ID_MA:
- WM_event_add_notifier(C, NC_MATERIAL, NULL);
+ WM_event_add_notifier(C, NC_MATERIAL, nullptr);
break;
case ID_TE:
- WM_event_add_notifier(C, NC_TEXTURE, NULL);
+ WM_event_add_notifier(C, NC_TEXTURE, nullptr);
break;
case ID_IM:
- WM_event_add_notifier(C, NC_IMAGE, NULL);
+ WM_event_add_notifier(C, NC_IMAGE, nullptr);
break;
case ID_SCE:
- WM_event_add_notifier(C, NC_SCENE, NULL);
+ WM_event_add_notifier(C, NC_SCENE, nullptr);
break;
case ID_OB: {
Object *ob = (Object *)tselem->id;
@@ -702,7 +714,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
default:
break;
}
- WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
/* Check the library target exists */
if (te->idcode == ID_LI) {
@@ -732,7 +744,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
switch (tselem->type) {
case TSE_DEFGROUP: {
Object *ob = (Object *)tselem->id;
- bDeformGroup *vg = te->directdata;
+ bDeformGroup *vg = reinterpret_cast<bDeformGroup *>(te->directdata);
BKE_object_defgroup_unique_name(vg, ob);
WM_msg_publish_rna_prop(mbus, &ob->id, vg, VertexGroup, name);
break;
@@ -746,7 +758,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
case TSE_EBONE: {
bArmature *arm = (bArmature *)tselem->id;
if (arm->edbo) {
- EditBone *ebone = te->directdata;
+ EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
char newname[sizeof(ebone->name)];
/* restore bone name */
@@ -754,7 +766,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
BLI_strncpy(ebone->name, oldname, sizeof(ebone->name));
ED_armature_bone_rename(bmain, arm, oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, ebone, EditBone, name);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
}
break;
}
@@ -764,7 +776,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
outliner_viewcontext_init(C, &tvc);
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = te->directdata;
+ Bone *bone = reinterpret_cast<Bone *>(te->directdata);
char newname[sizeof(bone->name)];
/* always make current object active */
@@ -775,7 +787,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
BLI_strncpy(bone->name, oldname, sizeof(bone->name));
ED_armature_bone_rename(bmain, arm, oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, bone, Bone, name);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
break;
}
case TSE_POSE_CHANNEL: {
@@ -784,7 +796,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
Object *ob = (Object *)tselem->id;
bArmature *arm = (bArmature *)ob->data;
- bPoseChannel *pchan = te->directdata;
+ bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
char newname[sizeof(pchan->name)];
/* always make current pose-bone active */
@@ -795,14 +807,15 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
/* restore bone name */
BLI_strncpy(newname, pchan->name, sizeof(pchan->name));
BLI_strncpy(pchan->name, oldname, sizeof(pchan->name));
- ED_armature_bone_rename(bmain, ob->data, oldname, newname);
+ ED_armature_bone_rename(
+ bmain, reinterpret_cast<bArmature *>(ob->data), oldname, newname);
WM_msg_publish_rna_prop(mbus, &arm->id, pchan->bone, Bone, name);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
break;
}
case TSE_POSEGRP: {
Object *ob = (Object *)tselem->id; /* id = object. */
- bActionGroup *grp = te->directdata;
+ bActionGroup *grp = reinterpret_cast<bActionGroup *>(te->directdata);
BLI_uniquename(&ob->pose->agroups,
grp,
@@ -816,7 +829,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
}
case TSE_GP_LAYER: {
bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */
- bGPDlayer *gpl = te->directdata;
+ bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata);
/* always make layer active */
BKE_gpencil_layer_active_set(gpd, gpl);
@@ -832,7 +845,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
}
case TSE_R_LAYER: {
Scene *scene = (Scene *)tselem->id;
- ViewLayer *view_layer = te->directdata;
+ ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
/* Restore old name. */
char newname[sizeof(view_layer->name)];
@@ -842,7 +855,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
/* Rename, preserving animation and compositing data. */
BKE_view_layer_rename(bmain, scene, view_layer, newname);
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, ViewLayer, name);
- WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
break;
}
case TSE_LAYER_COLLECTION: {
@@ -850,7 +863,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
Collection *collection = (Collection *)tselem->id;
BLI_libblock_ensure_unique_name(bmain, collection->id.name);
WM_msg_publish_rna_prop(mbus, &collection->id, &collection->id, ID, name);
- WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr);
break;
}
}
@@ -858,8 +871,9 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
tselem->flag &= ~TSE_TEXTBUT;
}
}
+}
-typedef struct RestrictProperties {
+struct RestrictProperties {
bool initialized;
PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render;
@@ -870,11 +884,11 @@ typedef struct RestrictProperties {
PropertyRNA *modifier_show_viewport, *modifier_show_render;
PropertyRNA *constraint_enable;
PropertyRNA *bone_hide_viewport;
-} RestrictProperties;
+};
/* We don't care about the value of the property
* but whether the property should be active or grayed out. */
-typedef struct RestrictPropertiesActive {
+struct RestrictPropertiesActive {
bool object_hide_viewport;
bool object_hide_select;
bool object_hide_render;
@@ -890,7 +904,7 @@ typedef struct RestrictPropertiesActive {
bool modifier_show_render;
bool constraint_enable;
bool bone_hide_viewport;
-} RestrictPropertiesActive;
+};
static void outliner_restrict_properties_enable_collection_set(
PointerRNA *collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active)
@@ -982,8 +996,9 @@ static bool outliner_restrict_properties_collection_set(Scene *scene,
RestrictPropertiesActive *props_active)
{
TreeStoreElem *tselem = TREESTORE(te);
- LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata :
- NULL;
+ LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
+ reinterpret_cast<LayerCollection *>(te->directdata) :
+ nullptr;
Collection *collection = outliner_collection_from_tree_element(te);
if (collection->flag & COLLECTION_IS_MASTER) {
@@ -992,7 +1007,7 @@ static bool outliner_restrict_properties_collection_set(Scene *scene,
/* Create the PointerRNA. */
RNA_id_pointer_create(&collection->id, collection_ptr);
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, layer_collection_ptr);
}
@@ -1096,7 +1111,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) {
/* View layer render toggle. */
- ViewLayer *layer = te->directdata;
+ ViewLayer *layer = reinterpret_cast<ViewLayer *>(te->directdata);
bt = uiDefIconButBitS(block,
UI_BTYPE_ICON_TOGGLE_N,
@@ -1113,7 +1128,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
0,
TIP_("Use view layer for rendering"));
- UI_but_func_set(bt, restrictbutton_r_lay_fn, tselem->id, NULL);
+ UI_but_func_set(bt, restrictbutton_r_lay_fn, tselem->id, nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
@@ -1256,7 +1271,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
-1,
-1,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
if (!props_active.constraint_enable) {
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
@@ -1285,7 +1300,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
-1,
-1,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
if (!props_active.modifier_show_viewport) {
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
@@ -1308,7 +1323,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
-1,
-1,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
if (!props_active.modifier_show_render) {
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
@@ -1320,7 +1335,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
@@ -1342,7 +1357,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
-1,
TIP_("Restrict visibility in the 3D View\n"
"* Shift to set children"));
- UI_but_func_set(bt, restrictbutton_bone_visibility_fn, bone, NULL);
+ UI_but_func_set(bt, restrictbutton_bone_visibility_fn, bone, nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
@@ -1470,11 +1485,12 @@ static void outliner_draw_restrictbuts(uiBlock *block,
scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active)) {
LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ?
- te->directdata :
- NULL;
+ reinterpret_cast<LayerCollection *>(
+ te->directdata) :
+ nullptr;
Collection *collection = outliner_collection_from_tree_element(te);
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
bt = uiDefIconButR_prop(block,
UI_BTYPE_ICON_TOGGLE,
@@ -1491,7 +1507,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
0,
0,
- NULL);
+ nullptr);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
}
@@ -1605,7 +1621,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
TIP_("Globally disable in viewports\n"
"* Ctrl to isolate collection\n"
"* Shift to set inside collections and objects"));
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
UI_but_func_set(bt,
view_layer__collection_set_flag_recursive_fn,
layer_collection,
@@ -1642,7 +1658,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
TIP_("Globally disable in renders\n"
"* Ctrl to isolate collection\n"
"* Shift to set inside collections and objects"));
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
UI_but_func_set(bt,
view_layer__collection_set_flag_recursive_fn,
layer_collection,
@@ -1677,7 +1693,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
TIP_("Disable selection in viewport\n"
"* Ctrl to isolate collection\n"
"* Shift to set inside collections and objects"));
- if (layer_collection != NULL) {
+ if (layer_collection != nullptr) {
UI_but_func_set(bt,
view_layer__collection_set_flag_recursive_fn,
layer_collection,
@@ -1721,7 +1737,7 @@ static void outliner_draw_userbuts(uiBlock *block,
if (tselem->type == TSE_SOME_ID) {
uiBut *bt;
ID *id = tselem->id;
- const char *tip = NULL;
+ const char *tip = nullptr;
char buf[16] = "";
int but_flag = UI_BUT_DRAG_LOCK;
@@ -1738,7 +1754,7 @@ static void outliner_draw_userbuts(uiBlock *block,
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
- NULL,
+ nullptr,
0.0,
0.0,
0,
@@ -1767,7 +1783,7 @@ static void outliner_draw_userbuts(uiBlock *block,
0,
0,
tip);
- UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
+ UI_but_func_set(bt, restrictbutton_id_user_toggle, id, nullptr);
UI_but_flag_enable(bt, but_flag);
}
}
@@ -1791,7 +1807,7 @@ static bool outliner_draw_overrides_buts(uiBlock *block,
const bool do_draw = (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin &&
te->ys <= region->v2d.cur.ymax);
int but_flag = UI_BUT_DRAG_LOCK;
- const char *tip = NULL;
+ const char *tip = nullptr;
TreeStoreElem *tselem = TREESTORE(te);
switch (tselem->type) {
@@ -1838,7 +1854,7 @@ static bool outliner_draw_overrides_buts(uiBlock *block,
if (do_draw &&
(item_has_warnings || (any_child_has_warnings && !TSELEM_OPEN(tselem, space_outliner)))) {
- if (tip == NULL) {
+ if (tip == nullptr) {
tip = TIP_("Some sub-items require attention");
}
uiBut *bt = uiDefIconBut(block,
@@ -1849,7 +1865,7 @@ static bool outliner_draw_overrides_buts(uiBlock *block,
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
- NULL,
+ nullptr,
0.0,
0.0,
0.0,
@@ -1894,20 +1910,20 @@ static void outliner_draw_rnacols(ARegion *region, int sizex)
static void outliner_draw_rnabuts(
uiBlock *block, ARegion *region, SpaceOutliner *space_outliner, int sizex, ListBase *lb)
{
- PointerRNA *ptr;
+ PointerRNA ptr;
PropertyRNA *prop;
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
- if (tselem->type == TSE_RNA_PROPERTY) {
- ptr = &te->rnaptr;
- prop = te->directdata;
+ if (TreeElementRNAProperty *te_rna_prop = tree_element_cast<TreeElementRNAProperty>(te)) {
+ ptr = te_rna_prop->getPointerRNA();
+ prop = te_rna_prop->getPropertyRNA();
if (!TSELEM_OPEN(tselem, space_outliner)) {
if (RNA_property_type(prop) == PROP_POINTER) {
uiBut *but = uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
-1,
"",
@@ -1920,10 +1936,10 @@ static void outliner_draw_rnabuts(
}
else if (RNA_property_type(prop) == PROP_ENUM) {
uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
-1,
- NULL,
+ nullptr,
ICON_NONE,
sizex,
te->ys,
@@ -1932,7 +1948,7 @@ static void outliner_draw_rnabuts(
}
else {
uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
-1,
"",
@@ -1944,12 +1960,13 @@ static void outliner_draw_rnabuts(
}
}
}
- else if (tselem->type == TSE_RNA_ARRAY_ELEM) {
- ptr = &te->rnaptr;
- prop = te->directdata;
+ else if (TreeElementRNAArrayElement *te_rna_array_elem =
+ tree_element_cast<TreeElementRNAArrayElement>(te)) {
+ ptr = te_rna_array_elem->getPointerRNA();
+ prop = te_rna_array_elem->getPropertyRNA();
uiDefAutoButR(block,
- ptr,
+ &ptr,
prop,
te->index,
"",
@@ -1983,13 +2000,13 @@ static void outliner_buttons(const bContext *C,
/* If we add support to rename Sequence, need change this. */
if (tselem->type == TSE_EBONE) {
- len = sizeof(((EditBone *)0)->name);
+ len = sizeof(((EditBone *)nullptr)->name);
}
else if (tselem->type == TSE_MODIFIER) {
- len = sizeof(((ModifierData *)0)->name);
+ len = sizeof(((ModifierData *)nullptr)->name);
}
else if (tselem->id && GS(tselem->id->name) == ID_LI) {
- len = sizeof(((Library *)0)->filepath);
+ len = sizeof(((Library *)nullptr)->filepath);
}
else {
len = MAX_ID_NAME - 2;
@@ -2019,7 +2036,7 @@ static void outliner_buttons(const bContext *C,
tselem->flag &= ~TSE_TEXTBUT;
/* Bad! (notifier within draw) without this, we don't get a refresh. */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
}
}
@@ -2036,7 +2053,7 @@ static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void *UNUSED
}
/* Check that the item is actually an object. */
- BLI_assert(tselem->id != NULL && GS(tselem->id->name) == ID_OB);
+ BLI_assert(tselem->id != nullptr && GS(tselem->id->name) == ID_OB);
Object *ob = (Object *)tselem->id;
const bool object_data_shared = (ob->data == tvc.obact->data);
@@ -2105,13 +2122,13 @@ static void outliner_draw_mode_column_toggle(uiBlock *block,
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
- NULL,
+ nullptr,
0.0,
0.0,
0.0,
0.0,
tip);
- UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL);
+ UI_but_func_set(but, outliner_mode_toggle_fn, tselem, nullptr);
UI_but_flag_enable(but, UI_BUT_DRAG_LOCK);
/* Mode toggling handles its own undo state because undo steps need to be grouped. */
UI_but_flag_disable(but, UI_BUT_UNDO);
@@ -2143,12 +2160,86 @@ static void outliner_draw_mode_column(const bContext *C,
}
}
+/* Returns `true` if some warning was drawn for that element or one of its sub-elements (if it is
+ * not open). */
+static bool outliner_draw_warning_tree_element(uiBlock *block,
+ SpaceOutliner *space_outliner,
+ TreeElement *te,
+ TreeStoreElem *tselem,
+ const bool use_mode_column,
+ const int te_ys)
+{
+ if ((te->flag & TE_HAS_WARNING) == 0) {
+ /* If given element has no warning, recursively try to display the first sub-elements' warning.
+ */
+ if (!TSELEM_OPEN(tselem, space_outliner)) {
+ LISTBASE_FOREACH (TreeElement *, sub_te, &te->subtree) {
+ TreeStoreElem *sub_tselem = TREESTORE(sub_te);
+
+ if (outliner_draw_warning_tree_element(
+ block, space_outliner, sub_te, sub_tselem, use_mode_column, te_ys)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ int icon = ICON_NONE;
+ const char *tip = "";
+ const bool has_warning = tree_element_warnings_get(te, &icon, &tip);
+ BLI_assert(has_warning);
+ UNUSED_VARS_NDEBUG(has_warning);
+
+ /* Move the warnings a unit left in view layer mode. */
+ const short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
+ UI_UNIT_X :
+ 0;
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS);
+ uiBut *but = uiDefIconBut(block,
+ UI_BTYPE_ICON_TOGGLE,
+ 0,
+ icon,
+ mode_column_offset,
+ te_ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ nullptr,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ tip);
+ /* No need for undo here, this is a pure info widget. */
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+
+ return true;
+}
+
+static void outliner_draw_warning_column(const bContext *C,
+ uiBlock *block,
+ SpaceOutliner *space_outliner,
+ const bool use_mode_column,
+ ListBase *tree)
+{
+ LISTBASE_FOREACH (TreeElement *, te, tree) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ outliner_draw_warning_tree_element(block, space_outliner, te, tselem, use_mode_column, te->ys);
+
+ if (TSELEM_OPEN(tselem, space_outliner)) {
+ outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &te->subtree);
+ }
+ }
+}
+
/* ****************************************************** */
/* Normal Drawing... */
TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
{
- TreeElementIcon data = {0};
+ TreeElementIcon data = {nullptr};
if (tselem->type != TSE_SOME_ID) {
switch (tselem->type) {
@@ -2182,7 +2273,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.drag_id = tselem->id;
break;
case TSE_CONSTRAINT: {
- bConstraint *con = te->directdata;
+ bConstraint *con = reinterpret_cast<bConstraint *>(te->directdata);
data.drag_id = tselem->id;
switch ((eBConstraint_Types)con->type) {
case CONSTRAINT_TYPE_CAMERASOLVER:
@@ -2295,9 +2386,11 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.drag_id = tselem->id;
if (ob->type != OB_GPENCIL) {
- ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr);
- const ModifierTypeInfo *modifier_type = BKE_modifier_get_info(md->type);
- if (modifier_type != NULL) {
+ ModifierData *md = reinterpret_cast<ModifierData *>(
+ BLI_findlink(&ob->modifiers, tselem->nr));
+ const ModifierTypeInfo *modifier_type = reinterpret_cast<const ModifierTypeInfo *>(
+ BKE_modifier_get_info((ModifierType)md->type));
+ if (modifier_type != nullptr) {
data.icon = modifier_type->icon;
}
else {
@@ -2306,7 +2399,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
}
else {
/* grease pencil modifiers */
- GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr);
+ GpencilModifierData *md = reinterpret_cast<GpencilModifierData *>(
+ BLI_findlink(&ob->greasepencil_modifiers, tselem->nr));
switch ((GpencilModifierType)md->type) {
case eGpencilModifierType_Noise:
data.icon = ICON_MOD_NOISE;
@@ -2462,22 +2556,26 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case TSE_SEQUENCE_DUP:
data.icon = ICON_SEQ_STRIP_DUPLICATE;
break;
- case TSE_RNA_STRUCT:
- if (RNA_struct_is_ID(te->rnaptr.type)) {
- data.drag_id = (ID *)te->rnaptr.data;
- data.icon = RNA_struct_ui_icon(te->rnaptr.type);
+ case TSE_RNA_STRUCT: {
+ const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te);
+ const PointerRNA &ptr = te_rna_struct->getPointerRNA();
+
+ if (RNA_struct_is_ID(ptr.type)) {
+ data.drag_id = reinterpret_cast<ID *>(ptr.data);
+ data.icon = RNA_struct_ui_icon(ptr.type);
}
else {
- data.icon = RNA_struct_ui_icon(te->rnaptr.type);
+ data.icon = RNA_struct_ui_icon(ptr.type);
}
break;
+ }
case TSE_LAYER_COLLECTION:
case TSE_SCENE_COLLECTION_BASE:
case TSE_VIEW_COLLECTION_BASE: {
Collection *collection = outliner_collection_from_tree_element(te);
if (collection && !(collection->flag & COLLECTION_IS_MASTER)) {
data.drag_id = tselem->id;
- data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL;
+ data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
}
data.icon = ICON_OUTLINER_COLLECTION;
@@ -2499,7 +2597,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
}
else if (tselem->id) {
data.drag_id = tselem->id;
- data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL;
+ data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr;
if (GS(tselem->id->name) == ID_OB) {
Object *ob = (Object *)tselem->id;
@@ -2639,7 +2737,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
break;
case ID_TXT: {
Text *text = (Text *)tselem->id;
- if (text->filepath == NULL || (text->flags & TXT_ISMEM)) {
+ if (text->filepath == nullptr || (text->flags & TXT_ISMEM)) {
data.icon = ICON_FILE_TEXT;
}
else {
@@ -2772,7 +2870,7 @@ static void tselem_draw_icon(uiBlock *block,
UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true);
}
else {
- UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, NULL, false);
+ UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false);
}
}
else {
@@ -2784,7 +2882,7 @@ static void tselem_draw_icon(uiBlock *block,
y,
UI_UNIT_X,
UI_UNIT_Y,
- NULL,
+ nullptr,
0.0,
0.0,
1.0,
@@ -2805,18 +2903,15 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
const float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
float ufac = 0.25f * UI_UNIT_X;
float offset_x = (float)offsx + UI_UNIT_X * 0.35f;
+ rctf rect{};
+ BLI_rctf_init(&rect,
+ offset_x + ufac,
+ offset_x + UI_UNIT_X - ufac,
+ (float)ys - UI_UNIT_Y * 0.2f + ufac,
+ (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(
- &(const rctf){
- .xmin = offset_x + ufac,
- .xmax = offset_x + UI_UNIT_X - ufac,
- .ymin = (float)ys - UI_UNIT_Y * 0.2f + ufac,
- .ymax = (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac,
- },
- true,
- (float)UI_UNIT_Y / 2.0f - ufac,
- color);
+ UI_draw_roundbox_aa(&rect, true, (float)UI_UNIT_Y / 2.0f - ufac, color);
/* Now the numbers. */
uchar text_col[4];
@@ -2829,7 +2924,7 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
/* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */
int num_digits = 4;
- char number_text[4] = "+99\0";
+ char number_text[4] = "+99";
if (num_elements < 100) {
BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements);
num_digits = num_elements < 10 ? 1 : 2;
@@ -2864,28 +2959,12 @@ static void outliner_draw_active_indicator(const float minx,
{
const float ufac = UI_UNIT_X / 20.0f;
const float radius = UI_UNIT_Y / 4.0f;
+ rctf rect{};
+ BLI_rctf_init(&rect, minx, maxx, miny + ufac, maxy - ufac);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(
- &(const rctf){
- .xmin = minx,
- .xmax = maxx,
- .ymin = miny + ufac,
- .ymax = maxy - ufac,
- },
- true,
- radius,
- icon_color);
- UI_draw_roundbox_aa(
- &(const rctf){
- .xmin = minx,
- .xmax = maxx,
- .ymin = miny + ufac,
- .ymax = maxy - ufac,
- },
- false,
- radius,
- icon_border);
+ UI_draw_roundbox_aa(&rect, true, radius, icon_color);
+ UI_draw_roundbox_aa(&rect, false, radius, icon_border);
GPU_blend(GPU_BLEND_ALPHA); /* Roundbox disables. */
}
@@ -2952,11 +3031,11 @@ int tree_element_id_type_to_index(TreeElement *te)
return id_index + OB_TYPE_MAX;
}
-typedef struct MergedIconRow {
+struct MergedIconRow {
eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX];
int num_elements[INDEX_ID_MAX + OB_TYPE_MAX];
TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX];
-} MergedIconRow;
+};
static void outliner_draw_iconrow(bContext *C,
uiBlock *block,
@@ -3014,7 +3093,7 @@ static void outliner_draw_iconrow(bContext *C,
else {
const int index = tree_element_id_type_to_index(te);
merged->num_elements[index]++;
- if ((merged->tree_element[index] == NULL) || (active > merged->active[index])) {
+ if ((merged->tree_element[index] == nullptr) || (active > merged->active[index])) {
merged->tree_element[index] = te;
}
merged->active[index] = MAX2(active, merged->active[index]);
@@ -3091,7 +3170,7 @@ static bool element_should_draw_faded(const TreeViewContext *tvc,
const Base *base = (te->directdata) ? (const Base *)te->directdata :
BKE_view_layer_base_find(
(ViewLayer *)tvc->view_layer, (Object *)ob);
- const bool is_visible = (base != NULL) && (base->flag & BASE_VISIBLE_VIEWLAYER);
+ const bool is_visible = (base != nullptr) && (base->flag & BASE_VISIBLE_VIEWLAYER);
if (!is_visible) {
return true;
}
@@ -3140,7 +3219,7 @@ static void outliner_draw_tree_element(bContext *C,
const float alpha_fac = element_should_draw_faded(tvc, te, tselem) ? 0.5f : 1.0f;
int xmax = region->v2d.cur.xmax;
- if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) {
+ if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == nullptr)) {
*te_edit = te;
}
@@ -3157,7 +3236,7 @@ static void outliner_draw_tree_element(bContext *C,
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
BKE_view_layer_base_find(tvc->view_layer, ob);
- const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
+ const bool is_selected = (base != nullptr) && ((base->flag & BASE_SELECTED) != 0);
if (ob == tvc->obact) {
active = OL_DRAWSEL_ACTIVE;
@@ -3246,9 +3325,10 @@ static void outliner_draw_tree_element(bContext *C,
offsx += 2 * ufac;
}
+ const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te);
if (ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION) ||
- ((tselem->type == TSE_RNA_STRUCT) && RNA_struct_is_ID(te->rnaptr.type))) {
- const BIFIconID lib_icon = UI_icon_from_library(tselem->id);
+ (te_rna_struct && RNA_struct_is_ID(te_rna_struct->getPointerRNA().type))) {
+ const BIFIconID lib_icon = (BIFIconID)UI_icon_from_library(tselem->id);
if (lib_icon != ICON_NONE) {
UI_icon_draw_alpha(
(float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, lib_icon, alpha_fac);
@@ -3281,7 +3361,7 @@ static void outliner_draw_tree_element(bContext *C,
GPU_blend(GPU_BLEND_ALPHA);
- MergedIconRow merged = {{0}};
+ MergedIconRow merged{};
outliner_draw_iconrow(C,
block,
fstyle,
@@ -3352,7 +3432,7 @@ static void outliner_draw_hierarchy_line(
/* Small vertical padding. */
const short line_padding = UI_UNIT_Y / 4.0f;
- /* >= is 1.0 for undashed lines. */
+ /* >= is 1.0 for un-dashed lines. */
immUniform1f("dash_factor", draw_dashed ? 0.5f : 1.0f);
immBegin(GPU_PRIM_LINES, 2);
@@ -3612,17 +3692,22 @@ static void outliner_draw_tree(bContext *C,
SpaceOutliner *space_outliner,
const float restrict_column_width,
const bool use_mode_column,
+ const bool use_warning_column,
TreeElement **te_edit)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
int starty, startx;
/* Move the tree a unit left in view layer mode */
- short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
- UI_UNIT_X :
- 0;
+ short columns_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
+ UI_UNIT_X :
+ 0;
if (!use_mode_column && (space_outliner->outlinevis == SO_VIEW_LAYER)) {
- mode_column_offset -= UI_UNIT_X;
+ columns_offset -= UI_UNIT_X;
+ }
+
+ if (use_warning_column) {
+ columns_offset += UI_UNIT_X;
}
GPU_blend(GPU_BLEND_ALPHA); /* Only once. */
@@ -3650,12 +3735,12 @@ static void outliner_draw_tree(bContext *C,
/* Draw hierarchy lines for collections and object children. */
starty = (int)region->v2d.tot.ymax - OL_Y_OFFSET;
- startx = mode_column_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
+ startx = columns_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, startx, &starty);
/* Items themselves. */
starty = (int)region->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
- startx = mode_column_offset;
+ startx = columns_offset;
LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
outliner_draw_tree_element(C,
block,
@@ -3755,7 +3840,7 @@ void draw_outliner(const bContext *C)
View2D *v2d = &region->v2d;
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
uiBlock *block;
- TreeElement *te_edit = NULL;
+ TreeElement *te_edit = nullptr;
TreeViewContext tvc;
outliner_viewcontext_init(C, &tvc);
@@ -3786,6 +3871,11 @@ void draw_outliner(const bContext *C)
const bool use_mode_column = (space_outliner->flag & SO_MODE_COLUMN) &&
(ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES));
+ const bool use_warning_column = ELEM(space_outliner->outlinevis,
+ SO_LIBRARIES,
+ SO_OVERRIDES_LIBRARY) &&
+ space_outliner->runtime->tree_display->hasWarnings();
+
/* Draw outliner stuff (background, hierarchy lines and names). */
const float restrict_column_width = outliner_restrict_columns_width(space_outliner);
outliner_back(region);
@@ -3797,6 +3887,7 @@ void draw_outliner(const bContext *C)
space_outliner,
restrict_column_width,
use_mode_column,
+ use_warning_column,
&te_edit);
/* Compute outliner dimensions after it has been drawn. */
@@ -3841,6 +3932,11 @@ void draw_outliner(const bContext *C)
outliner_draw_mode_column(C, block, &tvc, space_outliner, &space_outliner->tree);
}
+ /* Draw warning icons */
+ if (use_warning_column) {
+ outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &space_outliner->tree);
+ }
+
UI_block_emboss_set(block, UI_EMBOSS);
/* Draw edit buttons if necessary. */
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.cc
index 9d4b14a1f57..b41b260b14a 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -38,6 +38,7 @@
#include "BLT_translation.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_appdir.h"
#include "BKE_armature.h"
@@ -48,6 +49,7 @@
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
+#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_workspace.h"
@@ -71,7 +73,10 @@
#include "GPU_material.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
+#include "tree/tree_element_rna.hh"
+
+using namespace blender::ed::outliner;
static void outliner_show_active(SpaceOutliner *space_outliner,
ARegion *region,
@@ -105,11 +110,11 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const
TreeElement *hovered_te = outliner_find_item_at_y(
space_outliner, &space_outliner->tree, view_mval[1]);
- TreeElement *icon_te = NULL;
+ TreeElement *icon_te = nullptr;
bool is_over_icon = false;
if (hovered_te) {
icon_te = outliner_find_item_at_x_in_row(
- space_outliner, hovered_te, view_mval[0], NULL, &is_over_icon);
+ space_outliner, hovered_te, view_mval[0], nullptr, &is_over_icon);
}
bool changed = false;
@@ -181,11 +186,11 @@ void outliner_item_openclose(SpaceOutliner *space_outliner,
}
}
-typedef struct OpenCloseData {
+struct OpenCloseData {
TreeStoreElem *prev_tselem;
bool open;
int x_location;
-} OpenCloseData;
+};
static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -216,7 +221,7 @@ static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEv
data->prev_tselem = TREESTORE(te);
}
else {
- data->prev_tselem = NULL;
+ data->prev_tselem = nullptr;
}
}
else if (event->val == KM_RELEASE) {
@@ -256,7 +261,7 @@ static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmE
}
/* Store last expanded tselem and x coordinate of disclosure triangle */
- OpenCloseData *toggle_data = MEM_callocN(sizeof(OpenCloseData), "open_close_data");
+ OpenCloseData *toggle_data = MEM_cnew<OpenCloseData>("open_close_data");
toggle_data->prev_tselem = tselem;
toggle_data->open = open;
toggle_data->x_location = te->xs;
@@ -373,7 +378,7 @@ static TreeElement *outliner_item_rename_find_active(const SpaceOutliner *space_
if (!active_element) {
BKE_report(reports, RPT_WARNING, "No active item to rename");
- return NULL;
+ return nullptr;
}
return active_element;
@@ -391,7 +396,7 @@ static TreeElement *outliner_item_rename_find_hovered(const SpaceOutliner *space
return hovered;
}
- return NULL;
+ return nullptr;
}
static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *event)
@@ -450,12 +455,12 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
Main *bmain = CTX_data_main(C);
ID *id = tselem->id;
- BLI_assert(id != NULL);
+ BLI_assert(id != nullptr);
BLI_assert(((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
(tselem->type == TSE_LAYER_COLLECTION));
UNUSED_VARS_NDEBUG(te);
- if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) {
+ if (te->idcode == ID_LI && ((Library *)id)->parent != nullptr) {
BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked library '%s'", id->name);
return;
}
@@ -481,7 +486,7 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
BKE_id_delete(bmain, id);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
void id_delete_fn(bContext *C,
@@ -573,13 +578,13 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const short id_type = (short)RNA_enum_get(op->ptr, "id_type");
- ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type),
- RNA_enum_get(op->ptr, "old_id"));
- ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type),
- RNA_enum_get(op->ptr, "new_id"));
+ ID *old_id = reinterpret_cast<ID *>(
+ BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")));
+ ID *new_id = reinterpret_cast<ID *>(
+ BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")));
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -612,7 +617,7 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
* such as lights so freeing correctly refreshes. */
GPU_materials_free(bmain);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
return OPERATOR_FINISHED;
}
@@ -627,8 +632,6 @@ static bool outliner_id_remap_find_tree_element(bContext *C,
TreeStoreElem *tselem = TREESTORE(te);
if ((tselem->type == TSE_SOME_ID) && tselem->id) {
- printf("found id %s (%p)!\n", tselem->id->name, tselem->id);
-
RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
@@ -654,7 +657,7 @@ static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *
outliner_id_remap_find_tree_element(C, op, &space_outliner->tree, fmval[1]);
}
- return WM_operator_props_dialog_popup(C, op, 200);
+ return WM_operator_props_dialog_popup(C, op, 400);
}
static const EnumPropertyItem *outliner_id_itemf(bContext *C,
@@ -662,18 +665,18 @@ static const EnumPropertyItem *outliner_id_itemf(bContext *C,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
- if (C == NULL) {
+ if (C == nullptr) {
return DummyRNA_NULL_items;
}
- EnumPropertyItem item_tmp = {0}, *item = NULL;
+ EnumPropertyItem item_tmp = {0}, *item = nullptr;
int totitem = 0;
int i = 0;
short id_type = (short)RNA_enum_get(ptr, "id_type");
- ID *id = which_libbase(CTX_data_main(C), id_type)->first;
+ ID *id = reinterpret_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first);
- for (; id; id = id->next) {
+ for (; id; id = reinterpret_cast<ID *>(id->next)) {
item_tmp.identifier = item_tmp.name = id->name + 2;
item_tmp.value = i++;
RNA_enum_item_add(&item, &totitem, &item_tmp);
@@ -703,10 +706,13 @@ 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);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN);
+ RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, outliner_id_itemf);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN));
ot->prop = RNA_def_enum(ot->srna,
"new_id",
@@ -714,7 +720,7 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
0,
"New ID",
"New ID to remap all selected IDs' users to");
- RNA_def_property_enum_funcs_runtime(ot->prop, NULL, NULL, outliner_id_itemf);
+ RNA_def_property_enum_funcs_runtime(ot->prop, nullptr, nullptr, outliner_id_itemf);
RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE);
}
@@ -729,7 +735,7 @@ void id_remap_fn(bContext *C,
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
PointerRNA op_props;
- BLI_assert(tselem->id != NULL);
+ BLI_assert(tselem->id != nullptr);
WM_operator_properties_create_ptr(&op_props, ot);
@@ -826,7 +832,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted);
@@ -860,7 +866,7 @@ static int lib_relocate(
PointerRNA op_props;
int ret = 0;
- BLI_assert(te->idcode == ID_LI && tselem->id != NULL);
+ BLI_assert(te->idcode == ID_LI && tselem->id != nullptr);
UNUSED_VARS_NDEBUG(te);
WM_operator_properties_create_ptr(&op_props, ot);
@@ -1252,17 +1258,18 @@ static TreeElement *outliner_show_active_get_element(bContext *C,
Object *obact = OBACT(view_layer);
if (!obact) {
- return NULL;
+ return nullptr;
}
te = outliner_find_id(space_outliner, &space_outliner->tree, &obact->id);
- if (te != NULL && obact->type == OB_ARMATURE) {
+ if (te != nullptr && obact->type == OB_ARMATURE) {
/* traverse down the bone hierarchy in case of armature */
TreeElement *te_obact = te;
if (obact->mode & OB_MODE_POSE) {
- bPoseChannel *pchan = CTX_data_active_pose_bone(C);
+ Object *obpose = BKE_object_pose_armature_get(obact);
+ bPoseChannel *pchan = BKE_pose_channel_active(obpose, false);
if (pchan) {
te = outliner_find_posechannel(&te_obact->subtree, pchan);
}
@@ -1385,7 +1392,7 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
/* properties */
- prop = RNA_def_boolean(ot->srna, "up", 0, "Up", "Scroll up one page");
+ prop = RNA_def_boolean(ot->srna, "up", false, "Up", "Scroll up one page");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -1429,14 +1436,14 @@ static TreeElement *outliner_find_name(
}
/* nothing valid found */
- return NULL;
+ return nullptr;
}
static void outliner_find_panel(
Scene *UNUSED(scene), ARegion *region, SpaceOutliner *space_outliner, int again, int flags)
{
- ReportList *reports = NULL; /* CTX_wm_reports(C); */
- TreeElement *te = NULL;
+ ReportList *reports = nullptr; /* CTX_wm_reports(C); */
+ TreeElement *te = nullptr;
TreeElement *last_find;
TreeStoreElem *tselem;
int ytop, xdelta, prevFound = 0;
@@ -1453,7 +1460,7 @@ static void outliner_find_panel(
/* try to find matching element */
te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound);
- if (te == NULL) {
+ if (te == nullptr) {
/* no more matches after previous, start from beginning again */
prevFound = 1;
te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound);
@@ -1462,10 +1469,10 @@ static void outliner_find_panel(
else {
/* pop up panel - no previous, or user didn't want search after previous */
name[0] = '\0';
- /* XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) { */
- /* te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, NULL, &prevFound); */
- /* } */
- /* else return; XXX RETURN! XXX */
+ // XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) {
+ // te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, nullptr, &prevFound);
+ // }
+ // else return; XXX RETURN! XXX
}
/* do selection and reveal */
@@ -1481,7 +1488,7 @@ static void outliner_find_panel(
outliner_flag_set(space_outliner, &space_outliner->tree, TSE_SELECTED, 0);
tselem->flag |= TSE_SELECTED;
- /* make te->ys center of view */
+ /* Make `te->ys` center of view. */
ytop = (int)(te->ys + BLI_rctf_size_y(&region->v2d.mask) / 2);
if (ytop > 0) {
ytop = 0;
@@ -1489,7 +1496,7 @@ static void outliner_find_panel(
region->v2d.cur.ymax = (float)ytop;
region->v2d.cur.ymin = (float)(ytop - BLI_rctf_size_y(&region->v2d.mask));
- /* make te->xs ==> te->xend center of view */
+ /* Make `te->xs` ==> `te->xend` center of view. */
xdelta = (int)(te->xs - region->v2d.cur.xmin);
region->v2d.cur.xmin += xdelta;
region->v2d.cur.xmax += xdelta;
@@ -1582,7 +1589,7 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot)
/* no undo or registry, UI option */
/* properties */
- prop = RNA_def_boolean(ot->srna, "open", 1, "Open", "Expand all entries one level deep");
+ prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Expand all entries one level deep");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -1694,7 +1701,7 @@ static bool ed_operator_outliner_datablocks_active(bContext *C)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
return (space_outliner->outlinevis == SO_DATA_API);
}
- return 0;
+ return false;
}
/* Helper func to extract an RNA path from selected tree element
@@ -1709,13 +1716,8 @@ static void tree_element_to_path(TreeElement *te,
short *flag,
short *UNUSED(groupmode))
{
- ListBase hierarchy = {NULL, NULL};
- LinkData *ld;
- TreeElement *tem, *temnext;
- TreeStoreElem *tse /* , *tsenext */ /* UNUSED */;
- PointerRNA *ptr, *nextptr;
- PropertyRNA *prop;
- char *newpath = NULL;
+ ListBase hierarchy = {nullptr, nullptr};
+ char *newpath = nullptr;
/* optimize tricks:
* - Don't do anything if the selected item is a 'struct', but arrays are allowed
@@ -1734,20 +1736,19 @@ static void tree_element_to_path(TreeElement *te,
*/
/* step 1: flatten out hierarchy of parents into a flat chain */
- for (tem = te->parent; tem; tem = tem->parent) {
- ld = MEM_callocN(sizeof(LinkData), "LinkData for tree_element_to_path()");
+ for (TreeElement *tem = te->parent; tem; tem = tem->parent) {
+ LinkData *ld = MEM_cnew<LinkData>("LinkData for tree_element_to_path()");
ld->data = tem;
BLI_addhead(&hierarchy, ld);
}
/* step 2: step down hierarchy building the path
* (NOTE: addhead in previous loop was needed so that we can loop like this) */
- for (ld = hierarchy.first; ld; ld = ld->next) {
+ LISTBASE_FOREACH (LinkData *, ld, &hierarchy) {
/* get data */
- tem = (TreeElement *)ld->data;
- tse = TREESTORE(tem);
- ptr = &tem->rnaptr;
- prop = tem->directdata;
+ TreeElement *tem = (TreeElement *)ld->data;
+ TreeElementRNACommon *tem_rna = tree_element_cast<TreeElementRNACommon>(tem);
+ PointerRNA ptr = tem_rna->getPointerRNA();
/* check if we're looking for first ID, or appending to path */
if (*id) {
@@ -1755,23 +1756,23 @@ static void tree_element_to_path(TreeElement *te,
* - to prevent memory leaks, we must write to newpath not path,
* then free old path + swap them.
*/
- if (tse->type == TSE_RNA_PROPERTY) {
+ if (TreeElementRNAProperty *tem_rna_prop = tree_element_cast<TreeElementRNAProperty>(tem)) {
+ PropertyRNA *prop = tem_rna_prop->getPropertyRNA();
+
if (RNA_property_type(prop) == PROP_POINTER) {
/* for pointer we just append property name */
- newpath = RNA_path_append(*path, ptr, prop, 0, NULL);
+ newpath = RNA_path_append(*path, &ptr, prop, 0, nullptr);
}
else if (RNA_property_type(prop) == PROP_COLLECTION) {
char buf[128], *name;
- temnext = (TreeElement *)(ld->next->data);
- // tsenext = TREESTORE(temnext); /* UNUSED */
-
- nextptr = &temnext->rnaptr;
- name = RNA_struct_name_get_alloc(nextptr, buf, sizeof(buf), NULL);
+ TreeElement *temnext = (TreeElement *)(ld->next->data);
+ PointerRNA nextptr = tree_element_cast<TreeElementRNACommon>(temnext)->getPointerRNA();
+ name = RNA_struct_name_get_alloc(&nextptr, buf, sizeof(buf), nullptr);
if (name) {
/* if possible, use name as a key in the path */
- newpath = RNA_path_append(*path, NULL, prop, 0, name);
+ newpath = RNA_path_append(*path, nullptr, prop, 0, name);
if (name != buf) {
MEM_freeN(name);
@@ -1785,8 +1786,9 @@ static void tree_element_to_path(TreeElement *te,
if (temsub == temnext) {
break;
}
+ index++;
}
- newpath = RNA_path_append(*path, NULL, prop, index, NULL);
+ newpath = RNA_path_append(*path, nullptr, prop, index, nullptr);
}
ld = ld->next;
@@ -1798,22 +1800,22 @@ static void tree_element_to_path(TreeElement *te,
MEM_freeN(*path);
}
*path = newpath;
- newpath = NULL;
+ newpath = nullptr;
}
}
else {
/* no ID, so check if entry is RNA-struct,
* and if that RNA-struct is an ID datablock to extract info from. */
- if (tse->type == TSE_RNA_STRUCT) {
+ if (tree_element_cast<TreeElementRNAStruct>(tem)) {
/* ptr->data not ptr->owner_id seems to be the one we want,
* since ptr->data is sometimes the owner of this ID? */
- if (RNA_struct_is_ID(ptr->type)) {
- *id = ptr->data;
+ if (RNA_struct_is_ID(ptr.type)) {
+ *id = reinterpret_cast<ID *>(ptr.data);
/* clear path */
if (*path) {
MEM_freeN(*path);
- path = NULL;
+ path = nullptr;
}
}
}
@@ -1823,8 +1825,7 @@ static void tree_element_to_path(TreeElement *te,
/* step 3: if we've got an ID, add the current item to the path */
if (*id) {
/* add the active property to the path */
- ptr = &te->rnaptr;
- prop = te->directdata;
+ PropertyRNA *prop = tree_element_cast<TreeElementRNACommon>(te)->getPropertyRNA();
/* array checks */
if (tselem->type == TSE_RNA_ARRAY_ELEM) {
@@ -1837,7 +1838,7 @@ static void tree_element_to_path(TreeElement *te,
}
/* path */
- newpath = RNA_path_append(*path, NULL, prop, 0, NULL);
+ newpath = RNA_path_append(*path, nullptr, prop, 0, nullptr);
if (*path) {
MEM_freeN(*path);
}
@@ -1876,15 +1877,18 @@ static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
/* if item is selected, perform operation */
if (tselem->flag & TSE_SELECTED) {
- ID *id = NULL;
- char *path = NULL;
+ ID *id = nullptr;
+ char *path = nullptr;
int array_index = 0;
short flag = 0;
short groupmode = KSP_GROUP_KSNAME;
+ TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te);
+ PointerRNA ptr = te_rna ? te_rna->getPointerRNA() : PointerRNA_NULL;
+ PropertyRNA *prop = te_rna ? te_rna->getPropertyRNA() : nullptr;
+
/* check if RNA-property described by this selected element is an animatable prop */
- if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) &&
- RNA_property_animateable(&te->rnaptr, te->directdata)) {
+ if (prop && RNA_property_animateable(&ptr, prop)) {
/* get id + path + index info from the selected element */
tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
}
@@ -1897,7 +1901,7 @@ static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
/* array checks */
if (flag & KSP_FLAG_WHOLE_ARRAY) {
/* entire array was selected, so add drivers for all */
- arraylen = RNA_property_array_length(&te->rnaptr, te->directdata);
+ arraylen = RNA_property_array_length(&ptr, prop);
}
else {
arraylen = array_index;
@@ -1948,7 +1952,7 @@ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -1957,7 +1961,7 @@ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_ADD);
/* send notifiers */
- WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); /* XXX */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, nullptr); /* XXX */
return OPERATOR_FINISHED;
}
@@ -1988,7 +1992,7 @@ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -1997,7 +2001,7 @@ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_REMOVE);
/* send notifiers */
- WM_event_add_notifier(C, ND_KEYS, NULL); /* XXX */
+ WM_event_add_notifier(C, ND_KEYS, nullptr); /* XXX */
return OPERATOR_FINISHED;
}
@@ -2038,22 +2042,23 @@ enum {
/* TODO: should this be an API func? */
static KeyingSet *verify_active_keyingset(Scene *scene, short add)
{
- KeyingSet *ks = NULL;
+ KeyingSet *ks = nullptr;
/* sanity check */
- if (scene == NULL) {
- return NULL;
+ if (scene == nullptr) {
+ return nullptr;
}
/* try to find one from scene */
if (scene->active_keyingset > 0) {
- ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1);
+ ks = reinterpret_cast<KeyingSet *>(
+ BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1));
}
/* Add if none found */
/* XXX the default settings have yet to evolve. */
- if ((add) && (ks == NULL)) {
- ks = BKE_keyingset_add(&scene->keyingsets, NULL, NULL, KEYINGSET_ABSOLUTE, 0);
+ if ((add) && (ks == nullptr)) {
+ ks = BKE_keyingset_add(&scene->keyingsets, nullptr, nullptr, KEYINGSET_ABSOLUTE, 0);
scene->active_keyingset = BLI_listbase_count(&scene->keyingsets);
}
@@ -2071,15 +2076,17 @@ static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner,
/* if item is selected, perform operation */
if (tselem->flag & TSE_SELECTED) {
- ID *id = NULL;
- char *path = NULL;
+ ID *id = nullptr;
+ char *path = nullptr;
int array_index = 0;
short flag = 0;
short groupmode = KSP_GROUP_KSNAME;
/* check if RNA-property described by this selected element is an animatable prop */
- if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) &&
- RNA_property_animateable(&te->rnaptr, te->directdata)) {
+ const TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te);
+ PointerRNA ptr = te_rna->getPointerRNA();
+ if (te_rna && te_rna->getPropertyRNA() &&
+ RNA_property_animateable(&ptr, te_rna->getPropertyRNA())) {
/* get id + path + index info from the selected element */
tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
}
@@ -2092,13 +2099,13 @@ static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner,
/* add a new path with the information obtained (only if valid) */
/* TODO: what do we do with group name?
* for now, we don't supply one, and just let this use the KeyingSet name */
- BKE_keyingset_add_path(ks, id, NULL, path, array_index, flag, groupmode);
+ BKE_keyingset_add_path(ks, id, nullptr, path, array_index, flag, groupmode);
ks->active_path = BLI_listbase_count(&ks->paths);
break;
}
case KEYINGSET_EDITMODE_REMOVE: {
/* find the relevant path, then remove it from the KeyingSet */
- KS_Path *ksp = BKE_keyingset_find_path(ks, id, NULL, path, array_index, groupmode);
+ KS_Path *ksp = BKE_keyingset_find_path(ks, id, nullptr, path, array_index, groupmode);
if (ksp) {
/* free path's data */
@@ -2135,11 +2142,11 @@ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
KeyingSet *ks = verify_active_keyingset(scene, 1);
/* check for invalid states */
- if (ks == NULL) {
+ if (ks == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Operation requires an active keying set");
return OPERATOR_CANCELLED;
}
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2147,7 +2154,7 @@ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
do_outliner_keyingset_editop(space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_ADD);
/* send notifiers */
- WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr);
return OPERATOR_FINISHED;
}
@@ -2180,7 +2187,7 @@ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(o
KeyingSet *ks = verify_active_keyingset(scene, 1);
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2189,7 +2196,7 @@ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(o
space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_REMOVE);
/* send notifiers */
- WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr);
return OPERATOR_FINISHED;
}
@@ -2218,7 +2225,7 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
static bool ed_operator_outliner_id_orphans_active(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
- if (area != NULL && area->spacetype == SPACE_OUTLINER) {
+ if (area != nullptr && area->spacetype == SPACE_OUTLINER) {
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
return (space_outliner->outlinevis == SO_ID_ORPHANS);
}
@@ -2303,14 +2310,14 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
* outliner several mouse events can be handled in one cycle without
* handling notifiers/redraw which leads to deleting the same object twice.
* cleanup tree here to prevent such cases. */
- if ((area != NULL) && (area->spacetype == SPACE_OUTLINER)) {
+ if ((area != nullptr) && (area->spacetype == SPACE_OUTLINER)) {
outliner_cleanup_tree(space_outliner);
}
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_ID | NA_REMOVED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_REMOVED, nullptr);
/* Force full redraw of the UI. */
- WM_main_add_notifier(NC_WINDOW, NULL);
+ WM_main_add_notifier(NC_WINDOW, nullptr);
return OPERATOR_FINISHED;
}
@@ -2332,7 +2339,7 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
/* properties */
PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
RNA_def_boolean(ot->srna,
"do_local_ids",
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.hh
index 3439e4fa219..9db1d73dc76 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -23,8 +23,13 @@
#pragma once
+#include <memory>
+
#include "RNA_types.h"
+/* Needed for `tree_element_cast()`. */
+#include "tree/tree_element.hh"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -47,15 +52,25 @@ struct bPoseChannel;
struct wmKeyConfig;
struct wmOperatorType;
-typedef struct SpaceOutliner_Runtime {
- /** Internal C++ object to create and manage the tree for a specific display type (View Layers,
- * Scenes, Blender File, etc.). */
- struct TreeDisplay *tree_display;
+namespace blender::ed::outliner {
+class AbstractTreeDisplay;
+class AbstractTreeElement;
+} // namespace blender::ed::outliner
+
+struct SpaceOutliner_Runtime {
+ /** Object to create and manage the tree for a specific display type (View Layers, Scenes,
+ * Blender File, etc.). */
+ std::unique_ptr<blender::ed::outliner::AbstractTreeDisplay> tree_display;
/** Pointers to tree-store elements, grouped by `(id, type, nr)`
* in hash-table for faster searching. */
struct GHash *treehash;
-} SpaceOutliner_Runtime;
+
+ SpaceOutliner_Runtime() = default;
+ /** Used for copying runtime data to a duplicated space. */
+ SpaceOutliner_Runtime(const SpaceOutliner_Runtime &);
+ ~SpaceOutliner_Runtime();
+};
typedef enum TreeElementInsertType {
TE_INSERT_BEFORE,
@@ -82,7 +97,7 @@ typedef struct TreeElement {
* #TreeElement. Step by step, data should be moved to it and operations based on the type should
* become virtual methods of the class hierarchy.
*/
- struct TreeElementType *type;
+ std::unique_ptr<blender::ed::outliner::AbstractTreeElement> type;
ListBase subtree;
int xs, ys; /* Do selection. */
@@ -92,8 +107,7 @@ typedef struct TreeElement {
short idcode; /* From TreeStore id. */
short xend; /* Width of item display, for select. */
const char *name;
- void *directdata; /* Armature Bones, Base, Sequence, Strip... */
- PointerRNA rnaptr; /* RNA Pointer. */
+ void *directdata; /* Armature Bones, Base, ... */
} TreeElement;
typedef struct TreeElementIcon {
@@ -158,6 +172,8 @@ enum {
/* Child elements of the same type in the icon-row are drawn merged as one icon.
* This flag is set for an element that is part of these merged child icons. */
TE_ICONROW_MERGED = (1 << 7),
+ /* This element has some warning to be displayed. */
+ TE_HAS_WARNING = (1 << 8),
};
/* button events */
@@ -211,7 +227,7 @@ typedef enum {
* - not searching into RNA items helps but isn't the complete solution
*/
-#define SEARCHING_OUTLINER(sov) (sov->search_flags & SO_SEARCH_RECURSIVE)
+#define SEARCHING_OUTLINER(sov) ((sov)->search_flags & SO_SEARCH_RECURSIVE)
/* is the current element open? if so we also show children */
#define TSELEM_OPEN(telm, sv) \
@@ -267,6 +283,10 @@ void outliner_build_tree(struct Main *mainvar,
struct SpaceOutliner *space_outliner,
struct ARegion *region);
+struct TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
+ struct Collection *collection,
+ TreeElement *ten);
+
bool outliner_requires_rebuild_on_select_or_active_change(
const struct SpaceOutliner *space_outliner);
/**
@@ -296,7 +316,7 @@ void outliner_collection_isolate_flag(struct Scene *scene,
struct Collection *collection,
struct PropertyRNA *layer_or_collection_prop,
const char *propname,
- const bool value);
+ bool value);
/**
* Return the index to use based on the TreeElement ID and object type
@@ -314,7 +334,7 @@ void tree_element_type_active_set(struct bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
TreeStoreElem *tselem,
- const eOLSetState set,
+ eOLSetState set,
bool recursive);
/**
* Generic call for non-id data to check the active state in UI.
@@ -329,8 +349,8 @@ eOLDrawState tree_element_type_active_state_get(const struct bContext *C,
void tree_element_activate(struct bContext *C,
const TreeViewContext *tvc,
TreeElement *te,
- const eOLSetState set,
- const bool handle_all_types);
+ eOLSetState set,
+ bool handle_all_types);
eOLDrawState tree_element_active_state_get(const TreeViewContext *tvc,
const TreeElement *te,
const TreeStoreElem *tselem);
@@ -343,7 +363,7 @@ struct bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_
void outliner_item_select(struct bContext *C,
struct SpaceOutliner *space_outliner,
struct TreeElement *te,
- const short select_flag);
+ short select_flag);
/**
* Find if x coordinate is over an icon or name.
@@ -366,7 +386,7 @@ bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const floa
void outliner_item_mode_toggle(struct bContext *C,
TreeViewContext *tvc,
TreeElement *te,
- const bool do_extend);
+ bool do_extend);
/* outliner_edit.c ---------------------------------------------- */
typedef void (*outliner_operation_fn)(struct bContext *C,
@@ -396,7 +416,7 @@ void outliner_do_object_operation(struct bContext *C,
struct ListBase *lb,
outliner_operation_fn operation_fn);
-int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel);
+int outliner_flag_is_any_test(ListBase *lb, short flag, int curlevel);
/**
* Set or unset \a flag for all outliner elements in \a lb and sub-trees.
* \return if any flag was modified.
@@ -592,7 +612,7 @@ TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner,
bool *r_is_merged_icon,
bool *r_is_over_icon);
/**
- * `tse` is not in the treestore, we use its contents to find a match.
+ * `tse` is not in the tree-store, we use its contents to find a match.
*/
TreeElement *outliner_find_tse(struct SpaceOutliner *space_outliner, const TreeStoreElem *tse);
/**
@@ -606,7 +626,7 @@ TreeElement *outliner_find_parent_element(ListBase *lb,
TreeElement *parent_te,
const TreeElement *child_te);
/**
- * Find treestore that refers to given ID.
+ * Find tree-store that refers to given ID.
*/
TreeElement *outliner_find_id(struct SpaceOutliner *space_outliner,
ListBase *lb,
@@ -631,7 +651,7 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
void *customdata);
float outliner_restrict_columns_width(const struct SpaceOutliner *space_outliner);
/**
- * Find first tree element in tree with matching treestore flag.
+ * Find first tree element in tree with matching tree-store flag.
*/
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag);
/**
@@ -668,3 +688,19 @@ int outliner_context(const struct bContext *C,
#ifdef __cplusplus
}
#endif
+
+namespace blender::ed::outliner {
+
+/**
+ * Helper to safely "cast" a #TreeElement to its new C++ #AbstractTreeElement, if possible.
+ * \return nullptr if the tree-element doesn't match the requested type \a TreeElementT or the
+ * element doesn't hold a C++ #AbstractTreeElement pendant yet.
+ */
+template<typename TreeElementT> TreeElementT *tree_element_cast(const TreeElement *te)
+{
+ static_assert(std::is_base_of_v<AbstractTreeElement, TreeElementT>,
+ "Requested tree-element type must be an AbstractTreeElement");
+ return dynamic_cast<TreeElementT *>(te->type.get());
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.cc
index 7e5b0c90714..4664a3150a1 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.cc
@@ -25,7 +25,7 @@
#include "ED_screen.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
/* ************************** registration **********************************/
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.cc
index 855975eb2dc..3ff8b9e973f 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <stdlib.h>
+#include <cstdlib>
#include "MEM_guardedalloc.h"
@@ -79,7 +79,10 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
+#include "tree/tree_element_seq.hh"
+
+using namespace blender::ed::outliner;
/**
* \note changes to selection are by convention and not essential.
@@ -96,14 +99,14 @@ static void do_outliner_item_editmode_toggle(bContext *C, Scene *scene, Base *ba
changed = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
if (changed) {
ED_object_base_select(base, BA_DESELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, nullptr);
}
}
else {
changed = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT);
if (changed) {
ED_object_base_select(base, BA_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr);
}
}
@@ -134,14 +137,14 @@ static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *ba
changed = ED_object_posemode_exit_ex(bmain, ob);
if (changed) {
ED_object_base_select(base, BA_DESELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, nullptr);
}
}
else {
changed = ED_object_posemode_enter_ex(bmain, ob);
if (changed) {
ED_object_base_select(base, BA_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, nullptr);
}
}
@@ -165,7 +168,7 @@ static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *ba
*/
static void do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *tvc, Base *base)
{
- const int active_mode = tvc->obact->mode;
+ const eObjectMode active_mode = (eObjectMode)tvc->obact->mode;
ED_undo_group_begin(C);
if (ED_object_mode_set(C, OB_MODE_OBJECT)) {
@@ -222,13 +225,13 @@ static void tree_element_viewlayer_activate(bContext *C, TreeElement *te)
return;
}
- ViewLayer *view_layer = te->directdata;
+ ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
if (BLI_findindex(&scene->view_layers, view_layer) != -1) {
WM_window_set_active_view_layer(win, view_layer);
- WM_event_add_notifier(C, NC_SCREEN | ND_LAYER, NULL);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYER, nullptr);
}
}
@@ -241,7 +244,7 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer,
{
Base *base;
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
+ for (base = reinterpret_cast<Base *>(FIRSTBASE(view_layer)); base; base = base->next) {
Object *ob = base->object;
if ((((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) &&
BKE_object_is_child_recursive(ob_parent, ob))) {
@@ -252,8 +255,7 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer,
static void do_outliner_bone_select_recursive(bArmature *arm, Bone *bone_parent, bool select)
{
- Bone *bone;
- for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) {
if (select && PBONE_SELECTABLE(arm, bone)) {
bone->flag |= BONE_SELECTED;
}
@@ -287,11 +289,11 @@ static void tree_element_object_activate(bContext *C,
bool recursive)
{
TreeStoreElem *tselem = TREESTORE(te);
- TreeStoreElem *parent_tselem = NULL;
- TreeElement *parent_te = NULL;
+ TreeStoreElem *parent_tselem = nullptr;
+ TreeElement *parent_te = nullptr;
Scene *sce;
Base *base;
- Object *ob = NULL;
+ Object *ob = nullptr;
/* if id is not object, we search back */
if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
@@ -309,7 +311,7 @@ static void tree_element_object_activate(bContext *C,
}
}
}
- if (ob == NULL) {
+ if (ob == nullptr) {
return;
}
@@ -323,9 +325,9 @@ static void tree_element_object_activate(bContext *C,
base = BKE_view_layer_base_find(view_layer, ob);
if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
- if (base != NULL) {
+ if (base != nullptr) {
Object *obact = OBACT(view_layer);
- const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
+ const eObjectMode object_mode = obact ? (eObjectMode)obact->mode : OB_MODE_OBJECT;
if (base && !BKE_object_is_mode_compat(base->object, object_mode)) {
if (object_mode == OB_MODE_OBJECT) {
struct Main *bmain = CTX_data_main(C);
@@ -333,7 +335,7 @@ static void tree_element_object_activate(bContext *C,
ED_object_mode_generic_exit(bmain, depsgraph, scene, base->object);
}
if (!BKE_object_is_mode_compat(base->object, object_mode)) {
- base = NULL;
+ base = nullptr;
}
}
}
@@ -356,7 +358,7 @@ static void tree_element_object_activate(bContext *C,
}
}
else {
- /* deleselect all */
+ /* De-select all. */
/* Only in object mode so we can switch the active object,
* keeping all objects in the current 'mode' selected, useful for multi-pose/edit mode.
@@ -390,8 +392,8 @@ static void tree_element_material_activate(bContext *C, ViewLayer *view_layer, T
{
/* we search for the object parent */
Object *ob = (Object *)outliner_search_back(te, ID_OB);
- /* Note : ob->matbits can be NULL when a local object points to a library mesh. */
- if (ob == NULL || ob != OBACT(view_layer) || ob->matbits == NULL) {
+ /* Note : ob->matbits can be nullptr when a local object points to a library mesh. */
+ if (ob == nullptr || ob != OBACT(view_layer) || ob->matbits == nullptr) {
return; /* just paranoia */
}
@@ -411,7 +413,7 @@ static void tree_element_material_activate(bContext *C, ViewLayer *view_layer, T
* for render views to update. See T42973.
* Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */
DEG_id_tag_update((ID *)ob, ID_RECALC_TRANSFORM);
- WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, nullptr);
}
static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement *te)
@@ -421,17 +423,17 @@ static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement
scene->camera = ob;
Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = reinterpret_cast<wmWindowManager *>(bmain->wm.first);
WM_windows_scene_data_sync(&wm->windows, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_SCENE | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_SCENE | NA_EDITED, nullptr);
}
static void tree_element_world_activate(bContext *C, Scene *scene, TreeElement *te)
{
- Scene *sce = NULL;
+ Scene *sce = nullptr;
TreeElement *tep = te->parent;
if (tep) {
@@ -461,7 +463,7 @@ static void tree_element_defgroup_activate(bContext *C, TreeElement *te, TreeSto
static void tree_element_gplayer_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem)
{
bGPdata *gpd = (bGPdata *)tselem->id;
- bGPDlayer *gpl = te->directdata;
+ bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata);
/* We can only have a single "active" layer at a time
* and there must always be an active layer... */
@@ -489,30 +491,29 @@ static void tree_element_posechannel_activate(bContext *C,
bool recursive)
{
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
- bPoseChannel *pchan = te->directdata;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
+ bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
if (!(pchan->bone->flag & BONE_HIDDEN_P)) {
if (set != OL_SETSEL_EXTEND) {
/* Single select forces all other bones to get unselected. */
uint objects_len = 0;
- Object **objects = BKE_object_pose_array_get_unique(view_layer, NULL, &objects_len);
+ Object **objects = BKE_object_pose_array_get_unique(view_layer, nullptr, &objects_len);
for (uint object_index = 0; object_index < objects_len; object_index++) {
Object *ob_iter = BKE_object_pose_armature_get(objects[object_index]);
/* Sanity checks. */
- if (ELEM(NULL, ob_iter, ob_iter->pose, ob_iter->data)) {
+ if (ELEM(nullptr, ob_iter, ob_iter->pose, ob_iter->data)) {
continue;
}
- bPoseChannel *pchannel;
- for (pchannel = ob_iter->pose->chanbase.first; pchannel; pchannel = pchannel->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchannel, &ob_iter->pose->chanbase) {
pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
}
if (ob != ob_iter) {
- DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(reinterpret_cast<ID *>(ob_iter->data), ID_RECALC_SELECT);
}
}
MEM_freeN(objects);
@@ -545,14 +546,14 @@ static void tree_element_bone_activate(bContext *C,
bool recursive)
{
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = te->directdata;
+ Bone *bone = reinterpret_cast<Bone *>(te->directdata);
if (!(bone->flag & BONE_HIDDEN_P)) {
Object *ob = OBACT(view_layer);
if (ob) {
if (set != OL_SETSEL_EXTEND) {
/* single select forces all other bones to get unselected */
- for (Bone *bone_iter = arm->bonebase.first; bone_iter != NULL;
+ for (Bone *bone_iter = reinterpret_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr;
bone_iter = bone_iter->next) {
bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
do_outliner_bone_select_recursive(arm, bone_iter, false);
@@ -594,13 +595,18 @@ static void tree_element_ebone_activate(bContext *C,
bool recursive)
{
bArmature *arm = (bArmature *)tselem->id;
- EditBone *ebone = te->directdata;
+ EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
if (set == OL_SETSEL_NORMAL) {
if (!(ebone->flag & BONE_HIDDEN_A)) {
uint bases_len = 0;
- Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
- view_layer, NULL, &bases_len);
+
+ ObjectsInModeParams ob_params{};
+ ob_params.object_mode = OB_MODE_EDIT;
+ ob_params.no_dup_data = true;
+
+ Base **bases = BKE_view_layer_array_from_bases_in_mode_params(
+ view_layer, nullptr, &bases_len, &ob_params);
ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
MEM_freeN(bases);
@@ -673,12 +679,13 @@ static void tree_element_sequence_activate(bContext *C,
TreeElement *te,
const eOLSetState set)
{
- Sequence *seq = (Sequence *)te->directdata;
+ const TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te);
+ Sequence *seq = &te_seq->getSequence();
Editing *ed = SEQ_editing_get(scene);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
if (set == OL_SETSEL_EXTEND) {
- SEQ_select_active_set(scene, NULL);
+ SEQ_select_active_set(scene, nullptr);
}
ED_sequencer_deselect_all(scene);
@@ -701,7 +708,7 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED
#if 0
select_single_seq(seq, 1);
#endif
- Sequence *p = ed->seqbasep->first;
+ Sequence *p = reinterpret_cast<Sequence *>(ed->seqbasep->first);
while (p) {
if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) {
p = p->next;
@@ -720,22 +727,23 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED
static void tree_element_master_collection_activate(const bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- LayerCollection *layer_collection = view_layer->layer_collections.first;
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(
+ view_layer->layer_collections.first);
BKE_layer_collection_activate(view_layer, layer_collection);
/* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
* when only the active collection changes. */
- WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, nullptr);
}
static void tree_element_layer_collection_activate(bContext *C, TreeElement *te)
{
Scene *scene = CTX_data_scene(C);
- LayerCollection *layer_collection = te->directdata;
+ LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(te->directdata);
ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection);
BKE_layer_collection_activate(view_layer, layer_collection);
/* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work
* when only the active collection changes. */
- WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, nullptr);
}
static void tree_element_text_activate(bContext *C, TreeElement *te)
@@ -854,7 +862,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer,
const TreeStoreElem *tselem)
{
const bArmature *arm = (const bArmature *)tselem->id;
- const Bone *bone = te->directdata;
+ const Bone *bone = reinterpret_cast<Bone *>(te->directdata);
const Object *ob = OBACT(view_layer);
if (ob && ob->data == arm) {
if (bone->flag & BONE_SELECTED) {
@@ -866,7 +874,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer,
static eOLDrawState tree_element_ebone_state_get(const TreeElement *te)
{
- const EditBone *ebone = te->directdata;
+ const EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
if (ebone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
}
@@ -894,7 +902,7 @@ static eOLDrawState tree_element_pose_state_get(const ViewLayer *view_layer,
const Object *ob = (const Object *)tselem->id;
/* This will just lookup in a cache, it will not change the arguments. */
const Base *base = BKE_view_layer_base_find((ViewLayer *)view_layer, (Object *)ob);
- if (base == NULL) {
+ if (base == nullptr) {
/* Armature not instantiated in current scene (e.g. inside an appended group). */
return OL_DRAWSEL_NONE;
}
@@ -910,7 +918,7 @@ static eOLDrawState tree_element_posechannel_state_get(const Object *ob_pose,
const TreeStoreElem *tselem)
{
const Object *ob = (const Object *)tselem->id;
- const bPoseChannel *pchan = te->directdata;
+ const bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
if (ob == ob_pose && ob->pose) {
if (pchan->bone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
@@ -926,7 +934,7 @@ static eOLDrawState tree_element_viewlayer_state_get(const bContext *C, const Tr
return OL_DRAWSEL_NONE;
}
- const ViewLayer *view_layer = te->directdata;
+ const ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
if (CTX_data_view_layer(C) == view_layer) {
return OL_DRAWSEL_NORMAL;
@@ -950,7 +958,8 @@ static eOLDrawState tree_element_posegroup_state_get(const ViewLayer *view_layer
static eOLDrawState tree_element_sequence_state_get(const Scene *scene, const TreeElement *te)
{
- const Sequence *seq = (const Sequence *)te->directdata;
+ const TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te);
+ const Sequence *seq = &te_seq->getSequence();
const Editing *ed = scene->ed;
if (ed && ed->act_seq == seq && seq->flag & SELECT) {
@@ -961,7 +970,9 @@ static eOLDrawState tree_element_sequence_state_get(const Scene *scene, const Tr
static eOLDrawState tree_element_sequence_dup_state_get(const TreeElement *te)
{
- const Sequence *seq = (const Sequence *)te->directdata;
+ const TreeElementSequenceStripDuplicate *te_dup =
+ tree_element_cast<TreeElementSequenceStripDuplicate>(te);
+ const Sequence *seq = &te_dup->getSequence();
if (seq->flag & SELECT) {
return OL_DRAWSEL_NORMAL;
}
@@ -1002,8 +1013,8 @@ static eOLDrawState tree_element_active_material_get(const ViewLayer *view_layer
{
/* we search for the object parent */
const Object *ob = (const Object *)outliner_search_back((TreeElement *)te, ID_OB);
- /* Note : ob->matbits can be NULL when a local object points to a library mesh. */
- if (ob == NULL || ob != OBACT(view_layer) || ob->matbits == NULL) {
+ /* Note : ob->matbits can be nullptr when a local object points to a library mesh. */
+ if (ob == nullptr || ob != OBACT(view_layer) || ob->matbits == nullptr) {
return OL_DRAWSEL_NONE; /* just paranoia */
}
@@ -1042,7 +1053,7 @@ static eOLDrawState tree_element_active_scene_get(const TreeViewContext *tvc,
static eOLDrawState tree_element_active_world_get(const Scene *scene, const TreeElement *te)
{
const TreeElement *tep = te->parent;
- if (tep == NULL) {
+ if (tep == nullptr) {
return OL_DRAWSEL_NORMAL;
}
@@ -1138,7 +1149,7 @@ bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te
te = te->parent;
}
- return NULL;
+ return nullptr;
}
static void outliner_sync_to_properties_editors(const bContext *C,
@@ -1161,7 +1172,7 @@ static void outliner_sync_to_properties_editors(const bContext *C,
static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreElem *tselem)
{
- PointerRNA ptr = {0};
+ PointerRNA ptr = {nullptr};
int context = 0;
/* ID Types */
@@ -1209,7 +1220,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
break;
case TSE_CONSTRAINT_BASE:
case TSE_CONSTRAINT: {
- TreeElement *bone_te = NULL;
+ TreeElement *bone_te = nullptr;
bPoseChannel *pchan = outliner_find_parent_bone(te, &bone_te);
if (pchan) {
@@ -1223,7 +1234,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
/* Expand the selected constraint in the properties editor. */
if (tselem->type != TSE_CONSTRAINT_BASE) {
- BKE_constraint_panel_expand(te->directdata);
+ BKE_constraint_panel_expand(reinterpret_cast<bConstraint *>(te->directdata));
}
break;
}
@@ -1236,7 +1247,8 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
Object *ob = (Object *)tselem->id;
if (ob->type == OB_GPENCIL) {
- BKE_gpencil_modifier_panel_expand(te->directdata);
+ BKE_gpencil_modifier_panel_expand(
+ reinterpret_cast<GpencilModifierData *>(te->directdata));
}
else {
ModifierData *md = (ModifierData *)te->directdata;
@@ -1269,12 +1281,12 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
context = BCONTEXT_SHADERFX;
if (tselem->type != TSE_GPENCIL_EFFECT_BASE) {
- BKE_shaderfx_panel_expand(te->directdata);
+ BKE_shaderfx_panel_expand(reinterpret_cast<ShaderFxData *>(te->directdata));
}
break;
case TSE_BONE: {
bArmature *arm = (bArmature *)tselem->id;
- Bone *bone = te->directdata;
+ Bone *bone = reinterpret_cast<Bone *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
context = BCONTEXT_BONE;
@@ -1282,7 +1294,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_EBONE: {
bArmature *arm = (bArmature *)tselem->id;
- EditBone *ebone = te->directdata;
+ EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &ptr);
context = BCONTEXT_BONE;
@@ -1290,8 +1302,8 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_POSE_CHANNEL: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
- bPoseChannel *pchan = te->directdata;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
+ bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata);
RNA_pointer_create(&arm->id, &RNA_PoseBone, pchan, &ptr);
context = BCONTEXT_BONE;
@@ -1299,7 +1311,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_POSE_BASE: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr);
context = BCONTEXT_DATA;
@@ -1307,7 +1319,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
}
case TSE_R_LAYER_BASE:
case TSE_R_LAYER: {
- ViewLayer *view_layer = te->directdata;
+ ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata);
RNA_pointer_create(tselem->id, &RNA_ViewLayer, view_layer, &ptr);
context = BCONTEXT_VIEW_LAYER;
@@ -1316,7 +1328,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE
case TSE_POSEGRP_BASE:
case TSE_POSEGRP: {
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr);
context = BCONTEXT_DATA;
@@ -1392,7 +1404,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
Collection *gr = (Collection *)tselem->id;
if (extend) {
- int sel = BA_SELECT;
+ eObjectSelect_Mode sel = BA_SELECT;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
if (base && (base->flag & BASE_SELECTED)) {
@@ -1416,7 +1428,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
/* Object may not be in this scene */
- if (base != NULL) {
+ if (base != nullptr) {
if ((base->flag & BASE_SELECTED) == 0) {
ED_object_base_select(base, BA_SELECT);
}
@@ -1730,7 +1742,7 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
ARegion *region = CTX_wm_region(C);
rctf rectf;
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
@@ -1816,7 +1828,7 @@ static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *space_o
{
while (te->subtree.last) {
if (TSELEM_OPEN(TREESTORE(te), space_outliner)) {
- te = te->subtree.last;
+ te = reinterpret_cast<TreeElement *>(te->subtree.last);
}
else {
break;
@@ -1860,7 +1872,7 @@ static TreeElement *outliner_find_next_element(SpaceOutliner *space_outliner, Tr
TreeStoreElem *tselem = TREESTORE(te);
if (TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) {
- te = te->subtree.first;
+ te = reinterpret_cast<TreeElement *>(te->subtree.first);
}
else if (te->next) {
te = te->next;
@@ -1897,7 +1909,7 @@ static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner,
/* Only walk down a level if the element is open and not toggling expand */
if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
- te = te->subtree.first;
+ te = reinterpret_cast<TreeElement *>(te->subtree.first);
}
else {
outliner_item_openclose(space_outliner, te, true, toggle_all);
@@ -1948,7 +1960,7 @@ static TreeElement *find_walk_select_start_element(SpaceOutliner *space_outliner
/* If no active element exists, use the first element in the tree */
if (!active_te) {
- active_te = space_outliner->tree.first;
+ active_te = reinterpret_cast<TreeElement *>(space_outliner->tree.first);
*changed = true;
}
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.cc
index d95a0dde858..74416024b03 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <stdio.h>
+#include <cstdio>
#include "DNA_armature_types.h"
#include "DNA_layer_types.h"
@@ -50,7 +50,7 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
void ED_outliner_select_sync_from_object_tag(bContext *C)
{
@@ -93,7 +93,8 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C)
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = reinterpret_cast<bScreen *>(bmain->screens.first); screen;
+ screen = reinterpret_cast<bScreen *>(screen->id.next)) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_OUTLINER) {
@@ -114,12 +115,12 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C)
* outliner display mode also needs to be considered. This stores the types of data
* to sync to increase code clarity.
*/
-typedef struct SyncSelectTypes {
+struct SyncSelectTypes {
bool object;
bool edit_bone;
bool pose_bone;
bool sequence;
-} SyncSelectTypes;
+};
/**
* Set which types of data to sync when syncing selection from the outliner based on object
@@ -173,11 +174,11 @@ static bool outliner_sync_select_to_outliner_set_types(const bContext *C,
* Stores items selected from a sync from the outliner. Prevents syncing the selection
* state of the last instance of an object linked in multiple collections.
*/
-typedef struct SelectedItems {
+struct SelectedItems {
GSet *objects;
GSet *edit_bones;
GSet *pose_bones;
-} SelectedItems;
+};
static void selected_items_init(SelectedItems *selected_items)
{
@@ -188,9 +189,9 @@ static void selected_items_init(SelectedItems *selected_items)
static void selected_items_free(SelectedItems *selected_items)
{
- BLI_gset_free(selected_items->objects, NULL);
- BLI_gset_free(selected_items->edit_bones, NULL);
- BLI_gset_free(selected_items->pose_bones, NULL);
+ BLI_gset_free(selected_items->objects, nullptr);
+ BLI_gset_free(selected_items->edit_bones, nullptr);
+ BLI_gset_free(selected_items->pose_bones, nullptr);
}
/* Check if an instance of this object been selected by the sync */
@@ -274,7 +275,7 @@ static void outliner_select_sync_to_pose_bone(TreeElement *te,
GSet *selected_pbones)
{
Object *ob = (Object *)tselem->id;
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
short bone_flag = pchan->bone->flag;
@@ -403,7 +404,7 @@ static void outliner_select_sync_from_object(ViewLayer *view_layer,
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
BKE_view_layer_base_find(view_layer, ob);
- const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
+ const bool is_selected = (base != nullptr) && ((base->flag & BASE_SELECTED) != 0);
if (base && (ob == obact)) {
tselem->flag |= TSE_ACTIVE;
@@ -486,12 +487,12 @@ static void outliner_select_sync_from_sequence(Sequence *sequence_active, TreeSt
* Contains active object, bones, and sequence for syncing to prevent getting active data
* repeatedly throughout syncing to the outliner.
*/
-typedef struct SyncSelectActiveData {
+struct SyncSelectActiveData {
Object *object;
EditBone *edit_bone;
bPoseChannel *pose_channel;
Sequence *sequence;
-} SyncSelectActiveData;
+};
/** Sync select and active flags from active view layer, bones, and sequences to the outliner. */
static void outliner_sync_selection_to_outliner(ViewLayer *view_layer,
@@ -561,7 +562,7 @@ void outliner_sync_selection(const bContext *C, SpaceOutliner *space_outliner)
outliner_sync_selection_to_outliner(
view_layer, space_outliner, &space_outliner->tree, &active_data, &sync_types);
- /* Keep any unsynced data in the dirty flag */
+ /* Keep any un-synced data in the dirty flag. */
if (sync_types.object) {
space_outliner->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_OBJECT;
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.cc
index 01f0feec771..fa31025b550 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -95,10 +95,14 @@
#include "SEQ_relations.h"
#include "SEQ_sequencer.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
+#include "tree/tree_element_rna.hh"
+#include "tree/tree_element_seq.hh"
static CLG_LogRef LOG = {"ed.outliner.tools"};
+using namespace blender::ed::outliner;
+
/* -------------------------------------------------------------------- */
/** \name ID/Library/Data Set/Un-link Utilities
* \{ */
@@ -208,7 +212,7 @@ static bool outliner_operation_tree_element_poll(bContext *C)
}
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
TreeElement *te = get_target_element(space_outliner);
- if (te == NULL) {
+ if (te == nullptr) {
return false;
}
@@ -223,8 +227,8 @@ static void unlink_action_fn(bContext *C,
TreeStoreElem *UNUSED(tselem),
void *UNUSED(user_data))
{
- /* just set action to NULL */
- BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL);
+ /* just set action to nullptr */
+ BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, nullptr);
}
static void unlink_material_fn(bContext *UNUSED(C),
@@ -235,7 +239,7 @@ static void unlink_material_fn(bContext *UNUSED(C),
TreeStoreElem *UNUSED(tselem),
void *UNUSED(user_data))
{
- Material **matar = NULL;
+ Material **matar = nullptr;
int a, totcol = 0;
if (GS(tsep->id->name) == ID_OB) {
@@ -277,11 +281,11 @@ static void unlink_material_fn(bContext *UNUSED(C),
BLI_assert(0);
}
- if (LIKELY(matar != NULL)) {
+ if (LIKELY(matar != nullptr)) {
for (a = 0; a < totcol; a++) {
if (a == te->index && matar[a]) {
id_us_min(&matar[a]->id);
- matar[a] = NULL;
+ matar[a] = nullptr;
}
}
}
@@ -295,7 +299,7 @@ static void unlink_texture_fn(bContext *UNUSED(C),
TreeStoreElem *UNUSED(tselem),
void *UNUSED(user_data))
{
- MTex **mtex = NULL;
+ MTex **mtex = nullptr;
int a;
if (GS(tsep->id->name) == ID_LS) {
@@ -310,7 +314,7 @@ static void unlink_texture_fn(bContext *UNUSED(C),
if (a == te->index && mtex[a]) {
if (mtex[a]->tex) {
id_us_min(&mtex[a]->tex->id);
- mtex[a]->tex = NULL;
+ mtex[a]->tex = nullptr;
}
}
}
@@ -330,7 +334,7 @@ static void unlink_collection_fn(bContext *C,
if (tsep) {
if (GS(tsep->id->name) == ID_OB) {
Object *ob = (Object *)tsep->id;
- ob->instance_collection = NULL;
+ ob->instance_collection = nullptr;
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
DEG_relations_tag_update(bmain);
}
@@ -369,7 +373,7 @@ static void unlink_object_fn(bContext *C,
TreeElement *te_parent = te->parent;
while (tsep && GS(tsep->id->name) == ID_OB) {
te_parent = te_parent->parent;
- tsep = te_parent ? TREESTORE(te_parent) : NULL;
+ tsep = te_parent ? TREESTORE(te_parent) : nullptr;
}
}
@@ -404,7 +408,7 @@ static void unlink_world_fn(bContext *UNUSED(C),
/* need to use parent scene not just scene, otherwise may end up getting wrong one */
id_us_min(&wo->id);
- parscene->world = NULL;
+ parscene->world = nullptr;
}
static void outliner_do_libdata_operation(bContext *C,
@@ -420,7 +424,7 @@ static void outliner_do_libdata_operation(bContext *C,
if (tselem->flag & TSE_SELECTED) {
if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
tselem->type == TSE_LAYER_COLLECTION) {
- TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
+ TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
operation_fn(C, reports, scene, te, tsep, tselem, user_data);
}
}
@@ -437,13 +441,13 @@ static void outliner_do_libdata_operation(bContext *C,
/** \name Scene Menu Operator
* \{ */
-typedef enum eOutliner_PropSceneOps {
+enum eOutliner_PropSceneOps {
OL_SCENE_OP_DELETE = 1,
-} eOutliner_PropSceneOps;
+};
static const EnumPropertyItem prop_scene_op_types[] = {
{OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static bool outliner_do_scene_operation(
@@ -488,7 +492,7 @@ static bool scene_fn(bContext *C,
static int outliner_scene_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- const eOutliner_PropSceneOps event = RNA_enum_get(op->ptr, "type");
+ const eOutliner_PropSceneOps event = (eOutliner_PropSceneOps)RNA_enum_get(op->ptr, "type");
if (outliner_do_scene_operation(C, event, &space_outliner->tree, scene_fn) == false) {
return OPERATOR_CANCELLED;
@@ -534,10 +538,10 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
* the merged select popup menu. The sub-tree of the parent is searched and
* the child is needed to only show elements of the same type in the popup.
*/
-typedef struct MergedSearchData {
+struct MergedSearchData {
TreeElement *parent_element;
TreeElement *select_element;
-} MergedSearchData;
+};
static void merged_element_search_fn_recursive(
const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items)
@@ -615,13 +619,13 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d
but = uiDefSearchBut(
block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, "");
UI_but_func_search_set(but,
- NULL,
+ nullptr,
merged_element_search_update_fn,
data,
false,
- NULL,
+ nullptr,
merged_element_search_exec_fn,
- NULL);
+ nullptr);
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
/* Fake button to hold space for search items */
@@ -633,15 +637,16 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d
10 - UI_searchbox_size_y(),
menu_width,
UI_searchbox_size_y(),
- NULL,
+ nullptr,
0,
0,
0,
0,
- NULL);
+ nullptr);
/* Center the menu on the cursor */
- UI_block_bounds_set_popup(block, 6, (const int[2]){-(menu_width / 2), 0});
+ const int offset[2] = {-(menu_width / 2), 0};
+ UI_block_bounds_set_popup(block, 6, offset);
return block;
}
@@ -650,7 +655,7 @@ void merged_element_search_menu_invoke(bContext *C,
TreeElement *parent_te,
TreeElement *activate_te)
{
- MergedSearchData *select_data = MEM_callocN(sizeof(MergedSearchData), "merge_search_data");
+ MergedSearchData *select_data = MEM_cnew<MergedSearchData>("merge_search_data");
select_data->parent_element = parent_te;
select_data->select_element = activate_te;
@@ -773,7 +778,7 @@ static void object_proxy_to_override_convert_fn(bContext *C,
Object *ob_proxy = (Object *)id_proxy;
Scene *scene = CTX_data_scene(C);
- if (ob_proxy->proxy == NULL) {
+ if (ob_proxy->proxy == nullptr) {
return;
}
@@ -788,17 +793,17 @@ static void object_proxy_to_override_convert_fn(bContext *C,
}
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
-typedef struct OutlinerLibOverrideData {
+struct OutlinerLibOverrideData {
bool do_hierarchy;
/**
* For resync operation, force keeping newly created override IDs (or original linked IDs)
* instead of re-applying relevant existing ID pointer property override operations. Helps
* solving broken overrides while not losing *all* of your overrides. */
bool do_resync_hierarchy_enforce;
-} OutlinerLibOverrideData;
+};
static void id_override_library_create_fn(bContext *C,
ReportList *reports,
@@ -810,14 +815,14 @@ static void id_override_library_create_fn(bContext *C,
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
- OutlinerLibOverrideData *data = user_data;
+ OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy = data->do_hierarchy;
bool success = false;
- ID *id_reference = NULL;
+ ID *id_reference = nullptr;
bool is_override_instancing_object = false;
- if (tsep != NULL && tsep->type == TSE_SOME_ID && tsep->id != NULL &&
- GS(tsep->id->name) == ID_OB) {
+ if (tsep != nullptr && tsep->type == TSE_SOME_ID && tsep->id != nullptr &&
+ GS(tsep->id->name) == ID_OB && !ID_IS_OVERRIDE_LIBRARY(tsep->id)) {
Object *ob = (Object *)tsep->id;
if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root) {
BLI_assert(GS(id_root->name) == ID_GR);
@@ -847,7 +852,7 @@ static void id_override_library_create_fn(bContext *C,
if (do_hierarchy) {
/* Tag all linked parents in tree hierarchy to be also overridden. */
- while ((te = te->parent) != NULL) {
+ while ((te = te->parent) != nullptr) {
if (!TSE_IS_REAL_ID(te->store_elem)) {
continue;
}
@@ -869,10 +874,10 @@ static void id_override_library_create_fn(bContext *C,
}
success = BKE_lib_override_library_create(
- bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, NULL);
+ bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, nullptr);
}
else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) {
- success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != NULL;
+ success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != nullptr;
/* Cleanup. */
BKE_main_id_newptr_and_tag_clear(bmain);
@@ -903,7 +908,7 @@ static void id_override_library_reset_fn(bContext *C,
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
- OutlinerLibOverrideData *data = user_data;
+ OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy = data->do_hierarchy;
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
@@ -916,8 +921,8 @@ static void id_override_library_reset_fn(bContext *C,
BKE_lib_override_library_id_reset(bmain, id_root);
}
- WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, NULL);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, nullptr);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr);
}
else {
CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name);
@@ -934,7 +939,7 @@ static void id_override_library_resync_fn(bContext *C,
{
BLI_assert(TSE_IS_REAL_ID(tselem));
ID *id_root = tselem->id;
- OutlinerLibOverrideData *data = user_data;
+ OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data);
const bool do_hierarchy_enforce = data->do_resync_hierarchy_enforce;
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
@@ -943,7 +948,7 @@ static void id_override_library_resync_fn(bContext *C,
id_root->tag |= LIB_TAG_DOIT;
/* Tag all linked parents in tree hierarchy to be also overridden. */
- while ((te = te->parent) != NULL) {
+ while ((te = te->parent) != nullptr) {
if (!TSE_IS_REAL_ID(te->store_elem)) {
continue;
}
@@ -953,16 +958,12 @@ static void id_override_library_resync_fn(bContext *C,
te->store_elem->id->tag |= LIB_TAG_DOIT;
}
- BKE_lib_override_library_resync(bmain,
- scene,
- CTX_data_view_layer(C),
- id_root,
- NULL,
- do_hierarchy_enforce,
- true,
- &(struct BlendFileReadReport){.reports = reports});
+ BlendFileReadReport report{};
+ report.reports = reports;
+ BKE_lib_override_library_resync(
+ bmain, scene, CTX_data_view_layer(C), id_root, nullptr, do_hierarchy_enforce, &report);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
else {
CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name);
@@ -986,7 +987,7 @@ static void id_override_library_delete_fn(bContext *C,
id_root->tag |= LIB_TAG_DOIT;
/* Tag all linked parents in tree hierarchy to be also overridden. */
- while ((te = te->parent) != NULL) {
+ while ((te = te->parent) != nullptr) {
if (!TSE_IS_REAL_ID(te->store_elem)) {
continue;
}
@@ -998,7 +999,7 @@ static void id_override_library_delete_fn(bContext *C,
BKE_lib_override_library_delete(bmain, id_root);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
else {
CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name);
@@ -1062,7 +1063,7 @@ static void singleuser_action_fn(bContext *C,
if (id) {
IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id;
- PointerRNA ptr = {NULL};
+ PointerRNA ptr = {nullptr};
PropertyRNA *prop;
RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt, &ptr);
@@ -1085,7 +1086,7 @@ static void singleuser_world_fn(bContext *C,
/* need to use parent scene not just scene, otherwise may end up getting wrong one */
if (id) {
Scene *parscene = (Scene *)tsep->id;
- PointerRNA ptr = {NULL};
+ PointerRNA ptr = {nullptr};
PropertyRNA *prop;
RNA_id_pointer_create(&parscene->id, &ptr);
@@ -1115,10 +1116,10 @@ void outliner_do_object_operation_ex(bContext *C,
WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), scene_owner);
}
/* Important to use 'scene_owner' not scene_act else deleting objects can crash.
- * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
+ * only use 'scene_act' when 'scene_owner' is nullptr, which can happen when the
* outliner isn't showing scenes: Visible Layer draw mode for eg. */
operation_fn(
- C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, user_data);
+ C, reports, scene_owner ? scene_owner : scene_act, te, nullptr, tselem, user_data);
select_handled = true;
}
}
@@ -1130,7 +1131,7 @@ void outliner_do_object_operation_ex(bContext *C,
space_outliner,
&te->subtree,
operation_fn,
- NULL,
+ nullptr,
recurse_selected);
}
}
@@ -1145,7 +1146,7 @@ void outliner_do_object_operation(bContext *C,
outliner_operation_fn operation_fn)
{
outliner_do_object_operation_ex(
- C, reports, scene_act, space_outliner, lb, operation_fn, NULL, true);
+ C, reports, scene_act, space_outliner, lb, operation_fn, nullptr, true);
}
/** \} */
@@ -1168,8 +1169,8 @@ static void unlinkact_animdata_fn(int UNUSED(event),
TreeStoreElem *tselem,
void *UNUSED(arg))
{
- /* just set action to NULL */
- BKE_animdata_set_action(NULL, tselem->id, NULL);
+ /* just set action to nullptr */
+ BKE_animdata_set_action(nullptr, tselem->id, nullptr);
DEG_id_tag_update(tselem->id, ID_RECALC_ANIMATION);
}
@@ -1209,25 +1210,25 @@ static void refreshdrivers_animdata_fn(int UNUSED(event),
/** \name Object Operation Utilities
* \{ */
-typedef enum eOutliner_PropDataOps {
+enum eOutliner_PropDataOps {
OL_DOP_SELECT = 1,
OL_DOP_DESELECT,
OL_DOP_HIDE,
OL_DOP_UNHIDE,
OL_DOP_SELECT_LINKED,
-} eOutliner_PropDataOps;
+};
-typedef enum eOutliner_PropConstraintOps {
+enum eOutliner_PropConstraintOps {
OL_CONSTRAINTOP_ENABLE = 1,
OL_CONSTRAINTOP_DISABLE,
OL_CONSTRAINTOP_DELETE,
-} eOutliner_PropConstraintOps;
+};
-typedef enum eOutliner_PropModifierOps {
+enum eOutliner_PropModifierOps {
OL_MODIFIER_OP_TOGVIS = 1,
OL_MODIFIER_OP_TOGREN,
OL_MODIFIER_OP_DELETE,
-} eOutliner_PropModifierOps;
+};
static void pchan_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
{
@@ -1288,7 +1289,8 @@ static void ebone_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem),
static void sequence_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *scene_ptr)
{
- Sequence *seq = (Sequence *)te->directdata;
+ TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te);
+ Sequence *seq = &te_seq->getSequence();
Scene *scene = (Scene *)scene_ptr;
Editing *ed = SEQ_editing_get(scene);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
@@ -1339,10 +1341,16 @@ static void data_select_linked_fn(int event,
TreeStoreElem *UNUSED(tselem),
void *C_v)
{
+ const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te);
+ if (!te_rna_struct) {
+ return;
+ }
+
if (event == OL_DOP_SELECT_LINKED) {
- if (RNA_struct_is_ID(te->rnaptr.type)) {
+ const PointerRNA &ptr = te_rna_struct->getPointerRNA();
+ if (RNA_struct_is_ID(ptr.type)) {
bContext *C = (bContext *)C_v;
- ID *id = te->rnaptr.data;
+ ID *id = reinterpret_cast<ID *>(ptr.data);
ED_object_select_linked_by_id(C, id);
}
@@ -1351,7 +1359,7 @@ static void data_select_linked_fn(int event,
static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
{
- bContext *C = C_v;
+ bContext *C = reinterpret_cast<bContext *>(C_v);
Main *bmain = CTX_data_main(C);
bConstraint *constraint = (bConstraint *)te->directdata;
Object *ob = (Object *)outliner_search_back(te, ID_OB);
@@ -1367,7 +1375,7 @@ static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
}
else if (event == OL_CONSTRAINTOP_DELETE) {
- ListBase *lb = NULL;
+ ListBase *lb = nullptr;
if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) {
lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints;
@@ -1378,7 +1386,7 @@ static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
if (BKE_constraint_remove_ex(lb, ob, constraint, true)) {
/* there's no active constraint now, so make sure this is the case */
- BKE_constraints_active_set(&ob->constraints, NULL);
+ BKE_constraints_active_set(&ob->constraints, nullptr);
/* needed to set the flags on posebones correctly */
ED_object_constraint_update(bmain, ob);
@@ -1408,7 +1416,7 @@ static void modifier_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
else if (event == OL_MODIFIER_OP_DELETE) {
- ED_object_modifier_remove(NULL, bmain, scene, ob, md);
+ ED_object_modifier_remove(nullptr, bmain, scene, ob, md);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob);
te->store_elem->flag &= ~TSE_SELECTED;
}
@@ -1442,11 +1450,12 @@ static Base *outliner_batch_delete_hierarchy(
Object *object, *parent;
if (!base) {
- return NULL;
+ return nullptr;
}
object = base->object;
- for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) {
+ for (child_base = reinterpret_cast<Base *>(view_layer->object_bases.first); child_base;
+ child_base = base_next) {
base_next = child_base->next;
for (parent = child_base->object->parent; parent && (parent != object);
parent = parent->parent) {
@@ -1540,7 +1549,7 @@ static const EnumPropertyItem prop_object_op_types[] = {
0,
"Convert Proxy to Override",
"Convert a Proxy object to a full library override, including all its dependencies"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_object_operation_exec(bContext *C, wmOperator *op)
@@ -1550,11 +1559,11 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
wmWindow *win = CTX_wm_window(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int event;
- const char *str = NULL;
+ const char *str = nullptr;
bool selection_changed = false;
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -1579,7 +1588,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
object_select_hierarchy_fn,
- NULL,
+ nullptr,
false);
if (scene != sce) {
WM_window_set_active_scene(bmain, C, win, sce);
@@ -1595,7 +1604,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
}
else if (event == OL_OP_REMAP) {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
}
@@ -1624,7 +1633,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
ED_outliner_select_sync_from_object_tag(C);
}
- if (str != NULL) {
+ if (str != nullptr) {
ED_undo_push(C, str);
}
@@ -1653,13 +1662,13 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
/** \name Delete Object/Collection Operator
* \{ */
-typedef void (*OutlinerDeleteFunc)(bContext *C, ReportList *reports, Scene *scene, Object *ob);
+using OutlinerDeleteFn = void (*)(bContext *C, ReportList *reports, Scene *scene, Object *ob);
static void outliner_do_object_delete(bContext *C,
ReportList *reports,
Scene *scene,
GSet *objects_to_delete,
- OutlinerDeleteFunc delete_fn)
+ OutlinerDeleteFn delete_fn)
{
GSetIterator objects_to_delete_iter;
GSET_ITER (objects_to_delete_iter, objects_to_delete) {
@@ -1678,7 +1687,8 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void
return TRAVERSE_CONTINUE;
}
- if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) {
+ if ((tselem->type != TSE_SOME_ID) || (tselem->id == nullptr) ||
+ (GS(tselem->id->name) != ID_OB)) {
return TRAVERSE_SKIP_CHILDS;
}
@@ -1687,6 +1697,8 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void
return TRAVERSE_CONTINUE;
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static int outliner_delete_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -1720,7 +1732,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op)
outliner_do_object_delete(C, op->reports, scene, objects_to_delete, outliner_object_delete_fn);
}
- BLI_gset_free(objects_to_delete, NULL);
+ BLI_gset_free(objects_to_delete, nullptr);
outliner_collection_delete(C, bmain, scene, op->reports, delete_hierarchy);
@@ -1746,6 +1758,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+}
void OUTLINER_OT_delete(wmOperatorType *ot)
{
@@ -1773,7 +1786,7 @@ void OUTLINER_OT_delete(wmOperatorType *ot)
/** \name ID-Data Menu Operator
* \{ */
-typedef enum eOutlinerIdOpTypes {
+enum eOutlinerIdOpTypes {
OUTLINER_IDOP_INVALID = 0,
OUTLINER_IDOP_UNLINK,
@@ -1798,7 +1811,7 @@ typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_RENAME,
OUTLINER_IDOP_SELECT_LINKED,
-} eOutlinerIdOpTypes;
+};
/* TODO: implement support for changing the ID-block used. */
static const EnumPropertyItem prop_id_op_types[] = {
@@ -1811,7 +1824,7 @@ static const EnumPropertyItem prop_id_op_types[] = {
0,
"Remap Users",
"Make all users of selected data-blocks to use instead current (clicked) one"},
- {0, "", 0, NULL, NULL},
+ {0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
"OVERRIDE_LIBRARY_CREATE",
0,
@@ -1856,10 +1869,10 @@ static const EnumPropertyItem prop_id_op_types[] = {
"Delete Library Override Hierarchy",
"Delete this local override (including its hierarchy of override dependencies) and relink "
"its usages to the linked data-blocks"},
- {0, "", 0, NULL, NULL},
+ {0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""},
{OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""},
- {0, "", 0, NULL, NULL},
+ {0, "", 0, nullptr, nullptr},
{OUTLINER_IDOP_FAKE_ADD,
"ADD_FAKE",
0,
@@ -1869,7 +1882,7 @@ static const EnumPropertyItem prop_id_op_types[] = {
{OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
{OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""},
{OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static bool outliner_id_operation_item_poll(bContext *C,
@@ -1903,7 +1916,7 @@ static bool outliner_id_operation_item_poll(bContext *C,
if (GS(tselem->id->name) == ID_OB) {
Object *ob = (Object *)tselem->id;
- if ((ob != NULL) && (ob->proxy != NULL)) {
+ if ((ob != nullptr) && (ob->proxy != nullptr)) {
return true;
}
}
@@ -1935,13 +1948,13 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
PropertyRNA *prop,
bool *r_free)
{
- EnumPropertyItem *items = NULL;
+ EnumPropertyItem *items = nullptr;
int totitem = 0;
- if ((C == NULL) || (ED_operator_outliner_active(C) == false)) {
+ if ((C == nullptr) || (ED_operator_outliner_active(C) == false)) {
return prop_id_op_types;
}
- for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != NULL; it++) {
+ for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != nullptr; it++) {
if (!outliner_id_operation_item_poll(C, ptr, prop, it->value)) {
continue;
}
@@ -1961,22 +1974,27 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
- eOutlinerIdOpTypes event = RNA_enum_get(op->ptr, "type");
+ eOutlinerIdOpTypes event = (eOutlinerIdOpTypes)RNA_enum_get(op->ptr, "type");
switch (event) {
case OUTLINER_IDOP_UNLINK: {
/* unlink datablock from its parent */
if (objectlevel) {
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, unlink_object_fn, NULL);
-
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ unlink_object_fn,
+ nullptr);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr);
ED_undo_push(C, "Unlink Object");
break;
}
@@ -1989,9 +2007,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_action_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Unlink action");
break;
case ID_MA:
@@ -2001,9 +2019,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_material_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, nullptr);
ED_undo_push(C, "Unlink material");
break;
case ID_TE:
@@ -2013,16 +2031,21 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_texture_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, nullptr);
ED_undo_push(C, "Unlink texture");
break;
case ID_WO:
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, unlink_world_fn, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ unlink_world_fn,
+ nullptr);
- WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr);
ED_undo_push(C, "Unlink world");
break;
case ID_GR:
@@ -2032,9 +2055,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
unlink_collection_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr);
ED_undo_push(C, "Unlink Collection");
break;
default:
@@ -2046,29 +2069,32 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_LOCAL: {
/* make local */
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_local_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_local_fn, nullptr);
ED_undo_push(C, "Localized Data");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE: {
+ OutlinerLibOverrideData override_data{};
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_create_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = false});
+ &override_data);
ED_undo_push(C, "Overridden Data");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_create_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Overridden Data Hierarchy");
break;
}
@@ -2083,58 +2109,67 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: {
+ OutlinerLibOverrideData override_data{};
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_reset_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = false});
+ &override_data);
ED_undo_push(C, "Reset Overridden Data");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_reset_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Reset Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_resync_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: {
- outliner_do_libdata_operation(
- C,
- op->reports,
- scene,
- space_outliner,
- &space_outliner->tree,
- id_override_library_resync_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true, .do_resync_hierarchy_enforce = true});
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
+ override_data.do_resync_hierarchy_enforce = true;
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ id_override_library_resync_fn,
+ &override_data);
ED_undo_push(C, "Resync Overridden Data Hierarchy");
break;
}
case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: {
+ OutlinerLibOverrideData override_data{};
+ override_data.do_hierarchy = true;
outliner_do_libdata_operation(C,
op->reports,
scene,
space_outliner,
&space_outliner->tree,
id_override_library_delete_fn,
- &(OutlinerLibOverrideData){.do_hierarchy = true});
+ &override_data);
ED_undo_push(C, "Delete Overridden Data Hierarchy");
break;
}
@@ -2148,9 +2183,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
singleuser_action_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Single-User Action");
break;
@@ -2161,9 +2196,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
singleuser_world_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr);
ED_undo_push(C, "Single-User World");
break;
@@ -2176,7 +2211,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_DELETE: {
if (idlevel > 0) {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, nullptr);
ED_undo_push(C, "Delete");
}
break;
@@ -2184,7 +2219,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_REMAP: {
if (idlevel > 0) {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
}
@@ -2192,14 +2227,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_COPY: {
wm->op_undo_depth++;
- WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, NULL);
+ WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, nullptr);
wm->op_undo_depth--;
/* No need for undo, this operation does not change anything... */
break;
}
case OUTLINER_IDOP_PASTE: {
wm->op_undo_depth++;
- WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, NULL);
+ WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, nullptr);
wm->op_undo_depth--;
ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Paste");
@@ -2207,10 +2242,15 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_FAKE_ADD: {
/* set fake user */
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_fake_user_set_fn, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ id_fake_user_set_fn,
+ nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Add Fake User");
break;
}
@@ -2222,24 +2262,29 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
space_outliner,
&space_outliner->tree,
id_fake_user_clear_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Clear Fake User");
break;
}
case OUTLINER_IDOP_RENAME: {
/* rename */
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Rename");
break;
}
case OUTLINER_IDOP_SELECT_LINKED:
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_select_linked_fn, NULL);
+ outliner_do_libdata_operation(C,
+ op->reports,
+ scene,
+ space_outliner,
+ &space_outliner->tree,
+ id_select_linked_fn,
+ nullptr);
ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Select");
break;
@@ -2250,10 +2295,10 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
/* wrong notifier still... */
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
/* XXX: this is just so that outliner is always up to date. */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
return OPERATOR_FINISHED;
}
@@ -2281,14 +2326,14 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
/** \name Library Menu Operator
* \{ */
-typedef enum eOutlinerLibOpTypes {
+enum eOutlinerLibOpTypes {
OL_LIB_INVALID = 0,
OL_LIB_RENAME,
OL_LIB_DELETE,
OL_LIB_RELOCATE,
OL_LIB_RELOAD,
-} eOutlinerLibOpTypes;
+};
static const EnumPropertyItem outliner_lib_op_type_items[] = {
{OL_LIB_RENAME, "RENAME", 0, "Rename", ""},
@@ -2304,7 +2349,7 @@ static const EnumPropertyItem outliner_lib_op_type_items[] = {
"Relocate",
"Select a new path for this library, and reload all its data"},
{OL_LIB_RELOAD, "RELOAD", ICON_FILE_REFRESH, "Reload", "Reload all data from this library"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
@@ -2314,39 +2359,39 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
/* check for invalid states */
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return OPERATOR_CANCELLED;
}
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
- eOutlinerLibOpTypes event = RNA_enum_get(op->ptr, "type");
+ eOutlinerLibOpTypes event = (eOutlinerLibOpTypes)RNA_enum_get(op->ptr, "type");
switch (event) {
case OL_LIB_RENAME: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, nullptr);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
ED_undo_push(C, "Rename Library");
break;
}
case OL_LIB_DELETE: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, nullptr);
ED_undo_push(C, "Delete Library");
break;
}
case OL_LIB_RELOCATE: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, lib_relocate_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, lib_relocate_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
break;
}
case OL_LIB_RELOAD: {
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, &space_outliner->tree, lib_reload_fn, NULL);
+ C, op->reports, scene, space_outliner, &space_outliner->tree, lib_reload_fn, nullptr);
/* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
* trick does not work here). */
break;
@@ -2357,10 +2402,10 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
}
/* wrong notifier still... */
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
/* XXX: this is just so that outliner is always up to date */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr);
return OPERATOR_FINISHED;
}
@@ -2397,7 +2442,7 @@ static void outliner_do_id_set_operation(
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == type) {
- TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
+ TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
operation_fn(te, tselem, tsep, newid);
}
}
@@ -2416,14 +2461,14 @@ static void actionset_id_fn(TreeElement *UNUSED(te),
if (tselem->type == TSE_ANIM_DATA) {
/* "animation" entries - action is child of this */
- BKE_animdata_set_action(NULL, tselem->id, act);
+ BKE_animdata_set_action(nullptr, tselem->id, act);
}
/* TODO: if any other "expander" channels which own actions need to support this menu,
* add: tselem->type = ...
*/
else if (tsep && (tsep->type == TSE_ANIM_DATA)) {
/* "animation" entries case again */
- BKE_animdata_set_action(NULL, tsep->id, act);
+ BKE_animdata_set_action(nullptr, tsep->id, act);
}
/* TODO: other cases not supported yet. */
}
@@ -2439,9 +2484,10 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
/* get action to use */
- act = BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"));
+ act = reinterpret_cast<bAction *>(
+ BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action")));
- if (act == NULL) {
+ if (act == nullptr) {
BKE_report(op->reports, RPT_ERROR, "No valid action to add");
return OPERATOR_CANCELLED;
}
@@ -2470,7 +2516,7 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
}
/* set notifier that things have changed */
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Set action");
/* done */
@@ -2508,7 +2554,7 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
/** \name Animation Menu Operator
* \{ */
-typedef enum eOutliner_AnimDataOps {
+enum eOutliner_AnimDataOps {
OUTLINER_ANIMOP_INVALID = 0,
OUTLINER_ANIMOP_CLEAR_ADT,
@@ -2518,7 +2564,7 @@ typedef enum eOutliner_AnimDataOps {
OUTLINER_ANIMOP_REFRESH_DRV,
OUTLINER_ANIMOP_CLEAR_DRV
-} eOutliner_AnimDataOps;
+};
static const EnumPropertyItem prop_animdata_op_types[] = {
{OUTLINER_ANIMOP_CLEAR_ADT,
@@ -2530,7 +2576,7 @@ static const EnumPropertyItem prop_animdata_op_types[] = {
{OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""},
{OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""},
{OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
@@ -2546,21 +2592,21 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
}
/* perform the core operation */
- eOutliner_AnimDataOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_AnimDataOps event = (eOutliner_AnimDataOps)RNA_enum_get(op->ptr, "type");
switch (event) {
case OUTLINER_ANIMOP_CLEAR_ADT:
/* Remove Animation Data - this may remove the active action, in some cases... */
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, clear_animdata_fn, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, clear_animdata_fn, nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Clear Animation Data");
break;
case OUTLINER_ANIMOP_SET_ACT:
/* delegate once again... */
wm->op_undo_depth++;
- WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL);
+ WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, nullptr);
wm->op_undo_depth--;
ED_undo_push(C, "Set active action");
break;
@@ -2568,9 +2614,9 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_ANIMOP_CLEAR_ACT:
/* clear active action - using standard rules */
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, unlinkact_animdata_fn, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, unlinkact_animdata_fn, nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr);
ED_undo_push(C, "Unlink action");
break;
@@ -2580,17 +2626,21 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
event,
&space_outliner->tree,
refreshdrivers_animdata_fn,
- NULL);
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
/* ED_undo_push(C, "Refresh Drivers"); No undo needed - shouldn't have any impact? */
break;
case OUTLINER_ANIMOP_CLEAR_DRV:
- outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, cleardrivers_animdata_fn, NULL);
+ outliner_do_data_operation(space_outliner,
+ datalevel,
+ event,
+ &space_outliner->tree,
+ cleardrivers_animdata_fn,
+ nullptr);
- WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
ED_undo_push(C, "Clear Drivers");
break;
@@ -2630,13 +2680,13 @@ static const EnumPropertyItem prop_constraint_op_types[] = {
{OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""},
{OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_HIDE_ON, "Disable", ""},
{OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- eOutliner_PropConstraintOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_PropConstraintOps event = (eOutliner_PropConstraintOps)RNA_enum_get(op->ptr, "type");
outliner_do_data_operation(
space_outliner, TSE_CONSTRAINT, event, &space_outliner->tree, constraint_fn, C);
@@ -2677,13 +2727,13 @@ static const EnumPropertyItem prop_modifier_op_types[] = {
{OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle Viewport Use", ""},
{OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle Render Use", ""},
{OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- eOutliner_PropModifierOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_PropModifierOps event = (eOutliner_PropModifierOps)RNA_enum_get(op->ptr, "type");
outliner_do_data_operation(
space_outliner, TSE_MODIFIER, event, &space_outliner->tree, modifier_fn, C);
@@ -2726,28 +2776,28 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
- eOutliner_PropDataOps event = RNA_enum_get(op->ptr, "type");
+ eOutliner_PropDataOps event = (eOutliner_PropDataOps)RNA_enum_get(op->ptr, "type");
switch (datalevel) {
case TSE_POSE_CHANNEL: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, pchan_fn, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, pchan_fn, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "PoseChannel operation");
break;
}
case TSE_BONE: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, bone_fn, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, bone_fn, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "Bone operation");
break;
}
case TSE_EBONE: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, ebone_fn, NULL);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, ebone_fn, nullptr);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr);
ED_undo_push(C, "EditBone operation");
break;
@@ -2763,8 +2813,8 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
}
case TSE_GP_LAYER: {
outliner_do_data_operation(
- space_outliner, datalevel, event, &space_outliner->tree, gpencil_layer_fn, NULL);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ space_outliner, datalevel, event, &space_outliner->tree, gpencil_layer_fn, nullptr);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, nullptr);
ED_undo_push(C, "Grease Pencil Layer operation");
break;
@@ -2792,17 +2842,17 @@ static const EnumPropertyItem *outliner_data_op_sets_enum_item_fn(bContext *C,
bool *UNUSED(r_free))
{
/* Check for invalid states. */
- if (C == NULL) {
+ if (C == nullptr) {
return DummyRNA_DEFAULT_items;
}
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- if (space_outliner == NULL) {
+ if (space_outliner == nullptr) {
return DummyRNA_DEFAULT_items;
}
TreeElement *te = get_target_element(space_outliner);
- if (te == NULL) {
+ if (te == nullptr) {
return DummyRNA_NULL_items;
}
@@ -2813,10 +2863,11 @@ static const EnumPropertyItem *outliner_data_op_sets_enum_item_fn(bContext *C,
{OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_DOP_HIDE, "HIDE", 0, "Hide", ""},
{OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""},
- {0, NULL, 0, NULL, NULL}};
+ {0, nullptr, 0, nullptr, nullptr}};
static const EnumPropertyItem optype_sel_linked[] = {
- {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, {0, NULL, 0, NULL, NULL}};
+ {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
+ {0, nullptr, 0, nullptr, nullptr}};
if (tselem->type == TSE_RNA_STRUCT) {
return optype_sel_linked;
@@ -2851,7 +2902,7 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
static int outliner_operator_menu(bContext *C, const char *opname)
{
wmOperatorType *ot = WM_operatortype_find(opname, false);
- uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(ot, NULL), ICON_NONE);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(ot, nullptr), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
/* set this so the default execution context is the same as submenus */
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.cc
index 3353726de18..eb885eba20d 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.cc
@@ -21,8 +21,8 @@
* \ingroup spoutliner
*/
-#include <math.h>
-#include <string.h>
+#include <cmath>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -74,15 +74,19 @@
#include "RNA_access.h"
#include "UI_interface.h"
+#include "UI_resources.h"
-#include "outliner_intern.h"
-#include "tree/tree_display.h"
-#include "tree/tree_element.h"
+#include "outliner_intern.hh"
+#include "tree/common.hh"
+#include "tree/tree_display.hh"
+#include "tree/tree_element.hh"
#ifdef WIN32
# include "BLI_math_base.h" /* M_PI */
#endif
+using namespace blender::ed::outliner;
+
/* prototypes */
static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner);
@@ -101,7 +105,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
BLI_mempool_iter iter;
BLI_mempool_iternew(ts, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
+ while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
tselem->used = 0;
}
@@ -111,8 +115,8 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
space_outliner->storeflag &= ~SO_TREESTORE_CLEANUP;
BLI_mempool_iternew(ts, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == NULL) {
+ while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
+ if (tselem->id == nullptr) {
unused++;
}
}
@@ -120,10 +124,10 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
if (unused) {
if (BLI_mempool_len(ts) == unused) {
BLI_mempool_destroy(ts);
- space_outliner->treestore = NULL;
+ space_outliner->treestore = nullptr;
if (space_outliner->runtime->treehash) {
BKE_outliner_treehash_free(space_outliner->runtime->treehash);
- space_outliner->runtime->treehash = NULL;
+ space_outliner->runtime->treehash = nullptr;
}
}
else {
@@ -131,9 +135,9 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
BLI_mempool *new_ts = BLI_mempool_create(
sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, 512, BLI_MEMPOOL_ALLOW_ITER);
BLI_mempool_iternew(ts, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
+ while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
if (tselem->id) {
- tsenew = BLI_mempool_alloc(new_ts);
+ tsenew = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(new_ts));
*tsenew = *tselem;
}
}
@@ -156,14 +160,14 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner)
static void check_persistent(
SpaceOutliner *space_outliner, TreeElement *te, ID *id, short type, short nr)
{
- if (space_outliner->treestore == NULL) {
+ if (space_outliner->treestore == nullptr) {
/* if treestore was not created in readfile.c, create it here */
space_outliner->treestore = BLI_mempool_create(
sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER);
}
- if (space_outliner->runtime->treehash == NULL) {
- space_outliner->runtime->treehash = BKE_outliner_treehash_create_from_treestore(
- space_outliner->treestore);
+ if (space_outliner->runtime->treehash == nullptr) {
+ space_outliner->runtime->treehash = reinterpret_cast<GHash *>(
+ BKE_outliner_treehash_create_from_treestore(space_outliner->treestore));
}
/* find any unused tree element in treestore and mark it as used
@@ -177,7 +181,7 @@ static void check_persistent(
}
/* add 1 element to treestore */
- tselem = BLI_mempool_alloc(space_outliner->treestore);
+ tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(space_outliner->treestore));
tselem->type = type;
tselem->nr = type ? nr : 0;
tselem->id = id;
@@ -213,8 +217,8 @@ void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree)
if (element->flag & TE_FREE_NAME) {
MEM_freeN((void *)element->name);
}
- outliner_tree_element_type_free(&element->type);
- MEM_freeN(element);
+ element->type = nullptr;
+ MEM_delete(element);
}
/* ********************************************************* */
@@ -253,14 +257,6 @@ static void outliner_add_bone(SpaceOutliner *space_outliner,
}
}
-bool outliner_animdata_test(const AnimData *adt)
-{
- if (adt) {
- return (adt->action || adt->drivers.first || adt->nla_tracks.first);
- }
- return false;
-}
-
#ifdef WITH_FREESTYLE
static void outliner_add_line_styles(SpaceOutliner *space_outliner,
ListBase *lb,
@@ -313,13 +309,13 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0);
if (ob->pose) {
- bArmature *arm = ob->data;
+ bArmature *arm = reinterpret_cast<bArmature *>(ob->data);
TreeElement *tenla = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_POSE_BASE, 0);
tenla->name = IFACE_("Pose");
/* channels undefined in editmode, but we want the 'tenla' pose icon itself */
- if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) {
+ if ((arm->edbo == nullptr) && (ob->mode & OB_MODE_POSE)) {
int const_index = 1000; /* ensure unique id for bone constraints */
int a;
LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, a) {
@@ -359,7 +355,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
}
/* make hierarchy */
- TreeElement *ten = tenla->subtree.first;
+ TreeElement *ten = reinterpret_cast<TreeElement *>(tenla->subtree.first);
while (ten) {
TreeElement *nten = ten->next, *par;
tselem = TREESTORE(ten);
@@ -714,13 +710,15 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
ebone->temp.p = ten;
}
/* make hierarchy */
- TreeElement *ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
+ TreeElement *ten = arm->edbo->first ? reinterpret_cast<TreeElement *>(
+ ((EditBone *)arm->edbo->first)->temp.p) :
+ nullptr;
while (ten) {
TreeElement *nten = ten->next, *par;
EditBone *ebone = (EditBone *)ten->directdata;
if (ebone->parent) {
BLI_remlink(&te->subtree, ten);
- par = ebone->parent->temp.p;
+ par = reinterpret_cast<TreeElement *>(ebone->parent->temp.p);
BLI_addtail(&par->subtree, ten);
ten->parent = par;
}
@@ -812,6 +810,8 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
}
+namespace blender::ed::outliner {
+
TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
@@ -819,16 +819,16 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
short type,
short index)
{
- ID *id = idv;
+ ID *id = reinterpret_cast<ID *>(idv);
if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
id = ((PointerRNA *)idv)->owner_id;
if (!id) {
- id = ((PointerRNA *)idv)->data;
+ id = reinterpret_cast<ID *>(((PointerRNA *)idv)->data);
}
}
else if (type == TSE_GP_LAYER) {
- /* idv is the layer its self */
+ /* idv is the layer itself */
id = TREESTORE(parent)->id;
}
@@ -836,8 +836,8 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
if (type == TSE_ID_BASE) {
/* pass */
}
- else if (id == NULL) {
- return NULL;
+ else if (id == nullptr) {
+ return nullptr;
}
if (type == 0) {
@@ -845,7 +845,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
BLI_assert(TREESTORE_ID_TYPE(id));
}
- TreeElement *te = MEM_callocN(sizeof(TreeElement), __func__);
+ TreeElement *te = MEM_new<TreeElement>(__func__);
/* add to the visual tree */
BLI_addtail(lb, te);
/* add to the storage */
@@ -860,12 +860,12 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->parent = parent;
te->index = index; /* For data arrays. */
- /* New C++ based type handle (`TreeElementType` in C, `AbstractTreeElement` in C++). Only some
- * support this, eventually this should replace `TreeElement` entirely. */
- te->type = outliner_tree_element_type_create(type, te, idv);
+ /* New C++ based type handle. Only some support this, eventually this should replace
+ * `TreeElement` entirely. */
+ te->type = AbstractTreeElement::createFromType(type, *te, idv);
if (te->type) {
/* Element types ported to the new design are expected to have their name set at this point! */
- BLI_assert(te->name != NULL);
+ BLI_assert(te->name != nullptr);
}
if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
@@ -909,14 +909,14 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->idcode = GS(id->name);
}
- if (te->type && outliner_tree_element_type_is_expand_valid(te->type)) {
- outliner_tree_element_type_expand(te->type, space_outliner);
+ if (te->type && te->type->isExpandValid()) {
+ tree_element_expand(*te->type, *space_outliner);
}
else if (type == TSE_SOME_ID) {
/* ID types not (fully) ported to new design yet. */
- if (outliner_tree_element_type_expand_poll(te->type, space_outliner)) {
+ if (te->type->expandPoll(*space_outliner)) {
outliner_add_id_contents(space_outliner, te, tselem, id);
- outliner_tree_element_type_post_expand(te->type, space_outliner);
+ te->type->postExpand(*space_outliner);
}
}
else if (ELEM(type,
@@ -925,199 +925,25 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
TSE_NLA,
TSE_NLA_ACTION,
TSE_NLA_TRACK,
- TSE_GP_LAYER)) {
- /* Should already use new AbstractTreeElement design. */
- BLI_assert(0);
- }
- else if (type == TSE_SEQUENCE) {
- Sequence *seq = (Sequence *)idv;
-
- /*
- * The idcode is a little hack, but the outliner
- * only check te->idcode if te->type is equal to zero,
- * so this is "safe".
- */
- te->idcode = seq->type;
- te->directdata = seq;
- te->name = seq->name + 2;
-
- if (!(seq->type & SEQ_TYPE_EFFECT)) {
- /*
- * This work like the sequence.
- * If the sequence have a name (not default name)
- * show it, in other case put the filename.
- */
-
- if (seq->type == SEQ_TYPE_META) {
- LISTBASE_FOREACH (Sequence *, p, &seq->seqbase) {
- outliner_add_element(space_outliner, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
- }
- }
- else {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)seq->strip, te, TSE_SEQ_STRIP, index);
- }
- }
+ TSE_GP_LAYER,
+ TSE_RNA_STRUCT,
+ TSE_RNA_PROPERTY,
+ TSE_RNA_ARRAY_ELEM,
+ TSE_SEQUENCE,
+ TSE_SEQ_STRIP,
+ TSE_SEQUENCE_DUP)) {
+ BLI_assert_msg(false, "Element type should already use new AbstractTreeElement design");
}
- else if (type == TSE_SEQ_STRIP) {
- Strip *strip = (Strip *)idv;
-
- if (strip->dir[0] != '\0') {
- te->name = strip->dir;
- }
- else {
- te->name = IFACE_("Strip None");
- }
- te->directdata = strip;
- }
- else if (type == TSE_SEQUENCE_DUP) {
- Sequence *seq = (Sequence *)idv;
-
- te->idcode = seq->type;
- te->directdata = seq;
- te->name = seq->strip->stripdata->name;
- }
- else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
- PointerRNA *ptr = (PointerRNA *)idv;
-
- /* Don't display arrays larger, weak but index is stored as a short,
- * also the outliner isn't intended for editing such large data-sets. */
- BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!")
- const int tot_limit = SHRT_MAX;
-
- /* we do lazy build, for speed and to avoid infinite recursion */
-
- if (ptr->data == NULL) {
- te->name = IFACE_("(empty)");
- }
- else if (type == TSE_RNA_STRUCT) {
- /* struct */
- te->name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
-
- if (te->name) {
- te->flag |= TE_FREE_NAME;
- }
- else {
- te->name = RNA_struct_ui_name(ptr->type);
- }
-
- /* If searching don't expand RNA entries */
- if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) {
- tselem->flag &= ~TSE_CHILDSEARCH;
- }
-
- PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
- int tot = RNA_property_collection_length(ptr, iterprop);
- CLAMP_MAX(tot, tot_limit);
-
- /* auto open these cases */
- if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER) {
- if (!tselem->used) {
- tselem->flag &= ~TSE_CLOSED;
- }
- }
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- PointerRNA propptr;
- RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr);
- if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a);
- }
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
-
- te->rnaptr = *ptr;
- }
- else if (type == TSE_RNA_PROPERTY) {
- /* property */
- PointerRNA propptr;
- PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type);
- RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr);
- PropertyRNA *prop = propptr.data;
- PropertyType proptype = RNA_property_type(prop);
-
- te->name = RNA_property_ui_name(prop);
- te->directdata = prop;
- te->rnaptr = *ptr;
-
- /* If searching don't expand RNA entries */
- if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) {
- tselem->flag &= ~TSE_CHILDSEARCH;
- }
-
- if (proptype == PROP_POINTER) {
- PointerRNA pptr = RNA_property_pointer_get(ptr, prop);
-
- if (pptr.data) {
- if (TSELEM_OPEN(tselem, space_outliner)) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1);
- }
- else {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- }
- else if (proptype == PROP_COLLECTION) {
- int tot = RNA_property_collection_length(ptr, prop);
- CLAMP_MAX(tot, tot_limit);
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- PointerRNA pptr;
- RNA_property_collection_lookup_int(ptr, prop, a, &pptr);
- outliner_add_element(
- space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a);
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
- int tot = RNA_property_array_length(ptr, prop);
- CLAMP_MAX(tot, tot_limit);
-
- if (TSELEM_OPEN(tselem, space_outliner)) {
- for (int a = 0; a < tot; a++) {
- outliner_add_element(
- space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a);
- }
- }
- else if (tot) {
- te->flag |= TE_LAZY_CLOSED;
- }
- }
- }
- else if (type == TSE_RNA_ARRAY_ELEM) {
- PropertyRNA *prop = parent->directdata;
-
- te->directdata = prop;
- te->rnaptr = *ptr;
- te->index = index;
-
- char c = RNA_property_array_item_char(prop, index);
-
- te->name = MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName");
- if (c) {
- sprintf((char *)te->name, " %c", c);
- }
- else {
- sprintf((char *)te->name, " %d", index + 1);
- }
- te->flag |= TE_FREE_NAME;
- }
+ if (tree_element_warnings_get(te, nullptr, nullptr)) {
+ te->flag |= TE_HAS_WARNING;
}
return te;
}
+} // namespace blender::ed::outliner
+
/* ======================================================= */
BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection)
@@ -1157,43 +983,20 @@ TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner,
/* ======================================================= */
/* Generic Tree Building helpers - order these are called is top to bottom */
-/* Hierarchy --------------------------------------------- */
-
-void outliner_make_object_parent_hierarchy(ListBase *lb)
-{
- /* build hierarchy */
- /* XXX also, set extents here... */
- TreeElement *te = lb->first;
- while (te) {
- TreeElement *ten = te->next;
- TreeStoreElem *tselem = TREESTORE(te);
-
- if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) {
- Object *ob = (Object *)tselem->id;
- if (ob->parent && ob->parent->id.newid) {
- BLI_remlink(lb, te);
- TreeElement *tep = (TreeElement *)ob->parent->id.newid;
- BLI_addtail(&tep->subtree, te);
- te->parent = tep;
- }
- }
- te = ten;
- }
-}
-
/* Sorting ------------------------------------------------------ */
-typedef struct tTreeSort {
+struct tTreeSort {
TreeElement *te;
ID *id;
const char *name;
short idcode;
-} tTreeSort;
+};
/* alphabetical comparator, trying to put objects first */
static int treesort_alpha_ob(const void *v1, const void *v2)
{
- const tTreeSort *x1 = v1, *x2 = v2;
+ const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
/* first put objects last (hierarchy) */
int comp = (x1->idcode == ID_OB);
@@ -1231,7 +1034,8 @@ static int treesort_alpha_ob(const void *v1, const void *v2)
/* Move children that are not in the collection to the end of the list. */
static int treesort_child_not_in_collection(const void *v1, const void *v2)
{
- const tTreeSort *x1 = v1, *x2 = v2;
+ const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
/* Among objects first come the ones in the collection, followed by the ones not on it.
* This way we can have the dashed lines in a separate style connecting the former. */
@@ -1244,7 +1048,8 @@ static int treesort_child_not_in_collection(const void *v1, const void *v2)
/* alphabetical comparator */
static int treesort_alpha(const void *v1, const void *v2)
{
- const tTreeSort *x1 = v1, *x2 = v2;
+ const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1);
+ const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2);
int comp = BLI_strcasecmp_natural(x1->name, x2->name);
@@ -1301,24 +1106,25 @@ static int treesort_obtype_alpha(const void *v1, const void *v2)
/* sort happens on each subtree individual */
static void outliner_sort(ListBase *lb)
{
- TreeElement *te = lb->last;
- if (te == NULL) {
+ TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last);
+ if (last_te == nullptr) {
return;
}
- TreeStoreElem *tselem = TREESTORE(te);
+ TreeStoreElem *last_tselem = TREESTORE(last_te);
/* Sorting rules; only object lists, ID lists, or deform-groups. */
- if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
- ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) {
+ if (ELEM(last_tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
+ ((last_tselem->type == TSE_SOME_ID) && (last_te->idcode == ID_OB))) {
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
- tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
+ tTreeSort *tear = reinterpret_cast<tTreeSort *>(
+ MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"));
tTreeSort *tp = tear;
int skip = 0;
- for (te = lb->first; te; te = te->next, tp++) {
- tselem = TREESTORE(te);
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
+ TreeStoreElem *tselem = TREESTORE(te);
tp->te = te;
tp->name = te->name;
tp->idcode = te->idcode;
@@ -1331,6 +1137,7 @@ static void outliner_sort(ListBase *lb)
}
tp->id = tselem->id;
+ tp++;
}
/* just sort alphabetically */
@@ -1367,26 +1174,28 @@ static void outliner_sort(ListBase *lb)
static void outliner_collections_children_sort(ListBase *lb)
{
- TreeElement *te = lb->last;
- if (te == NULL) {
+ TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last);
+ if (last_te == nullptr) {
return;
}
- TreeStoreElem *tselem = TREESTORE(te);
+ TreeStoreElem *last_tselem = TREESTORE(last_te);
/* Sorting rules: only object lists. */
- if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
+ if ((last_tselem->type == TSE_SOME_ID) && (last_te->idcode == ID_OB)) {
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
- tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
+ tTreeSort *tear = reinterpret_cast<tTreeSort *>(
+ MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"));
tTreeSort *tp = tear;
- for (te = lb->first; te; te = te->next, tp++) {
- tselem = TREESTORE(te);
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
+ TreeStoreElem *tselem = TREESTORE(te);
tp->te = te;
tp->name = te->name;
tp->idcode = te->idcode;
tp->id = tselem->id;
+ tp++;
}
qsort(tear, totelem, sizeof(tTreeSort), treesort_child_not_in_collection);
@@ -1408,10 +1217,10 @@ static void outliner_collections_children_sort(ListBase *lb)
/* Filtering ----------------------------------------------- */
-typedef struct OutlinerTreeElementFocus {
+struct OutlinerTreeElementFocus {
TreeStoreElem *tselem;
int ys;
-} OutlinerTreeElementFocus;
+};
/**
* Bring the outliner scrolling back to where it was in relation to the original focus element
@@ -1423,12 +1232,12 @@ static void outliner_restore_scrolling_position(SpaceOutliner *space_outliner,
{
View2D *v2d = &region->v2d;
- if (focus->tselem != NULL) {
+ if (focus->tselem != nullptr) {
outliner_set_coordinates(region, space_outliner);
TreeElement *te_new = outliner_find_tree_element(&space_outliner->tree, focus->tselem);
- if (te_new != NULL) {
+ if (te_new != nullptr) {
int ys_new = te_new->ys;
int ys_old = focus->ys;
@@ -1466,17 +1275,16 @@ static TreeElement *outliner_find_first_desired_element_at_y_recursive(
}
if (TSELEM_OPEN(te->store_elem, space_outliner)) {
- TreeElement *te_iter, *te_sub;
- for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) {
- te_sub = outliner_find_first_desired_element_at_y_recursive(
+ LISTBASE_FOREACH (TreeElement *, te_iter, &te->subtree) {
+ TreeElement *te_sub = outliner_find_first_desired_element_at_y_recursive(
space_outliner, te_iter, limit, callback_test);
- if (te_sub != NULL) {
+ if (te_sub != nullptr) {
return te_sub;
}
}
}
- return NULL;
+ return nullptr;
}
/**
@@ -1487,7 +1295,7 @@ static TreeElement *outliner_find_first_desired_element_at_y_recursive(
*
* Basically we keep going up and down the outliner tree from that point forward, until we find
* what we are looking for. If we are past the visible range and we can't find a valid element
- * we return NULL.
+ * we return nullptr.
*/
static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner *space_outliner,
const float view_co,
@@ -1504,15 +1312,15 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner
callback_test = test_collection_callback;
}
- while (te != NULL) {
+ while (te != nullptr) {
TreeElement *te_sub = outliner_find_first_desired_element_at_y_recursive(
space_outliner, te, view_co_limit, callback_test);
- if (te_sub != NULL) {
+ if (te_sub != nullptr) {
/* Skip the element if it was not visible to start with. */
if (te->ys + UI_UNIT_Y > view_co_limit) {
return te_sub;
}
- return NULL;
+ return nullptr;
}
if (te->next) {
@@ -1520,7 +1328,7 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner
continue;
}
- if (te->parent == NULL) {
+ if (te->parent == nullptr) {
break;
}
@@ -1533,7 +1341,7 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner
}
}
- return NULL;
+ return nullptr;
}
/**
@@ -1554,12 +1362,12 @@ static void outliner_store_scrolling_position(SpaceOutliner *space_outliner,
TreeElement *te = outliner_find_first_desired_element_at_y(
space_outliner, region->v2d.cur.ymax, limit);
- if (te != NULL) {
+ if (te != nullptr) {
focus->tselem = TREESTORE(te);
focus->ys = te->ys;
}
else {
- focus->tselem = NULL;
+ focus->tselem = nullptr;
}
}
@@ -1617,7 +1425,7 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
Object *ob = (Object *)tselem->id;
Base *base = (Base *)te->directdata;
- BLI_assert((base == NULL) || (base->object == ob));
+ BLI_assert((base == nullptr) || (base->object == ob));
if (exclude_filter & SO_FILTER_OB_TYPE) {
switch (ob->type) {
@@ -1655,10 +1463,10 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
}
if (exclude_filter & SO_FILTER_OB_STATE) {
- if (base == NULL) {
+ if (base == nullptr) {
base = BKE_view_layer_base_find(view_layer, ob);
- if (base == NULL) {
+ if (base == nullptr) {
return false;
}
}
@@ -1693,14 +1501,14 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
return is_visible;
}
- if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
+ if ((te->parent != nullptr) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
(te->parent->idcode == ID_OB)) {
if (exclude_filter & SO_FILTER_NO_CHILDREN) {
return false;
}
}
}
- else if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
+ else if ((te->parent != nullptr) && (TREESTORE(te->parent)->type == TSE_SOME_ID) &&
(te->parent->idcode == ID_OB)) {
if (exclude_filter & SO_FILTER_NO_OB_CONTENT) {
return false;
@@ -1743,8 +1551,9 @@ static TreeElement *outliner_extract_children_from_subtree(TreeElement *element,
TreeElement *te_next = element->next;
if (outliner_element_is_collection_or_object(element)) {
- TreeElement *te_prev = NULL;
- for (TreeElement *te = element->subtree.last; te; te = te_prev) {
+ TreeElement *te_prev = nullptr;
+ for (TreeElement *te = reinterpret_cast<TreeElement *>(element->subtree.last); te;
+ te = te_prev) {
te_prev = te->prev;
if (!outliner_element_is_collection_or_object(te)) {
@@ -1771,7 +1580,7 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner,
TreeElement *te, *te_next;
TreeStoreElem *tselem;
- for (te = lb->first; te; te = te_next) {
+ for (te = reinterpret_cast<TreeElement *>(lb->first); te; te = te_next) {
te_next = te->next;
if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
/* Don't free the tree, but extract the children from the parent and add to this tree. */
@@ -1824,7 +1633,7 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner,
static void outliner_filter_tree(SpaceOutliner *space_outliner, ViewLayer *view_layer)
{
- char search_buff[sizeof(((struct SpaceOutliner *)NULL)->search_string) + 2];
+ char search_buff[sizeof(((struct SpaceOutliner *)nullptr)->search_string) + 2];
char *search_string;
const int exclude_filter = outliner_exclude_filter_get(space_outliner);
@@ -1850,7 +1659,7 @@ static void outliner_clear_newid_from_main(Main *bmain)
{
ID *id_iter;
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
- id_iter->newid = NULL;
+ id_iter->newid = nullptr;
}
FOREACH_MAIN_ID_END;
}
@@ -1890,17 +1699,15 @@ void outliner_build_tree(Main *mainvar,
outliner_free_tree(&space_outliner->tree);
outliner_storage_cleanup(space_outliner);
- outliner_tree_display_destroy(&space_outliner->runtime->tree_display);
- space_outliner->runtime->tree_display = outliner_tree_display_create(space_outliner->outlinevis,
- space_outliner);
+ space_outliner->runtime->tree_display = AbstractTreeDisplay::createFromDisplayMode(
+ space_outliner->outlinevis, *space_outliner);
/* All tree displays should be created as sub-classes of AbstractTreeDisplay. */
- BLI_assert(space_outliner->runtime->tree_display != NULL);
+ BLI_assert(space_outliner->runtime->tree_display != nullptr);
- TreeSourceData source_data = {.bmain = mainvar, .scene = scene, .view_layer = view_layer};
- space_outliner->tree = outliner_tree_display_build_tree(space_outliner->runtime->tree_display,
- &source_data);
+ TreeSourceData source_data{*mainvar, *scene, *view_layer};
+ space_outliner->tree = space_outliner->runtime->tree_display->buildTree(source_data);
if ((space_outliner->flag & SO_SKIP_SORT_ALPHA) == 0) {
outliner_sort(&space_outliner->tree);
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.cc
index d370d508198..86b56a7ec12 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.cc
@@ -21,7 +21,7 @@
* \ingroup spoutliner
*/
-#include <string.h>
+#include <cstring>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -42,7 +42,7 @@
#include "UI_interface.h"
#include "UI_view2d.h"
-#include "outliner_intern.h"
+#include "outliner_intern.hh"
/* -------------------------------------------------------------------- */
/** \name Tree View Context
@@ -58,7 +58,7 @@ void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc)
/* Objects. */
tvc->obact = OBACT(tvc->view_layer);
- if (tvc->obact != NULL) {
+ if (tvc->obact != nullptr) {
tvc->ob_edit = OBEDIT_FROM_OBACT(tvc->obact);
if ((tvc->obact->type == OB_ARMATURE) ||
@@ -104,14 +104,14 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner,
}
}
- return NULL;
+ return nullptr;
}
static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *parent_te,
float view_co_x,
bool *r_is_merged_icon)
{
- TreeElement *child_te = parent_te->subtree.first;
+ TreeElement *child_te = reinterpret_cast<TreeElement *>(parent_te->subtree.first);
while (child_te) {
const bool over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend);
@@ -168,7 +168,7 @@ TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store
return tes;
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_parent_element(ListBase *lb,
@@ -185,25 +185,25 @@ TreeElement *outliner_find_parent_element(ListBase *lb,
return find_te;
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_tse(SpaceOutliner *space_outliner, const TreeStoreElem *tse)
{
TreeStoreElem *tselem;
- if (tse->id == NULL) {
- return NULL;
+ if (tse->id == nullptr) {
+ return nullptr;
}
- /* check if 'tse' is in treestore */
+ /* Check if 'tse' is in tree-store. */
tselem = BKE_outliner_treehash_lookup_any(
space_outliner->runtime->treehash, tse->type, tse->nr, tse->id);
if (tselem) {
return outliner_find_tree_element(&space_outliner->tree, tselem);
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const ID *id)
@@ -221,7 +221,7 @@ TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const
return tes;
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
@@ -239,7 +239,7 @@ TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
}
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
@@ -257,7 +257,7 @@ TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
}
}
}
- return NULL;
+ return nullptr;
}
TreeElement *outliner_search_back_te(TreeElement *te, short idcode)
@@ -272,7 +272,7 @@ TreeElement *outliner_search_back_te(TreeElement *te, short idcode)
}
te = te->parent;
}
- return NULL;
+ return nullptr;
}
ID *outliner_search_back(TreeElement *te, short idcode)
@@ -285,7 +285,7 @@ ID *outliner_search_back(TreeElement *te, short idcode)
tselem = TREESTORE(search_te);
return tselem->id;
}
- return NULL;
+ return nullptr;
}
bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
@@ -295,7 +295,8 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
TreeTraversalFunc func,
void *customdata)
{
- for (TreeElement *te = tree->first, *te_next; te; te = te_next) {
+ for (TreeElement *te = reinterpret_cast<TreeElement *>(tree->first), *te_next; te;
+ te = te_next) {
TreeTraversalAction func_retval = TRAVERSE_CONTINUE;
/* in case te is freed in callback */
TreeStoreElem *tselem = TREESTORE(te);
@@ -382,7 +383,7 @@ TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
return active_element;
}
}
- return NULL;
+ return nullptr;
}
bool outliner_is_element_visible(const TreeElement *te)
@@ -467,7 +468,7 @@ Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
TreeElement *te;
- Base *base = NULL;
+ Base *base = nullptr;
float view_mval[2];
UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.cc
index 6c45d39e0d8..0fb17fa3f47 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.cc
@@ -21,8 +21,8 @@
* \ingroup spoutliner
*/
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -31,6 +31,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_lib_remap.h"
#include "BKE_outliner_treehash.h"
#include "BKE_screen.h"
@@ -49,8 +50,20 @@
#include "UI_resources.h"
#include "UI_view2d.h"
-#include "outliner_intern.h"
-#include "tree/tree_display.h"
+#include "outliner_intern.hh"
+#include "tree/tree_display.hh"
+
+SpaceOutliner_Runtime::SpaceOutliner_Runtime(const SpaceOutliner_Runtime & /*other*/)
+ : tree_display(nullptr), treehash(nullptr)
+{
+}
+
+SpaceOutliner_Runtime::~SpaceOutliner_Runtime()
+{
+ if (treehash) {
+ BKE_outliner_treehash_free(treehash);
+ }
+}
static void outliner_main_region_init(wmWindowManager *wm, ARegion *region)
{
@@ -92,7 +105,7 @@ static void outliner_main_region_draw(const bContext *C, ARegion *region)
UI_view2d_view_restore(C);
/* scrollers */
- UI_view2d_scrollers_draw(v2d, NULL);
+ UI_view2d_scrollers_draw(v2d, nullptr);
}
static void outliner_main_region_free(ARegion *UNUSED(region))
@@ -104,7 +117,7 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params)
ScrArea *area = params->area;
ARegion *region = params->region;
wmNotifier *wmn = params->notifier;
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
/* context changes */
switch (wmn->category) {
@@ -262,23 +275,25 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params)
}
}
+/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
+extern "C" {
static void outliner_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
struct wmMsgBus *mbus = params->message_bus;
ScrArea *area = params->area;
ARegion *region = params->region;
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
- wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
- .owner = region,
- .user_data = region,
- .notify = ED_region_do_msg_notify_tag_redraw,
- };
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
+ msg_sub_value_region_tag_redraw.owner = region;
+ msg_sub_value_region_tag_redraw.user_data = region;
+ msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
if (ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_OVERRIDES_LIBRARY)) {
WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
}
}
+}
/* ************************ header outliner area region *********************** */
@@ -324,7 +339,7 @@ static SpaceLink *outliner_create(const ScrArea *UNUSED(area), const Scene *UNUS
ARegion *region;
SpaceOutliner *space_outliner;
- space_outliner = MEM_callocN(sizeof(SpaceOutliner), "initoutliner");
+ space_outliner = MEM_cnew<SpaceOutliner>("initoutliner");
space_outliner->spacetype = SPACE_OUTLINER;
space_outliner->filter_id_type = ID_GR;
space_outliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE | SO_RESTRICT_RENDER;
@@ -334,14 +349,14 @@ static SpaceLink *outliner_create(const ScrArea *UNUSED(area), const Scene *UNUS
space_outliner->filter = SO_FILTER_NO_VIEW_LAYERS;
/* header */
- region = MEM_callocN(sizeof(ARegion), "header for outliner");
+ region = MEM_cnew<ARegion>("header for outliner");
BLI_addtail(&space_outliner->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
/* main region */
- region = MEM_callocN(sizeof(ARegion), "main region for outliner");
+ region = MEM_cnew<ARegion>("main region for outliner");
BLI_addtail(&space_outliner->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
@@ -359,84 +374,81 @@ static void outliner_free(SpaceLink *sl)
BLI_mempool_destroy(space_outliner->treestore);
}
- if (space_outliner->runtime) {
- outliner_tree_display_destroy(&space_outliner->runtime->tree_display);
- if (space_outliner->runtime->treehash) {
- BKE_outliner_treehash_free(space_outliner->runtime->treehash);
- }
- MEM_freeN(space_outliner->runtime);
- }
+ MEM_delete(space_outliner->runtime);
}
/* spacetype; init callback */
static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
- if (space_outliner->runtime == NULL) {
- space_outliner->runtime = MEM_callocN(sizeof(*space_outliner->runtime),
- "SpaceOutliner_Runtime");
+ if (space_outliner->runtime == nullptr) {
+ space_outliner->runtime = MEM_new<SpaceOutliner_Runtime>("SpaceOutliner_Runtime");
}
}
static SpaceLink *outliner_duplicate(SpaceLink *sl)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
- SpaceOutliner *space_outliner_new = MEM_dupallocN(space_outliner);
+ SpaceOutliner *space_outliner_new = MEM_new<SpaceOutliner>(__func__, *space_outliner);
BLI_listbase_clear(&space_outliner_new->tree);
- space_outliner_new->treestore = NULL;
+ space_outliner_new->treestore = nullptr;
space_outliner_new->sync_select_dirty = WM_OUTLINER_SYNC_SELECT_FROM_ALL;
if (space_outliner->runtime) {
- space_outliner_new->runtime = MEM_dupallocN(space_outliner->runtime);
- space_outliner_new->runtime->tree_display = NULL;
- space_outliner_new->runtime->treehash = NULL;
+ /* Copy constructor handles details. */
+ space_outliner_new->runtime = MEM_new<SpaceOutliner_Runtime>("SpaceOutliner_runtime dup",
+ *space_outliner->runtime);
}
return (SpaceLink *)space_outliner_new;
}
-static void outliner_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
+static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRemapper *mappings)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)slink;
- /* Some early out checks. */
- if (!TREESTORE_ID_TYPE(old_id)) {
- return; /* ID type is not used by outliner. */
- }
+ BKE_id_remapper_apply(mappings, (ID **)&space_outliner->search_tse.id, ID_REMAP_APPLY_DEFAULT);
- if (space_outliner->search_tse.id == old_id) {
- space_outliner->search_tse.id = new_id;
+ if (!space_outliner->treestore) {
+ return;
}
- if (space_outliner->treestore) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
- bool changed = false;
-
- BLI_mempool_iternew(space_outliner->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- if (tselem->id == old_id) {
- tselem->id = new_id;
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+ bool unassigned = false;
+
+ BLI_mempool_iternew(space_outliner->treestore, &iter);
+ while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) {
+ switch (BKE_id_remapper_apply(mappings, &tselem->id, ID_REMAP_APPLY_DEFAULT)) {
+ case ID_REMAP_RESULT_SOURCE_REMAPPED:
changed = true;
- }
+ break;
+ case ID_REMAP_RESULT_SOURCE_UNASSIGNED:
+ changed = true;
+ unassigned = true;
+ break;
+ case ID_REMAP_RESULT_SOURCE_UNAVAILABLE:
+ case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE:
+ break;
}
+ }
- /* Note that the Outliner may not be the active editor of the area, and hence not initialized.
- * So runtime data might not have been created yet. */
- if (space_outliner->runtime && space_outliner->runtime->treehash && changed) {
- /* rebuild hash table, because it depends on ids too */
- /* postpone a full rebuild because this can be called many times on-free */
- space_outliner->storeflag |= SO_TREESTORE_REBUILD;
-
- if (new_id == NULL) {
- /* Redraw is needed when removing data for multiple outlines show the same data.
- * without this, the stale data won't get fully flushed when this outliner
- * is not the active outliner the user is interacting with. See T85976. */
- ED_area_tag_redraw(area);
- }
+ /* Note that the Outliner may not be the active editor of the area, and hence not initialized.
+ * So runtime data might not have been created yet. */
+ if (space_outliner->runtime && space_outliner->runtime->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ space_outliner->storeflag |= SO_TREESTORE_REBUILD;
+
+ if (unassigned) {
+ /* Redraw is needed when removing data for multiple outlines show the same data.
+ * without this, the stale data won't get fully flushed when this outliner
+ * is not the active outliner the user is interacting with. See T85976. */
+ ED_area_tag_redraw(area);
}
}
}
@@ -444,14 +456,14 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *n
static void outliner_deactivate(struct ScrArea *area)
{
/* Remove hover highlights */
- SpaceOutliner *space_outliner = area->spacedata.first;
+ SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first);
outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED_ANY, false);
ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
}
void ED_spacetype_outliner(void)
{
- SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time");
+ SpaceType *st = MEM_cnew<SpaceType>("spacetype time");
ARegionType *art;
st->spaceid = SPACE_OUTLINER;
@@ -469,7 +481,7 @@ void ED_spacetype_outliner(void)
st->context = outliner_context;
/* regions: main window */
- art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region");
+ art = MEM_cnew<ARegionType>("spacetype outliner region");
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
@@ -481,7 +493,7 @@ void ED_spacetype_outliner(void)
BLI_addhead(&st->regiontypes, art);
/* regions: header */
- art = MEM_callocN(sizeof(ARegionType), "spacetype outliner header region");
+ art = MEM_cnew<ARegionType>("spacetype outliner header region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
diff --git a/source/blender/editors/space_outliner/tree/common.cc b/source/blender/editors/space_outliner/tree/common.cc
index 306d59288f4..c6b5ee3b7ef 100644
--- a/source/blender/editors/space_outliner/tree/common.cc
+++ b/source/blender/editors/space_outliner/tree/common.cc
@@ -20,10 +20,18 @@
* Functions and helpers shared between tree-display types or other tree related code.
*/
+#include "BLI_listbase.h"
+
#include "BKE_idtype.h"
+#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
+#include "DNA_outliner_types.h"
+
#include "RNA_access.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
/* -------------------------------------------------------------------- */
@@ -38,3 +46,33 @@ const char *outliner_idcode_to_plural(short idcode)
}
/** \} */
+
+void outliner_make_object_parent_hierarchy(ListBase *lb)
+{
+ /* build hierarchy */
+ /* XXX also, set extents here... */
+ TreeElement *te = reinterpret_cast<TreeElement *>(lb->first);
+ while (te) {
+ TreeElement *ten = te->next;
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) {
+ Object *ob = (Object *)tselem->id;
+ if (ob->parent && ob->parent->id.newid) {
+ BLI_remlink(lb, te);
+ TreeElement *tep = (TreeElement *)ob->parent->id.newid;
+ BLI_addtail(&tep->subtree, te);
+ te->parent = tep;
+ }
+ }
+ te = ten;
+ }
+}
+
+bool outliner_animdata_test(const AnimData *adt)
+{
+ if (adt) {
+ return (adt->action || adt->drivers.first || adt->nla_tracks.first);
+ }
+ return false;
+}
diff --git a/source/blender/editors/space_outliner/tree/common.hh b/source/blender/editors/space_outliner/tree/common.hh
new file mode 100644
index 00000000000..1745bfa436e
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/common.hh
@@ -0,0 +1,28 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+struct ListBase;
+
+const char *outliner_idcode_to_plural(short idcode);
+
+void outliner_make_object_parent_hierarchy(ListBase *lb);
+bool outliner_animdata_test(const struct AnimData *adt);
diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc
index 003afd5bdec..d2b6fff6996 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display.cc
@@ -19,50 +19,41 @@
*/
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
#include "tree_display.hh"
using namespace blender::ed::outliner;
-TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutliner *space_outliner)
-{
- AbstractTreeDisplay *tree_display = nullptr;
+namespace blender::ed::outliner {
- switch (mode) {
+std::unique_ptr<AbstractTreeDisplay> AbstractTreeDisplay::createFromDisplayMode(
+ int /*eSpaceOutliner_Mode*/ mode, SpaceOutliner &space_outliner)
+{
+ switch ((eSpaceOutliner_Mode)mode) {
case SO_SCENES:
- tree_display = new TreeDisplayScenes(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayScenes>(space_outliner);
case SO_LIBRARIES:
- tree_display = new TreeDisplayLibraries(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayLibraries>(space_outliner);
case SO_SEQUENCE:
- tree_display = new TreeDisplaySequencer(*space_outliner);
- break;
+ return std::make_unique<TreeDisplaySequencer>(space_outliner);
case SO_DATA_API:
- tree_display = new TreeDisplayDataAPI(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayDataAPI>(space_outliner);
case SO_ID_ORPHANS:
- tree_display = new TreeDisplayIDOrphans(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayIDOrphans>(space_outliner);
case SO_OVERRIDES_LIBRARY:
- tree_display = new TreeDisplayOverrideLibrary(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayOverrideLibrary>(space_outliner);
case SO_VIEW_LAYER:
+ /* FIXME(Julian): this should not be the default! Return nullptr and handle that as valid
+ * case. */
default:
- tree_display = new TreeDisplayViewLayer(*space_outliner);
- break;
+ return std::make_unique<TreeDisplayViewLayer>(space_outliner);
}
-
- return reinterpret_cast<TreeDisplay *>(tree_display);
}
-void outliner_tree_display_destroy(TreeDisplay **tree_display)
+bool AbstractTreeDisplay::hasWarnings() const
{
- delete reinterpret_cast<AbstractTreeDisplay *>(*tree_display);
- *tree_display = nullptr;
+ return has_warnings;
}
-ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceData *source_data)
-{
- return reinterpret_cast<AbstractTreeDisplay *>(tree_display)->buildTree(*source_data);
-}
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_display.h b/source/blender/editors/space_outliner/tree/tree_display.h
deleted file mode 100644
index b6dc33ba7b7..00000000000
--- a/source/blender/editors/space_outliner/tree/tree_display.h
+++ /dev/null
@@ -1,76 +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.
- */
-
-/** \file
- * \ingroup spoutliner
- *
- * C-API for the Tree-Display types.
- */
-
-#pragma once
-
-#include "DNA_space_types.h"
-
-struct ListBase;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** C alias for an #AbstractTreeDisplay handle. */
-typedef struct TreeDisplay TreeDisplay;
-
-/**
- * \brief The data to build the tree from.
- */
-typedef struct TreeSourceData {
- struct Main *bmain;
- struct Scene *scene;
- struct ViewLayer *view_layer;
-} TreeSourceData;
-
-TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutliner *space_outliner);
-void outliner_tree_display_destroy(TreeDisplay **tree_display);
-
-ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceData *source_data);
-
-/* 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,
- struct Collection *collection,
- TreeElement *ten);
-
-const char *outliner_idcode_to_plural(short idcode);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index 54e64655b18..68f0f9c562d 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -34,16 +34,35 @@
#pragma once
-#include "tree_display.h"
+#include <memory>
+struct ID;
+struct LayerCollection;
+struct Library;
struct ListBase;
struct Main;
+struct Scene;
+struct Sequence;
struct SpaceOutliner;
struct TreeElement;
-struct TreeSourceData;
+struct ViewLayer;
namespace blender::ed::outliner {
+/**
+ * \brief The data to build the tree from.
+ */
+struct TreeSourceData {
+ Main *bmain;
+ Scene *scene;
+ ViewLayer *view_layer;
+
+ TreeSourceData(Main &bmain, Scene &scene, ViewLayer &view_layer)
+ : bmain(&bmain), scene(&scene), view_layer(&view_layer)
+ {
+ }
+};
+
/* -------------------------------------------------------------------- */
/* Tree-Display Interface */
@@ -59,13 +78,21 @@ class AbstractTreeDisplay {
}
virtual ~AbstractTreeDisplay() = default;
+ static std::unique_ptr<AbstractTreeDisplay> createFromDisplayMode(
+ int /*eSpaceOutliner_Mode*/ mode, SpaceOutliner &space_outliner);
+
/**
* Build a tree for this display mode with the Blender context data given in \a source_data and
* the view settings in \a space_outliner.
*/
virtual ListBase buildTree(const TreeSourceData &source_data) = 0;
+ /** Accessor to whether given tree has some warnings to display. */
+ bool hasWarnings() const;
+
protected:
+ bool has_warnings = false;
+
/** All derived classes will need a handle to this, so storing it in the base for convenience. */
SpaceOutliner &space_outliner_;
};
@@ -105,7 +132,7 @@ class TreeDisplayLibraries final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
private:
- TreeElement *add_library_contents(Main &, ListBase &, Library *) const;
+ TreeElement *add_library_contents(Main &, ListBase &, Library *);
bool library_id_filter_poll(const Library *lib, ID *id) const;
short id_filter_get() const;
};
@@ -123,7 +150,7 @@ class TreeDisplayOverrideLibrary final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
private:
- TreeElement *add_library_contents(Main &, ListBase &, Library *) const;
+ TreeElement *add_library_contents(Main &, ListBase &, Library *);
bool override_library_id_filter_poll(const Library *lib, ID *id) const;
short id_filter_get() const;
};
diff --git a/source/blender/editors/space_outliner/tree/tree_display_data.cc b/source/blender/editors/space_outliner/tree/tree_display_data.cc
index 8a5c2e7d9f3..5c88e88bd37 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_data.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_data.cc
@@ -21,10 +21,13 @@
#include "BLI_listbase.h"
#include "BLI_mempool.h"
+#include "DNA_space_types.h"
+
#include "RNA_access.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
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 836f0937cf4..1d77e82612d 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
@@ -25,11 +25,14 @@
#include "BKE_main.h"
#include "DNA_collection_types.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
@@ -104,9 +107,7 @@ ListBase TreeDisplayLibraries::buildTree(const TreeSourceData &source_data)
return tree;
}
-TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
- ListBase &lb,
- Library *lib) const
+TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase &lb, Library *lib)
{
const short filter_id_type = id_filter_get();
@@ -149,6 +150,9 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar,
tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
tenlib->name = IFACE_("Current File");
}
+ if (tenlib->flag & TE_HAS_WARNING) {
+ has_warnings = true;
+ }
}
/* Create data-block list parent element on demand. */
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 eeb3ca6893a..587f807c40c 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc
@@ -19,6 +19,7 @@
*/
#include "DNA_ID.h"
+#include "DNA_space_types.h"
#include "BLI_listbase.h"
#include "BLI_listbase_wrapper.hh"
@@ -26,8 +27,10 @@
#include "BKE_main.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::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 943e182277c..d9a0661d3b4 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
@@ -25,11 +25,14 @@
#include "BKE_main.h"
#include "DNA_collection_types.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
@@ -112,7 +115,7 @@ ListBase TreeDisplayOverrideLibrary::buildTree(const TreeSourceData &source_data
TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
ListBase &lb,
- Library *lib) const
+ Library *lib)
{
const short filter_id_type = id_filter_get();
@@ -152,6 +155,9 @@ TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
tenlib->name = IFACE_("Current File");
}
+ if (tenlib->flag & TE_HAS_WARNING) {
+ has_warnings = true;
+ }
}
/* Create data-block list parent element on demand. */
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 29442aace37..ad66e8a7ee5 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc
@@ -18,14 +18,18 @@
* \ingroup spoutliner
*/
+#include "DNA_space_types.h"
+
#include "BLI_listbase.h"
#include "BLI_listbase_wrapper.hh"
#include "BLI_mempool.h"
#include "BKE_main.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::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 aa28b164584..7c5137a72dd 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc
@@ -24,10 +24,14 @@
#include "BLI_listbase_wrapper.hh"
#include "BLI_utildefines.h"
+#include "DNA_sequence_types.h"
+#include "DNA_space_types.h"
+
#include "SEQ_sequencer.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc
index ebbc9baaa9f..73990b45562 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
@@ -22,6 +22,7 @@
#include "DNA_collection_types.h"
#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "BKE_layer.h"
@@ -32,8 +33,10 @@
#include "BLT_translation.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_display.hh"
+#include "tree_element.hh"
namespace blender::ed::outliner {
diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc
index 36da7fe1944..5685d8964f5 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element.cc
@@ -20,6 +20,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
+
+#include "UI_resources.h"
+
+#include "BLT_translation.h"
#include "tree_element_anim_data.hh"
#include "tree_element_collection.hh"
@@ -28,15 +33,19 @@
#include "tree_element_id.hh"
#include "tree_element_nla.hh"
#include "tree_element_overrides.hh"
+#include "tree_element_rna.hh"
#include "tree_element_scene_objects.hh"
+#include "tree_element_seq.hh"
#include "tree_element_view_layer.hh"
-#include "tree_element.h"
+#include "../outliner_intern.hh"
#include "tree_element.hh"
namespace blender::ed::outliner {
-static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te, void *idv)
+std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const int type,
+ TreeElement &legacy_te,
+ void *idv)
{
ID &id = *static_cast<ID *>(idv);
@@ -56,28 +65,46 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te
case TSE_SOME_ID:
return TreeElementID::createFromID(legacy_te, id);
case TSE_ANIM_DATA:
- return new TreeElementAnimData(legacy_te, *reinterpret_cast<IdAdtTemplate &>(id).adt);
+ return std::make_unique<TreeElementAnimData>(legacy_te,
+ *reinterpret_cast<IdAdtTemplate &>(id).adt);
case TSE_DRIVER_BASE:
- return new TreeElementDriverBase(legacy_te, *static_cast<AnimData *>(idv));
+ return std::make_unique<TreeElementDriverBase>(legacy_te, *static_cast<AnimData *>(idv));
case TSE_NLA:
- return new TreeElementNLA(legacy_te, *static_cast<AnimData *>(idv));
+ return std::make_unique<TreeElementNLA>(legacy_te, *static_cast<AnimData *>(idv));
case TSE_NLA_TRACK:
- return new TreeElementNLATrack(legacy_te, *static_cast<NlaTrack *>(idv));
+ return std::make_unique<TreeElementNLATrack>(legacy_te, *static_cast<NlaTrack *>(idv));
case TSE_NLA_ACTION:
- return new TreeElementNLAAction(legacy_te, *static_cast<bAction *>(idv));
+ return std::make_unique<TreeElementNLAAction>(legacy_te, *static_cast<bAction *>(idv));
case TSE_GP_LAYER:
- return new TreeElementGPencilLayer(legacy_te, *static_cast<bGPDlayer *>(idv));
+ return std::make_unique<TreeElementGPencilLayer>(legacy_te, *static_cast<bGPDlayer *>(idv));
case TSE_R_LAYER_BASE:
- return new TreeElementViewLayerBase(legacy_te, *static_cast<Scene *>(idv));
+ return std::make_unique<TreeElementViewLayerBase>(legacy_te, *static_cast<Scene *>(idv));
case TSE_SCENE_COLLECTION_BASE:
- return new TreeElementCollectionBase(legacy_te, *static_cast<Scene *>(idv));
+ return std::make_unique<TreeElementCollectionBase>(legacy_te, *static_cast<Scene *>(idv));
case TSE_SCENE_OBJECTS_BASE:
- return new TreeElementSceneObjectsBase(legacy_te, *static_cast<Scene *>(idv));
+ return std::make_unique<TreeElementSceneObjectsBase>(legacy_te, *static_cast<Scene *>(idv));
case TSE_LIBRARY_OVERRIDE_BASE:
- return new TreeElementOverridesBase(legacy_te, id);
+ return std::make_unique<TreeElementOverridesBase>(legacy_te, id);
case TSE_LIBRARY_OVERRIDE:
- return new TreeElementOverridesProperty(legacy_te,
- *static_cast<TreeElementOverridesData *>(idv));
+ return std::make_unique<TreeElementOverridesProperty>(
+ legacy_te, *static_cast<TreeElementOverridesData *>(idv));
+ case TSE_RNA_STRUCT:
+ return std::make_unique<TreeElementRNAStruct>(legacy_te,
+ *reinterpret_cast<PointerRNA *>(idv));
+ case TSE_RNA_PROPERTY:
+ return std::make_unique<TreeElementRNAProperty>(
+ legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index);
+ case TSE_RNA_ARRAY_ELEM:
+ return std::make_unique<TreeElementRNAArrayElement>(
+ legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index);
+ case TSE_SEQUENCE:
+ return std::make_unique<TreeElementSequence>(legacy_te, *reinterpret_cast<Sequence *>(idv));
+ case TSE_SEQ_STRIP:
+ return std::make_unique<TreeElementSequenceStrip>(legacy_te,
+ *reinterpret_cast<Strip *>(idv));
+ case TSE_SEQUENCE_DUP:
+ return std::make_unique<TreeElementSequenceStripDuplicate>(
+ legacy_te, *reinterpret_cast<Sequence *>(idv));
default:
break;
}
@@ -85,14 +112,7 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te
return nullptr;
}
-static void tree_element_free(AbstractTreeElement **tree_element)
-{
- delete *tree_element;
- *tree_element = nullptr;
-}
-
-static void tree_element_expand(const AbstractTreeElement &tree_element,
- SpaceOutliner &space_outliner)
+void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner)
{
/* Most types can just expand. IDs optionally expand (hence the poll) and do additional, common
* expanding. Could be done nicer, we could request a small "expander" helper object from the
@@ -104,58 +124,39 @@ static void tree_element_expand(const AbstractTreeElement &tree_element,
tree_element.postExpand(space_outliner);
}
-/**
- * Needed for types that still expand in C, but need to execute the same post-expand logic. Can be
- * removed once all ID types expand entirely using the new design.
- */
-static void tree_element_post_expand_only(const AbstractTreeElement &tree_element,
- SpaceOutliner &space_outliner)
+bool tree_element_warnings_get(TreeElement *te, int *r_icon, const char **r_message)
{
- tree_element.postExpand(space_outliner);
-}
-/**
- * Needed for types that still expand in C, to poll if they should expand in current context. Can
- * be removed once all ID types expand entirely using the new design.
- */
-static bool tree_element_expand_poll(const AbstractTreeElement &tree_element,
- const SpaceOutliner &space_outliner)
-{
- return tree_element.expandPoll(space_outliner);
-}
+ TreeStoreElem *tselem = te->store_elem;
-} // namespace blender::ed::outliner
-
-namespace outliner = blender::ed::outliner;
-
-TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv)
-{
- outliner::AbstractTreeElement *element = outliner::tree_element_create(type, *legacy_te, idv);
- return reinterpret_cast<TreeElementType *>(element);
-}
+ if (tselem->type != TSE_SOME_ID) {
+ return false;
+ }
+ if (te->idcode != ID_LI) {
+ return false;
+ }
-void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner)
-{
- outliner::tree_element_expand(reinterpret_cast<outliner::AbstractTreeElement &>(*type),
- *space_outliner);
-}
-bool outliner_tree_element_type_is_expand_valid(TreeElementType *type)
-{
- outliner::AbstractTreeElement &element = reinterpret_cast<outliner::AbstractTreeElement &>(
- *type);
- return element.isExpandValid();
-}
-bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner)
-{
- return outliner::tree_element_expand_poll(
- reinterpret_cast<outliner::AbstractTreeElement &>(*type), *space_outliner);
-}
-void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner)
-{
- outliner::tree_element_post_expand_only(reinterpret_cast<outliner::AbstractTreeElement &>(*type),
- *space_outliner);
+ Library *library = (Library *)tselem->id;
+ if (library->tag & LIBRARY_TAG_RESYNC_REQUIRED) {
+ if (r_icon) {
+ *r_icon = ICON_ERROR;
+ }
+ if (r_message) {
+ *r_message = TIP_(
+ "Contains linked library overrides that need to be resynced, updating the library is "
+ "recommended");
+ }
+ return true;
+ }
+ if (library->id.tag & LIB_TAG_MISSING) {
+ if (r_icon) {
+ *r_icon = ICON_ERROR;
+ }
+ if (r_message) {
+ *r_message = TIP_("Missing library");
+ }
+ return true;
+ }
+ return false;
}
-void outliner_tree_element_type_free(TreeElementType **type)
-{
- outliner::tree_element_free(reinterpret_cast<outliner::AbstractTreeElement **>(type));
-}
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h
deleted file mode 100644
index 8e5b02278cc..00000000000
--- a/source/blender/editors/space_outliner/tree/tree_element.h
+++ /dev/null
@@ -1,48 +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.
- */
-
-/** \file
- * \ingroup spoutliner
- *
- * C-API for the Tree-Element types.
- * This API shouldn't stay for long. All tree building should eventually be done through C++ types,
- * with more type safety and an easier to reason about design.
- */
-
-#pragma once
-
-#include "DNA_space_types.h"
-
-struct TreeElement;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** C alias for an #AbstractTreeElement handle. */
-typedef struct TreeElementType TreeElementType;
-
-TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv);
-void outliner_tree_element_type_free(TreeElementType **type);
-
-void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner);
-bool outliner_tree_element_type_is_expand_valid(TreeElementType *type);
-bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner);
-void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh
index 09bd0eec05d..aca5738b91a 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element.hh
@@ -20,7 +20,11 @@
#pragma once
-#include "tree_element.h"
+#include <memory>
+
+struct ListBase;
+struct SpaceOutliner;
+struct TreeElement;
namespace blender::ed::outliner {
@@ -39,6 +43,10 @@ class AbstractTreeElement {
public:
virtual ~AbstractTreeElement() = default;
+ static std::unique_ptr<AbstractTreeElement> createFromType(int type,
+ TreeElement &legacy_te,
+ void *idv);
+
/**
* Check if the type is expandable in current context.
*/
@@ -46,12 +54,6 @@ class AbstractTreeElement {
{
return true;
}
- /**
- * Let the type add its own children.
- */
- virtual void expand(SpaceOutliner &) const
- {
- }
virtual void postExpand(SpaceOutliner &) const
{
}
@@ -65,11 +67,46 @@ class AbstractTreeElement {
return true;
}
+ friend void tree_element_expand(const AbstractTreeElement &tree_element,
+ SpaceOutliner &space_outliner);
+
protected:
/* Pseudo-abstract: Only allow creation through derived types. */
AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te)
{
}
+
+ /**
+ * Let the type add its own children.
+ */
+ virtual void expand(SpaceOutliner &) const
+ {
+ }
};
+/**
+ * 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);
+
+void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner);
+
+/**
+ * Get actual warning data of a tree element, if any.
+ *
+ * \param r_icon The icon to display as warning.
+ * \param r_message The message to display as warning.
+ * \return true if there is a warning, false otherwise.
+ */
+bool tree_element_warnings_get(struct TreeElement *te, int *r_icon, const char **r_message);
+
} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
index c0fef7c98e2..41212f61d5d 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc
@@ -22,11 +22,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_outliner_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_anim_data.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.cc b/source/blender/editors/space_outliner/tree/tree_element_collection.cc
index 1add61db7f1..0a7ee21df15 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_collection.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_collection.cc
@@ -19,11 +19,12 @@
*/
#include "DNA_listBase.h"
+#include "DNA_outliner_types.h"
+#include "DNA_scene_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_collection.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver.cc b/source/blender/editors/space_outliner/tree/tree_element_driver.cc
index 42f51908eaa..49d7f91b557 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_driver.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_driver.cc
@@ -24,11 +24,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_driver.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
index 91e6fdcde4b..ead83ad6931 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc
@@ -21,8 +21,9 @@
#include "BLI_utildefines.h"
#include "DNA_gpencil_types.h"
+#include "DNA_space_types.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_element_gpencil_layer.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc
index 7ff5a3285f1..afbbd171cf4 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc
@@ -19,6 +19,7 @@
*/
#include "DNA_ID.h"
+#include "DNA_space_types.h"
#include "BLI_listbase_wrapper.hh"
#include "BLI_utildefines.h"
@@ -29,8 +30,8 @@
#include "RNA_access.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_element_id_library.hh"
#include "tree_element_id_scene.hh"
@@ -38,13 +39,13 @@
namespace blender::ed::outliner {
-TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
+std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
{
switch (ID_Type type = GS(id.name); type) {
case ID_LI:
- return new TreeElementIDLibrary(legacy_te, (Library &)id);
+ return std::make_unique<TreeElementIDLibrary>(legacy_te, (Library &)id);
case ID_SCE:
- return new TreeElementIDScene(legacy_te, (Scene &)id);
+ return std::make_unique<TreeElementIDScene>(legacy_te, (Scene &)id);
case ID_OB:
case ID_ME:
case ID_CU:
@@ -82,7 +83,7 @@ TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
case ID_PAL:
case ID_PC:
case ID_CF:
- return new TreeElementID(legacy_te, id);
+ return std::make_unique<TreeElementID>(legacy_te, id);
/* Deprecated */
case ID_IP:
BLI_assert_msg(0, "Outliner trying to build tree-element for deprecated ID type");
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh
index b3b5ca2770c..9b5b955be0b 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh
@@ -24,6 +24,9 @@
#include "tree_element.hh"
+struct AnimData;
+struct ID;
+
namespace blender::ed::outliner {
class TreeElementID : public AbstractTreeElement {
@@ -33,7 +36,7 @@ class TreeElementID : public AbstractTreeElement {
public:
TreeElementID(TreeElement &legacy_te, ID &id);
- static TreeElementID *createFromID(TreeElement &legacy_te, ID &id);
+ static std::unique_ptr<TreeElementID> createFromID(TreeElement &legacy_te, ID &id);
void postExpand(SpaceOutliner &) const override;
bool expandPoll(const SpaceOutliner &) const override;
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
index 36f536c9845..b5fd67d4807 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc
@@ -18,9 +18,10 @@
* \ingroup spoutliner
*/
+#include "DNA_ID.h"
#include "DNA_listBase.h"
-#include "../outliner_intern.h"
+#include "../outliner_intern.hh"
#include "tree_element_id_library.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
index 88660cd8aa9..ce128b1a5ff 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh
@@ -22,6 +22,8 @@
#include "tree_element_id.hh"
+struct Library;
+
namespace blender::ed::outliner {
class TreeElementIDLibrary final : public TreeElementID {
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
index ae81b44a1e4..c71d6786c6e 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc
@@ -19,9 +19,10 @@
*/
#include "DNA_listBase.h"
+#include "DNA_outliner_types.h"
+#include "DNA_scene_types.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_id_scene.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.cc b/source/blender/editors/space_outliner/tree/tree_element_nla.cc
index 65832e8f981..89ebee49192 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_nla.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_nla.cc
@@ -22,11 +22,11 @@
#include "DNA_anim_types.h"
#include "DNA_listBase.h"
+#include "DNA_space_types.h"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_nla.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
index 731beb3956e..ba1471625b9 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -27,10 +27,11 @@
#include "BLT_translation.h"
+#include "DNA_space_types.h"
+
#include "RNA_access.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_overrides.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.cc b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
new file mode 100644
index 00000000000..7a9f1b6f0fa
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
@@ -0,0 +1,268 @@
+/*
+ * 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 spoutliner
+ */
+
+#include <climits>
+#include <iostream>
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_outliner_types.h"
+#include "DNA_space_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "../outliner_intern.hh"
+
+#include "tree_element_rna.hh"
+
+namespace blender::ed::outliner {
+
+/* Don't display arrays larger, weak but index is stored as a short,
+ * also the outliner isn't intended for editing such large data-sets. */
+BLI_STATIC_ASSERT(sizeof(TreeElement::index) == 2, "Index is no longer short!")
+
+/* -------------------------------------------------------------------- */
+/* Common functionality (#TreeElementRNACommon Base Class) */
+
+TreeElementRNACommon::TreeElementRNACommon(TreeElement &legacy_te, PointerRNA &rna_ptr)
+ : AbstractTreeElement(legacy_te), rna_ptr_(rna_ptr)
+{
+ /* Create an empty tree-element. */
+ if (!isRNAValid()) {
+ legacy_te_.name = IFACE_("(empty)");
+ return;
+ }
+}
+
+bool TreeElementRNACommon::isExpandValid() const
+{
+ return true;
+}
+
+bool TreeElementRNACommon::isRNAValid() const
+{
+ return rna_ptr_.data != nullptr;
+}
+
+bool TreeElementRNACommon::expandPoll(const SpaceOutliner &) const
+{
+ return isRNAValid();
+}
+
+const PointerRNA &TreeElementRNACommon::getPointerRNA() const
+{
+ return rna_ptr_;
+}
+
+PropertyRNA *TreeElementRNACommon::getPropertyRNA() const
+{
+ return nullptr;
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Struct */
+
+TreeElementRNAStruct::TreeElementRNAStruct(TreeElement &legacy_te, PointerRNA &rna_ptr)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_RNA_STRUCT);
+
+ if (!isRNAValid()) {
+ return;
+ }
+
+ legacy_te_.name = RNA_struct_name_get_alloc(&rna_ptr, nullptr, 0, nullptr);
+ if (legacy_te_.name) {
+ legacy_te_.flag |= TE_FREE_NAME;
+ }
+ else {
+ legacy_te_.name = RNA_struct_ui_name(rna_ptr.type);
+ }
+}
+
+void TreeElementRNAStruct::expand(SpaceOutliner &space_outliner) const
+{
+ TreeStoreElem &tselem = *TREESTORE(&legacy_te_);
+ PointerRNA ptr = rna_ptr_;
+
+ /* If searching don't expand RNA entries */
+ if (SEARCHING_OUTLINER(&space_outliner) && BLI_strcasecmp("RNA", legacy_te_.name) == 0) {
+ tselem.flag &= ~TSE_CHILDSEARCH;
+ }
+
+ PropertyRNA *iterprop = RNA_struct_iterator_property(ptr.type);
+ int tot = RNA_property_collection_length(&ptr, iterprop);
+ CLAMP_MAX(tot, max_index);
+
+ TreeElementRNAProperty *parent_prop_te = legacy_te_.parent ?
+ tree_element_cast<TreeElementRNAProperty>(
+ legacy_te_.parent) :
+ nullptr;
+ /* auto open these cases */
+ if (!parent_prop_te || (RNA_property_type(parent_prop_te->getPropertyRNA()) == PROP_POINTER)) {
+ if (!tselem.used) {
+ tselem.flag &= ~TSE_CLOSED;
+ }
+ }
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ PointerRNA propptr;
+ RNA_property_collection_lookup_int(&ptr, iterprop, index, &propptr);
+ if (!(RNA_property_flag(reinterpret_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &ptr, &legacy_te_, TSE_RNA_PROPERTY, index);
+ }
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Property */
+
+TreeElementRNAProperty::TreeElementRNAProperty(TreeElement &legacy_te,
+ PointerRNA &rna_ptr,
+ const int index)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_RNA_PROPERTY);
+
+ if (!isRNAValid()) {
+ return;
+ }
+
+ PointerRNA propptr;
+ PropertyRNA *iterprop = RNA_struct_iterator_property(rna_ptr.type);
+ RNA_property_collection_lookup_int(&rna_ptr, iterprop, index, &propptr);
+
+ PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(propptr.data);
+
+ legacy_te_.name = RNA_property_ui_name(prop);
+ rna_prop_ = prop;
+}
+
+void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const
+{
+ TreeStoreElem &tselem = *TREESTORE(&legacy_te_);
+ PointerRNA rna_ptr = rna_ptr_;
+ PropertyType proptype = RNA_property_type(rna_prop_);
+
+ /* If searching don't expand RNA entries */
+ if (SEARCHING_OUTLINER(&space_outliner) && BLI_strcasecmp("RNA", legacy_te_.name) == 0) {
+ tselem.flag &= ~TSE_CHILDSEARCH;
+ }
+
+ if (proptype == PROP_POINTER) {
+ PointerRNA pptr = RNA_property_pointer_get(&rna_ptr, rna_prop_);
+
+ if (pptr.data) {
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, -1);
+ }
+ else {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+ }
+ else if (proptype == PROP_COLLECTION) {
+ int tot = RNA_property_collection_length(&rna_ptr, rna_prop_);
+ CLAMP_MAX(tot, max_index);
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ PointerRNA pptr;
+ RNA_property_collection_lookup_int(&rna_ptr, rna_prop_, index, &pptr);
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, index);
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+ else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ int tot = RNA_property_array_length(&rna_ptr, rna_prop_);
+ CLAMP_MAX(tot, max_index);
+
+ if (TSELEM_OPEN(&tselem, &space_outliner)) {
+ for (int index = 0; index < tot; index++) {
+ outliner_add_element(&space_outliner,
+ &legacy_te_.subtree,
+ &rna_ptr,
+ &legacy_te_,
+ TSE_RNA_ARRAY_ELEM,
+ index);
+ }
+ }
+ else if (tot) {
+ legacy_te_.flag |= TE_LAZY_CLOSED;
+ }
+ }
+}
+
+PropertyRNA *TreeElementRNAProperty::getPropertyRNA() const
+{
+ return rna_prop_;
+}
+
+/* -------------------------------------------------------------------- */
+/* RNA Array Element */
+
+TreeElementRNAArrayElement::TreeElementRNAArrayElement(TreeElement &legacy_te,
+ PointerRNA &rna_ptr,
+ const int index)
+ : TreeElementRNACommon(legacy_te, rna_ptr)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_RNA_ARRAY_ELEM);
+
+ BLI_assert(legacy_te.parent && (legacy_te.parent->store_elem->type == TSE_RNA_PROPERTY));
+ legacy_te_.index = index;
+
+ char c = RNA_property_array_item_char(TreeElementRNAArrayElement::getPropertyRNA(), index);
+
+ legacy_te_.name = reinterpret_cast<char *>(
+ MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName"));
+ if (c) {
+ sprintf((char *)legacy_te_.name, " %c", c);
+ }
+ else {
+ sprintf((char *)legacy_te_.name, " %d", index + 1);
+ }
+ legacy_te_.flag |= TE_FREE_NAME;
+}
+
+PropertyRNA *TreeElementRNAArrayElement::getPropertyRNA() const
+{
+ /* Forward query to the parent (which is expected to be a #TreeElementRNAProperty). */
+ const TreeElementRNAProperty *parent_prop_te = tree_element_cast<TreeElementRNAProperty>(
+ legacy_te_.parent);
+ return parent_prop_te ? parent_prop_te->getPropertyRNA() : nullptr;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.hh b/source/blender/editors/space_outliner/tree/tree_element_rna.hh
new file mode 100644
index 00000000000..1f107ddbf88
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_rna.hh
@@ -0,0 +1,86 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include <limits>
+
+#include "RNA_types.h"
+
+#include "tree_element.hh"
+
+struct PointerRNA;
+
+namespace blender::ed::outliner {
+
+/**
+ * Base class for common behavior of RNA tree elements.
+ */
+class TreeElementRNACommon : public AbstractTreeElement {
+ protected:
+ constexpr static int max_index = std::numeric_limits<short>::max();
+ PointerRNA rna_ptr_;
+
+ public:
+ TreeElementRNACommon(TreeElement &legacy_te, PointerRNA &rna_ptr);
+ bool isExpandValid() const override;
+ bool expandPoll(const SpaceOutliner &) const override;
+
+ const PointerRNA &getPointerRNA() const;
+ /**
+ * If this element represents a property or is part of a property (array element), this returns
+ * the property. Otherwise nullptr.
+ */
+ virtual PropertyRNA *getPropertyRNA() const;
+
+ bool isRNAValid() const;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAStruct : public TreeElementRNACommon {
+ public:
+ TreeElementRNAStruct(TreeElement &legacy_te, PointerRNA &rna_ptr);
+ void expand(SpaceOutliner &space_outliner) const override;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAProperty : public TreeElementRNACommon {
+ private:
+ PropertyRNA *rna_prop_ = nullptr;
+
+ public:
+ TreeElementRNAProperty(TreeElement &legacy_te, PointerRNA &rna_ptr, int index);
+ void expand(SpaceOutliner &space_outliner) const override;
+
+ PropertyRNA *getPropertyRNA() const override;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementRNAArrayElement : public TreeElementRNACommon {
+ public:
+ TreeElementRNAArrayElement(TreeElement &legacy_te, PointerRNA &rna_ptr, int index);
+
+ PropertyRNA *getPropertyRNA() const override;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
index a46e8de1bdd..dad03d392fb 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc
@@ -24,8 +24,10 @@
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "DNA_outliner_types.h"
+
+#include "../outliner_intern.hh"
+#include "common.hh"
#include "tree_element_scene_objects.hh"
diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
index a2aa29c4a33..7ce5a404f5c 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh
@@ -22,6 +22,8 @@
#include "tree_element.hh"
+struct Scene;
+
namespace blender::ed::outliner {
class TreeElementSceneObjectsBase final : public AbstractTreeElement {
diff --git a/source/blender/editors/space_outliner/tree/tree_element_seq.cc b/source/blender/editors/space_outliner/tree/tree_element_seq.cc
new file mode 100644
index 00000000000..8d0b4c140c7
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_seq.cc
@@ -0,0 +1,111 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spoutliner
+ */
+
+#include "DNA_outliner_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BLT_translation.h"
+
+#include "../outliner_intern.hh"
+#include "tree_element_seq.hh"
+
+namespace blender::ed::outliner {
+
+TreeElementSequence::TreeElementSequence(TreeElement &legacy_te, Sequence &sequence)
+ : AbstractTreeElement(legacy_te), sequence_(sequence)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SEQUENCE);
+
+ /*
+ * The idcode is a little hack, but the outliner
+ * only check te->idcode if te->type is equal to zero,
+ * so this is "safe".
+ */
+ legacy_te.idcode = sequence_.type;
+ legacy_te.name = sequence_.name + 2;
+}
+
+bool TreeElementSequence::expandPoll(const SpaceOutliner & /*space_outliner*/) const
+{
+ return !(sequence_.type & SEQ_TYPE_EFFECT);
+}
+
+void TreeElementSequence::expand(SpaceOutliner &space_outliner) const
+{
+ /*
+ * This work like the sequence.
+ * If the sequence have a name (not default name)
+ * show it, in other case put the filename.
+ */
+
+ if (sequence_.type == SEQ_TYPE_META) {
+ LISTBASE_FOREACH (Sequence *, child, &sequence_.seqbase) {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, child, &legacy_te_, TSE_SEQUENCE, 0);
+ }
+ }
+ else {
+ outliner_add_element(
+ &space_outliner, &legacy_te_.subtree, sequence_.strip, &legacy_te_, TSE_SEQ_STRIP, 0);
+ }
+}
+
+Sequence &TreeElementSequence::getSequence() const
+{
+ return sequence_;
+}
+
+/* -------------------------------------------------------------------- */
+/* Strip */
+
+TreeElementSequenceStrip::TreeElementSequenceStrip(TreeElement &legacy_te, Strip &strip)
+ : AbstractTreeElement(legacy_te)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SEQ_STRIP);
+
+ if (strip.dir[0] != '\0') {
+ legacy_te_.name = strip.dir;
+ }
+ else {
+ legacy_te_.name = IFACE_("Strip None");
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* Strip Duplicate */
+
+TreeElementSequenceStripDuplicate::TreeElementSequenceStripDuplicate(TreeElement &legacy_te,
+ Sequence &sequence)
+ : AbstractTreeElement(legacy_te), sequence_(sequence)
+{
+ BLI_assert(legacy_te.store_elem->type == TSE_SEQUENCE_DUP);
+
+ legacy_te_.idcode = sequence.type;
+ legacy_te_.name = sequence.strip->stripdata->name;
+}
+
+Sequence &TreeElementSequenceStripDuplicate::getSequence() const
+{
+ return sequence_;
+}
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_seq.hh b/source/blender/editors/space_outliner/tree/tree_element_seq.hh
new file mode 100644
index 00000000000..2b334b5b7fa
--- /dev/null
+++ b/source/blender/editors/space_outliner/tree/tree_element_seq.hh
@@ -0,0 +1,60 @@
+/*
+ * 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 spoutliner
+ */
+
+#pragma once
+
+#include "tree_element.hh"
+
+struct Sequence;
+struct Strip;
+
+namespace blender::ed::outliner {
+
+class TreeElementSequence : public AbstractTreeElement {
+ Sequence &sequence_;
+
+ public:
+ TreeElementSequence(TreeElement &legacy_te, Sequence &sequence);
+
+ bool expandPoll(const SpaceOutliner &) const override;
+ void expand(SpaceOutliner &) const override;
+
+ Sequence &getSequence() const;
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementSequenceStrip : public AbstractTreeElement {
+ public:
+ TreeElementSequenceStrip(TreeElement &legacy_te, Strip &strip);
+};
+
+/* -------------------------------------------------------------------- */
+
+class TreeElementSequenceStripDuplicate : public AbstractTreeElement {
+ Sequence &sequence_;
+
+ public:
+ TreeElementSequenceStripDuplicate(TreeElement &legacy_te, Sequence &sequence);
+
+ Sequence &getSequence() const;
+};
+
+} // namespace blender::ed::outliner
diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
index 7bb9405147e..65786ac89ed 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc
@@ -19,13 +19,14 @@
*/
#include "DNA_layer_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
#include "BLI_listbase_wrapper.hh"
#include "BLT_translation.h"
-#include "../outliner_intern.h"
-#include "tree_display.h"
+#include "../outliner_intern.hh"
#include "tree_element_view_layer.hh"
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 616953e720a..72c39839739 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -59,6 +59,7 @@
#include "SEQ_add.h"
#include "SEQ_effects.h"
+#include "SEQ_iterator.h"
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
@@ -601,35 +602,48 @@ static IMB_Proxy_Size seq_get_proxy_size_flags(bContext *C)
return proxy_sizes;
}
-static void seq_build_proxy(bContext *C, Sequence *seq)
+static void seq_build_proxy(bContext *C, SeqCollection *movie_strips)
{
if (U.sequencer_proxy_setup != USER_SEQ_PROXY_SETUP_AUTOMATIC) {
return;
}
- /* Enable and set proxy size. */
- SEQ_proxy_set(seq, true);
- seq->strip->proxy->build_size_flags = seq_get_proxy_size_flags(C);
- seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
-
- /* Build proxy. */
- GSet *file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
wmJob *wm_job = ED_seq_proxy_wm_job_get(C);
ProxyJob *pj = ED_seq_proxy_job_get(C, wm_job);
- SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
- BLI_gset_free(file_list, MEM_freeN);
+
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, movie_strips) {
+ /* Enable and set proxy size. */
+ SEQ_proxy_set(seq, true);
+ seq->strip->proxy->build_size_flags = seq_get_proxy_size_flags(C);
+ seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
+ SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, NULL, &pj->queue, true);
+ }
if (!WM_jobs_is_running(wm_job)) {
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
-
ED_area_tag_redraw(CTX_wm_area(C));
}
+static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene,
+ ListBase *seqbase,
+ Sequence *seq_movie,
+ Sequence *seq_sound)
+{
+ if (ELEM(NULL, seq_movie, seq_sound) || seq_sound->len <= seq_movie->len) {
+ return;
+ }
+
+ SEQ_transform_set_right_handle_frame(seq_sound, SEQ_transform_get_right_handle_frame(seq_movie));
+ SEQ_time_update_sequence(scene, seqbase, seq_sound);
+}
+
static void sequencer_add_movie_multiple_strips(bContext *C,
wmOperator *op,
- SeqLoadData *load_data)
+ SeqLoadData *load_data,
+ SeqCollection *r_movie_strips)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -689,15 +703,19 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
else {
load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp;
}
+ sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
- seq_build_proxy(C, seq_movie);
+ SEQ_collection_append_strip(seq_movie, r_movie_strips);
}
}
RNA_END;
}
-static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoadData *load_data)
+static bool sequencer_add_movie_single_strip(bContext *C,
+ wmOperator *op,
+ SeqLoadData *load_data,
+ SeqCollection *r_movie_strips)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -740,9 +758,10 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa
load_data->start_frame += audio_frame_offset;
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, audio_skip);
}
+ sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
- seq_build_proxy(C, seq_movie);
+ SEQ_collection_append_strip(seq_movie, r_movie_strips);
return true;
}
@@ -759,21 +778,25 @@ static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
ED_sequencer_deselect_all(scene);
}
+ SeqCollection *movie_strips = SEQ_collection_create(__func__);
const int tot_files = RNA_property_collection_length(op->ptr,
RNA_struct_find_property(op->ptr, "files"));
if (tot_files > 1) {
- sequencer_add_movie_multiple_strips(C, op, &load_data);
+ sequencer_add_movie_multiple_strips(C, op, &load_data, movie_strips);
}
else {
- if (!sequencer_add_movie_single_strip(C, op, &load_data)) {
- sequencer_add_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
+ sequencer_add_movie_single_strip(C, op, &load_data, movie_strips);
+ }
+
+ if (SEQ_collection_len(movie_strips) == 0) {
+ SEQ_collection_free(movie_strips);
+ return OPERATOR_CANCELLED;
}
/* Free custom data. */
sequencer_add_cancel(C, op);
+ seq_build_proxy(C, movie_strips);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index e814530d1e2..6dffc0bc2a4 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -2262,28 +2262,15 @@ void sequencer_draw_preview(const bContext *C,
seq_prefetch_wm_notify(C, scene);
}
-/* Draw backdrop in sequencer timeline. */
-static void draw_seq_backdrop(View2D *v2d)
+static void draw_seq_timeline_channels(View2D *v2d)
{
- int i;
-
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- /* View backdrop. */
- immUniformThemeColor(TH_BACK);
- immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
-
- /* Darker overlay over the view backdrop. */
- immUniformThemeColorShade(TH_BACK, -10);
- immRectf(pos, v2d->cur.xmin, -1.0, v2d->cur.xmax, 1.0);
-
- /* Alternating horizontal stripes. */
- i = max_ii(1, ((int)v2d->cur.ymin) - 1);
-
GPU_blend(GPU_BLEND_ALPHA);
immUniformThemeColor(TH_ROW_ALTERNATE);
+ /* Alternating horizontal stripes. */
+ int i = max_ii(1, ((int)v2d->cur.ymin) - 1);
while (i < v2d->cur.ymax) {
if (i & 1) {
immRectf(pos, v2d->cur.xmin, i, v2d->cur.xmax, i + 1);
@@ -2295,6 +2282,14 @@ static void draw_seq_backdrop(View2D *v2d)
immUnbindProgram();
}
+static void draw_seq_timeline_channel_numbers(ARegion *region)
+{
+ View2D *v2d = &region->v2d;
+ rcti rect;
+ BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y);
+ UI_view2d_draw_scale_y__block(region, v2d, &rect, TH_SCROLL_TEXT);
+}
+
static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
{
Scene *scene = CTX_data_scene(C);
@@ -2718,7 +2713,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
}
UI_view2d_view_ortho(v2d);
- draw_seq_backdrop(v2d);
+ draw_seq_timeline_channels(v2d);
if ((sseq->flag & SEQ_SHOW_OVERLAY) && (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_GRID)) {
U.v2d_min_gridsize *= 3;
UI_view2d_draw_lines_x__discrete_frames_or_seconds(
@@ -2776,13 +2771,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
UI_view2d_view_restore(C);
ED_time_scrub_draw(region, scene, !(sseq->flag & SEQ_DRAWFRAMES), true);
- /* Draw channel numbers. */
- {
- rcti rect;
- BLI_rcti_init(
- &rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y);
- UI_view2d_draw_scale_y__block(region, v2d, &rect, TH_SCROLL_TEXT);
- }
+ draw_seq_timeline_channel_numbers(region);
}
void draw_timeline_seq_display(const bContext *C, ARegion *region)
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index e9f37fa6838..3b5e16d84a9 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -39,6 +39,7 @@
#include "DNA_sound_types.h"
#include "BKE_context.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -46,6 +47,7 @@
#include "BKE_sound.h"
#include "SEQ_add.h"
+#include "SEQ_animation.h"
#include "SEQ_clipboard.h"
#include "SEQ_edit.h"
#include "SEQ_effects.h"
@@ -66,6 +68,7 @@
#include "RNA_enum_types.h"
/* For menu, popup, icons, etc. */
+#include "ED_keyframing.h"
#include "ED_numinput.h"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -1558,7 +1561,7 @@ static int sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *ev
}
RNA_int_set(op->ptr, "channel", mouseloc[1]);
RNA_enum_set(op->ptr, "side", split_side);
- /*RNA_enum_set(op->ptr, "type", split_hard); */
+ // RNA_enum_set(op->ptr, "type", split_hard);
return sequencer_split_exec(C, op);
}
@@ -1655,6 +1658,35 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot)
/** \name Duplicate Strips Operator
* \{ */
+static void sequencer_backup_original_animation(Scene *scene, ListBase *list)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL ||
+ BLI_listbase_is_empty(&scene->adt->action->curves)) {
+ return;
+ }
+
+ BLI_movelisttolist(list, &scene->adt->action->curves);
+}
+
+static void sequencer_restore_original_animation(Scene *scene, ListBase *list)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL || BLI_listbase_is_empty(list)) {
+ return;
+ }
+
+ BLI_movelisttolist(&scene->adt->action->curves, list);
+}
+
+static void sequencer_duplicate_animation(Scene *scene, Sequence *seq, ListBase *curves_backup)
+{
+ GSet *fcurves = SEQ_fcurves_by_strip_get(seq, curves_backup);
+ GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
+ FCurve *fcu_cpy = BKE_fcurve_copy(fcu);
+ BLI_addtail(&scene->adt->action->curves, fcu_cpy);
+ }
+ GSET_FOREACH_END();
+}
+
static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1665,32 +1697,44 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
}
Sequence *active_seq = SEQ_select_active_get(scene);
- ListBase duplicated = {NULL, NULL};
+ ListBase duplicated_strips = {NULL, NULL};
- SEQ_sequence_base_dupli_recursive(scene, scene, &duplicated, ed->seqbasep, 0, 0);
+ SEQ_sequence_base_dupli_recursive(scene, scene, &duplicated_strips, ed->seqbasep, 0, 0);
ED_sequencer_deselect_all(scene);
- if (duplicated.first) {
- Sequence *seq = duplicated.first;
- /* Rely on the nseqbase list being added at the end.
- * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */
- BLI_movelisttolist(ed->seqbasep, &duplicated);
-
- /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation
- * data. */
- for (; seq; seq = seq->next) {
- if (active_seq != NULL && STREQ(seq->name, active_seq->name)) {
- SEQ_select_active_set(scene, seq);
- }
- seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
- SEQ_ensure_unique_name(seq, scene);
- }
+ if (duplicated_strips.first == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
- return OPERATOR_FINISHED;
+ /* Duplicate animation.
+ * First backup original curves from scene and duplicate strip curves from backup into scene.
+ * This way, when pasted strips are renamed, curves are renamed with them. Finally, restore
+ * original curves from backup.
+ */
+ ListBase fcurves_original_backup = {NULL, NULL};
+ sequencer_backup_original_animation(scene, &fcurves_original_backup);
+
+ Sequence *seq = duplicated_strips.first;
+
+ /* Rely on the nseqbase list being added at the end.
+ * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */
+ BLI_movelisttolist(ed->seqbasep, &duplicated_strips);
+
+ /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation
+ * data. */
+ for (; seq; seq = seq->next) {
+ if (active_seq != NULL && STREQ(seq->name, active_seq->name)) {
+ SEQ_select_active_set(scene, seq);
+ }
+ seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
+ sequencer_duplicate_animation(scene, seq, &fcurves_original_backup);
+ SEQ_ensure_unique_name(seq, scene);
}
- return OPERATOR_CANCELLED;
+ sequencer_restore_original_animation(scene, &fcurves_original_backup);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ return OPERATOR_FINISHED;
}
void SEQUENCER_OT_duplicate(wmOperatorType *ot)
@@ -1905,7 +1949,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
}
seq_next = seq->next;
- SEQ_sequence_free(scene, seq, true);
+ SEQ_edit_flag_for_removal(scene, seqbase, seq);
seq = seq_next;
}
else {
@@ -1913,6 +1957,8 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
}
}
+ SEQ_edit_remove_flagged_sequences(scene, seqbase);
+
SEQ_sort(seqbase);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -1950,6 +1996,8 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
Editing *ed = SEQ_editing_get(scene);
Sequence *active_seq = SEQ_select_active_get(scene);
+ SEQ_prefetch_stop(scene);
+
if (active_seq && active_seq->type == SEQ_TYPE_META && active_seq->flag & SELECT) {
/* Enter meta-strip. */
SEQ_meta_stack_alloc(ed, active_seq);
@@ -2439,6 +2487,22 @@ static void seq_copy_del_sound(Scene *scene, Sequence *seq)
}
}
+static void sequencer_copy_animation(Scene *scene, Sequence *seq)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL ||
+ BLI_listbase_is_empty(&scene->adt->action->curves)) {
+ return;
+ }
+
+ GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
+
+ GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
+ BLI_addtail(&fcurves_clipboard, BKE_fcurve_copy(fcu));
+ }
+ GSET_FOREACH_END();
+ BLI_gset_free(fcurves, NULL);
+}
+
static int sequencer_copy_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -2465,8 +2529,10 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
seqbase_clipboard_frame = scene->r.cfra;
SEQ_clipboard_active_seq_name_store(scene);
- /* Remove anything that references the current scene. */
LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
+ /* Copy curves. */
+ sequencer_copy_animation(scene, seq);
+ /* Remove anything that references the current scene. */
seq_copy_del_sound(scene, seq);
}
@@ -2511,6 +2577,29 @@ void ED_sequencer_deselect_all(Scene *scene)
}
}
+static void sequencer_paste_animation(bContext *C)
+{
+ if (BLI_listbase_is_empty(&fcurves_clipboard)) {
+ return;
+ }
+
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ bAction *act;
+
+ if (scene->adt != NULL && scene->adt->action != NULL) {
+ act = scene->adt->action;
+ }
+ else {
+ /* get action to add F-Curve+keyframe to */
+ act = ED_id_action_ensure(bmain, &scene->id);
+ }
+
+ LISTBASE_FOREACH (FCurve *, fcu, &fcurves_clipboard) {
+ BLI_addtail(&act->curves, BKE_fcurve_copy(fcu));
+ }
+}
+
static int sequencer_paste_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -2540,6 +2629,17 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
ofs = scene->r.cfra - min_seq_startdisp;
}
+ /* Paste animation.
+ * Note: Only fcurves are copied. Drivers and NLA action strips are not copied.
+ * First backup original curves from scene and move curves from clipboard into scene. This way,
+ * when pasted strips are renamed, pasted fcurves are renamed with them. Finally restore original
+ * curves from backup.
+ */
+
+ ListBase fcurves_original_backup = {NULL, NULL};
+ sequencer_backup_original_animation(scene, &fcurves_original_backup);
+ sequencer_paste_animation(C);
+
/* Copy strips, temporarily restoring pointers to actual data-blocks. This
* must happen on the clipboard itself, so that copying does user counting
* on the actual data-blocks. */
@@ -2569,6 +2669,8 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
}
}
+ sequencer_restore_original_animation(scene, &fcurves_original_backup);
+
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);
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index cb33c648b0a..7143a1fa1ca 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -33,13 +33,13 @@ struct ARegionType;
struct Depsgraph;
struct Main;
struct Scene;
-struct Sequence;
struct SeqCollection;
+struct Sequence;
struct SpaceSeq;
struct StripElem;
+struct View2D;
struct bContext;
struct rctf;
-struct View2D;
struct wmOperator;
#define OVERLAP_ALPHA 180
@@ -57,12 +57,12 @@ void sequencer_draw_preview(const struct bContext *C,
bool draw_backdrop);
void color3ubv_from_seq(const struct Scene *curscene,
const struct Sequence *seq,
- const bool show_strip_color_tag,
+ bool show_strip_color_tag,
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);
+float sequence_handle_size_get_clamped(struct Sequence *seq, float pixelx);
/* UNUSED */
/* void seq_reset_imageofs(struct SpaceSeq *sseq); */
diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c
index 0a8eb7cb88f..fb561025da2 100644
--- a/source/blender/editors/space_sequencer/sequencer_proxy.c
+++ b/source/blender/editors/space_sequencer/sequencer_proxy.c
@@ -85,7 +85,7 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports)
}
bool success = SEQ_proxy_rebuild_context(
- pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
+ pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue, false);
if (!success && (seq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) != 0) {
BKE_reportf(reports, RPT_WARNING, "Overwrite is not checked for %s, skipping", seq->name);
@@ -137,7 +137,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
short stop = 0, do_update;
float progress;
- SEQ_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue);
+ SEQ_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue, false);
for (link = queue.first; link; link = link->next) {
struct SeqIndexBuildContext *context = link->data;
diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
index c6fecdb1fc6..82ba17d4db1 100644
--- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c
+++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
@@ -66,7 +66,7 @@ typedef struct ThumbDataItem {
static void thumbnail_hash_data_free(void *val)
{
ThumbDataItem *item = val;
- SEQ_sequence_free(item->scene, item->seq_dupli, 0);
+ SEQ_sequence_free(item->scene, item->seq_dupli);
MEM_freeN(val);
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index b93f421ff5c..b294fdf4820 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -39,6 +39,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "BKE_sequencer_offscreen.h"
@@ -988,19 +989,12 @@ static void sequencer_buttons_region_listener(const wmRegionListenerParams *para
}
}
-static void sequencer_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void sequencer_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceSeq *sseq = (SpaceSeq *)slink;
-
- if (!ELEM(GS(old_id->name), ID_GD)) {
- return;
- }
-
- if ((ID *)sseq->gpd == old_id) {
- sseq->gpd = (bGPdata *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&sseq->gpd, ID_REMAP_APPLY_DEFAULT);
}
/* ************************************* */
diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt
index 27446fe1a94..f1db8dedf1a 100644
--- a/source/blender/editors/space_spreadsheet/CMakeLists.txt
+++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt
@@ -49,7 +49,6 @@ set(SRC
spreadsheet_row_filter_ui.cc
spreadsheet_cache.hh
- spreadsheet_cell_value.hh
spreadsheet_column.hh
spreadsheet_column_values.hh
spreadsheet_context.hh
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 0cb4a52eb2f..18f383d45fb 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -18,6 +18,7 @@
#include "BLI_listbase.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_screen.h"
@@ -60,15 +61,14 @@ using namespace blender::ed::spreadsheet;
static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
- SpaceSpreadsheet *spreadsheet_space = (SpaceSpreadsheet *)MEM_callocN(sizeof(SpaceSpreadsheet),
- "spreadsheet space");
+ SpaceSpreadsheet *spreadsheet_space = MEM_cnew<SpaceSpreadsheet>("spreadsheet space");
spreadsheet_space->spacetype = SPACE_SPREADSHEET;
spreadsheet_space->filter_flag = SPREADSHEET_FILTER_ENABLE;
{
/* Header. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet header");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
@@ -76,7 +76,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Footer. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet footer region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet footer region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_FOOTER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
@@ -84,16 +84,15 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Dataset Region */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet dataset region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet dataset region");
BLI_addtail(&spreadsheet_space->regionbase, region);
- region->regiontype = RGN_TYPE_CHANNELS;
+ region->regiontype = RGN_TYPE_TOOLS;
region->alignment = RGN_ALIGN_LEFT;
- region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
}
{
/* Properties region. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet right region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet right region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
@@ -102,7 +101,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Main window. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet main region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
}
@@ -114,7 +113,7 @@ static void spreadsheet_free(SpaceLink *sl)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- delete sspreadsheet->runtime;
+ MEM_delete(sspreadsheet->runtime);
LISTBASE_FOREACH_MUTABLE (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
spreadsheet_row_filter_free(row_filter);
@@ -131,7 +130,7 @@ static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)area->spacedata.first;
if (sspreadsheet->runtime == nullptr) {
- sspreadsheet->runtime = new SpaceSpreadsheet_Runtime();
+ sspreadsheet->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__);
}
}
@@ -140,10 +139,11 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
const SpaceSpreadsheet *sspreadsheet_old = (SpaceSpreadsheet *)sl;
SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old);
if (sspreadsheet_old->runtime) {
- sspreadsheet_new->runtime = new SpaceSpreadsheet_Runtime(*sspreadsheet_old->runtime);
+ sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__,
+ *sspreadsheet_old->runtime);
}
else {
- sspreadsheet_new->runtime = new SpaceSpreadsheet_Runtime();
+ sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__);
}
BLI_listbase_clear(&sspreadsheet_new->row_filters);
@@ -172,21 +172,23 @@ static void spreadsheet_keymap(wmKeyConfig *keyconf)
WM_keymap_ensure(keyconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
}
-static void spreadsheet_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void spreadsheet_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const IDRemapper *mappings)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)slink;
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
- if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
- SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
- if ((ID *)object_context->object == old_id) {
- if (new_id && GS(new_id->name) == ID_OB) {
- object_context->object = (Object *)new_id;
- }
- else {
- object_context->object = nullptr;
- }
- }
+ if (context->type != SPREADSHEET_CONTEXT_OBJECT) {
+ continue;
+ }
+ SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
+
+ if (object_context->object != nullptr && GS(object_context->object->id.name) != ID_OB) {
+ object_context->object = nullptr;
+ continue;
}
+
+ BKE_id_remapper_apply(mappings, ((ID **)&object_context->object), ID_REMAP_APPLY_DEFAULT);
}
}
@@ -323,6 +325,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;
}
@@ -619,7 +623,7 @@ static void spreadsheet_right_region_listener(const wmRegionListenerParams *UNUS
void ED_spacetype_spreadsheet()
{
- SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet");
+ SpaceType *st = MEM_cnew<SpaceType>("spacetype spreadsheet");
ARegionType *art;
st->spaceid = SPACE_SPREADSHEET;
@@ -634,7 +638,7 @@ void ED_spacetype_spreadsheet()
st->id_remap = spreadsheet_id_remap;
/* regions: main window */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet region");
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
@@ -644,7 +648,7 @@ void ED_spacetype_spreadsheet()
BLI_addhead(&st->regiontypes, art);
/* regions: header */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet header region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet header region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = 0;
@@ -657,7 +661,7 @@ void ED_spacetype_spreadsheet()
BLI_addhead(&st->regiontypes, art);
/* regions: footer */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet footer region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet footer region");
art->regionid = RGN_TYPE_FOOTER;
art->prefsizey = HEADERY;
art->keymapflag = 0;
@@ -670,7 +674,7 @@ void ED_spacetype_spreadsheet()
BLI_addhead(&st->regiontypes, art);
/* regions: right panel buttons */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet right region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet right region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
@@ -685,10 +689,10 @@ void ED_spacetype_spreadsheet()
register_row_filter_panels(*art);
/* regions: channels */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region");
- art->regionid = RGN_TYPE_CHANNELS;
+ art = MEM_cnew<ARegionType>("spreadsheet dataset region");
+ art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = 150 + V2D_SCROLL_WIDTH;
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
+ art->keymapflag = ED_KEYMAP_UI;
art->init = ED_region_panels_init;
art->draw = spreadsheet_dataset_region_draw;
art->listener = spreadsheet_dataset_region_listener;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_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..ede8756a9da 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -18,18 +18,54 @@
#include "MEM_guardedalloc.h"
+#include "BLI_color.hh"
#include "BLI_hash.hh"
+#include "BLI_math_vec_types.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),
- __func__);
+ SpreadsheetColumnID *column_id = MEM_cnew<SpreadsheetColumnID>(__func__);
return column_id;
}
@@ -50,8 +86,7 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id)
SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id)
{
- SpreadsheetColumn *column = (SpreadsheetColumn *)MEM_callocN(sizeof(SpreadsheetColumn),
- __func__);
+ SpreadsheetColumn *column = MEM_cnew<SpreadsheetColumn>(__func__);
column->id = column_id;
return column;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
index 1a03278acad..7dad505c21b 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh
@@ -44,7 +44,7 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id);
SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id);
SpreadsheetColumn *spreadsheet_column_copy(const SpreadsheetColumn *src_column);
void spreadsheet_column_assign_runtime_data(SpreadsheetColumn *column,
- const eSpreadsheetColumnValueType data_type,
+ eSpreadsheetColumnValueType data_type,
const StringRefNull display_name);
void spreadsheet_column_free(SpreadsheetColumn *column);
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_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
index e55a7cae6a6..5cec016b727 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
@@ -50,8 +50,7 @@ namespace blender::ed::spreadsheet {
static SpreadsheetContextObject *spreadsheet_context_object_new()
{
- SpreadsheetContextObject *context = (SpreadsheetContextObject *)MEM_callocN(
- sizeof(SpreadsheetContextObject), __func__);
+ SpreadsheetContextObject *context = MEM_cnew<SpreadsheetContextObject>(__func__);
context->base.type = SPREADSHEET_CONTEXT_OBJECT;
return context;
}
@@ -77,8 +76,7 @@ static void spreadsheet_context_object_free(SpreadsheetContextObject *context)
static SpreadsheetContextModifier *spreadsheet_context_modifier_new()
{
- SpreadsheetContextModifier *context = (SpreadsheetContextModifier *)MEM_callocN(
- sizeof(SpreadsheetContextModifier), __func__);
+ SpreadsheetContextModifier *context = MEM_cnew<SpreadsheetContextModifier>(__func__);
context->base.type = SPREADSHEET_CONTEXT_MODIFIER;
return context;
}
@@ -111,8 +109,7 @@ static void spreadsheet_context_modifier_free(SpreadsheetContextModifier *contex
static SpreadsheetContextNode *spreadsheet_context_node_new()
{
- SpreadsheetContextNode *context = (SpreadsheetContextNode *)MEM_callocN(
- sizeof(SpreadsheetContextNode), __func__);
+ SpreadsheetContextNode *context = MEM_cnew<SpreadsheetContextNode>(__func__);
context->base.type = SPREADSHEET_CONTEXT_NODE;
return context;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index 173ef43bfb6..b9b03732a40 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -14,8 +14,11 @@
* 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_global.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_wrapper.h"
@@ -51,30 +54,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 +71,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(
@@ -157,6 +104,20 @@ void GeometryDataSource::foreach_default_column_ids(
fn({(char *)"Rotation"}, false);
fn({(char *)"Scale"}, false);
}
+ else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
+ if (domain_ == ATTR_DOMAIN_EDGE) {
+ fn({(char *)"Vertex 1"}, false);
+ fn({(char *)"Vertex 2"}, false);
+ }
+ else if (domain_ == ATTR_DOMAIN_FACE) {
+ fn({(char *)"Corner Start"}, false);
+ fn({(char *)"Corner Size"}, false);
+ }
+ else if (domain_ == ATTR_DOMAIN_CORNER) {
+ fn({(char *)"Vertex"}, false);
+ fn({(char *)"Edge"}, false);
+ }
+ }
}
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
@@ -179,52 +140,72 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
if (STREQ(column_id.name, "Name")) {
Span<int> reference_handles = instances.instance_reference_handles();
Span<InstanceReference> references = instances.references();
- std::unique_ptr<ColumnValues> values = column_values_from_function(
- SPREADSHEET_VALUE_TYPE_INSTANCES,
- "Name",
- domain_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;
+ 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 column_values_from_function(
- SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- domain_size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].to_euler();
- });
+ 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 column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3,
- column_id.name,
- domain_size,
- [transforms](int index, CellValue &r_cell_value) {
- r_cell_value.value_float3 = transforms[index].scale();
- });
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) {
+ return transforms[index].scale();
+ }));
+ }
+ }
+ else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &component = static_cast<const MeshComponent &>(*component_);
+ if (const Mesh *mesh = component.get_for_read()) {
+ if (domain_ == ATTR_DOMAIN_EDGE) {
+ if (STREQ(column_id.name, "Vertex 1")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totedge, [mesh](int64_t index) {
+ return mesh->medge[index].v1;
+ }));
+ }
+ if (STREQ(column_id.name, "Vertex 2")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totedge, [mesh](int64_t index) {
+ return mesh->medge[index].v2;
+ }));
+ }
+ }
+ else if (domain_ == ATTR_DOMAIN_FACE) {
+ if (STREQ(column_id.name, "Corner Start")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totpoly, [mesh](int64_t index) {
+ return mesh->mpoly[index].loopstart;
+ }));
+ }
+ if (STREQ(column_id.name, "Corner Size")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totpoly, [mesh](int64_t index) {
+ return mesh->mpoly[index].totloop;
+ }));
+ }
+ }
+ else if (domain_ == ATTR_DOMAIN_CORNER) {
+ if (STREQ(column_id.name, "Vertex")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totloop, [mesh](int64_t index) {
+ return mesh->mloop[index].v;
+ }));
+ }
+ if (STREQ(column_id.name, "Edge")) {
+ return std::make_unique<ColumnValues>(
+ column_id.name, VArray<int>::ForFunc(mesh->totloop, [mesh](int64_t index) {
+ return mesh->mloop[index].e;
+ }));
+ }
+ }
}
}
@@ -237,71 +218,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
return {};
}
- 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
@@ -309,90 +226,9 @@ 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.
+ */
bool GeometryDataSource::has_selection_filter() const
{
Object *object_orig = DEG_get_original_object(object_eval_);
@@ -409,7 +245,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_};
@@ -425,27 +272,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);
- }
+ 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(
@@ -472,50 +330,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_("Unknown");
+ if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) {
+ return IFACE_("Level Set");
}
- },
- 5.0f);
+ return IFACE_("Unknown");
+ }));
}
#else
UNUSED_VARS(column_id);
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 23207734d2b..b5105050d2b 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -87,7 +87,7 @@ class GeometryDataSource : public DataSource {
* filtering.
*/
bool has_selection_filter() const override;
- void apply_selection_filter(MutableSpan<bool> rows_included) const;
+ 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_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
index e62835d5792..df23a27aa22 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh
@@ -36,10 +36,10 @@ struct SpaceSpreadsheet_Runtime {
}
};
-struct bContext;
struct ARegionType;
+struct bContext;
-void spreadsheet_operatortypes(void);
+void spreadsheet_operatortypes();
void spreadsheet_update_context_path(const bContext *C);
Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet,
const Depsgraph *depsgraph);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index 202523c0e64..f4b5ff819ed 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -17,8 +17,15 @@
#include <iomanip>
#include <sstream>
+#include "BLI_math_vec_types.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 +99,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 +127,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 +151,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 +171,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/editors/space_spreadsheet/spreadsheet_panels.cc b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
index 854c3d4aba6..db8265a33ce 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
@@ -25,7 +25,7 @@ namespace blender::ed::spreadsheet {
void spreadsheet_data_set_region_panels_register(ARegionType &region_type)
{
- PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_data_set");
strcpy(panel_type->label, N_("Data Set"));
strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index 1e46fef8d71..556c0b0d5ca 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,193 @@
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 math::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_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ 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 math::distance_squared(cell, value) > threshold_sq; },
+ 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_GREATER: {
apply_filter_operation(
- values,
- [value](const CellValue &cell_value) -> bool {
- return *cell_value.value_bool == value;
+ 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;
}
- case SPREADSHEET_VALUE_TYPE_INSTANCES: {
- const StringRef value = row_filter.value_string;
+ case SPREADSHEET_ROW_FILTER_LESS: {
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:
+ }
+ }
+ 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;
+ }
}
-
- /* 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<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 +251,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,35 +263,51 @@ 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()
{
- SpreadsheetRowFilter *row_filter = (SpreadsheetRowFilter *)MEM_callocN(
- sizeof(SpreadsheetRowFilter), __func__);
+ SpreadsheetRowFilter *row_filter = MEM_cnew<SpreadsheetRowFilter>(__func__);
row_filter->flag = (SPREADSHEET_ROW_FILTER_UI_EXPAND | SPREADSHEET_ROW_FILTER_ENABLED);
row_filter->operation = SPREADSHEET_ROW_FILTER_LESS;
row_filter->threshold = 0.01f;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.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..56722104b4f 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;
}
}
@@ -325,7 +331,7 @@ static void set_filter_expand_flag(const bContext *UNUSED(C), Panel *panel, shor
void register_row_filter_panels(ARegionType &region_type)
{
{
- PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_row_filters");
strcpy(panel_type->label, N_("Filters"));
strcpy(panel_type->category, "Filters");
@@ -336,7 +342,7 @@ void register_row_filter_panels(ARegionType &region_type)
}
{
- PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_filter");
strcpy(panel_type->label, "");
strcpy(panel_type->category, "Filters");
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index f449ce50ae3..7339d8248c8 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -32,6 +32,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_remap.h"
#include "BKE_screen.h"
#include "ED_screen.h"
@@ -401,18 +402,12 @@ static void text_properties_region_draw(const bContext *C, ARegion *region)
}
}
-static void text_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
+static void text_id_remap(ScrArea *UNUSED(area),
+ SpaceLink *slink,
+ const struct IDRemapper *mappings)
{
SpaceText *stext = (SpaceText *)slink;
-
- if (!ELEM(GS(old_id->name), ID_TXT)) {
- return;
- }
-
- if ((ID *)stext->text == old_id) {
- stext->text = (Text *)new_id;
- id_us_ensure_real(new_id);
- }
+ BKE_id_remapper_apply(mappings, (ID **)&stext->text, ID_REMAP_APPLY_ENSURE_REAL);
}
/********************* registration ********************/
diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h
index 01c40b4ed22..ebccaa54342 100644
--- a/source/blender/editors/space_text/text_format.h
+++ b/source/blender/editors/space_text/text_format.h
@@ -66,12 +66,12 @@ int text_check_format_len(TextLine *line, unsigned int len);
*
* \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);
+void text_format_fill(const char **str_p, char **fmt_p, char type, 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);
+void text_format_fill_ascii(const char **str_p, char **fmt_p, char type, int len);
/* *** Generalize Formatting *** */
typedef struct TextFormatType {
@@ -88,7 +88,7 @@ typedef struct TextFormatType {
*
* See: FMT_TYPE_ enums below
*/
- void (*format_line)(SpaceText *st, TextLine *line, const bool do_next);
+ void (*format_line)(SpaceText *st, TextLine *line, bool do_next);
const char **ext; /* NULL terminated extensions */
} TextFormatType;
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index 3cae4188932..0b81cd74a42 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -42,7 +42,7 @@ 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_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *area, bool center);
void text_update_cursor_moved(struct bContext *C);
/* Padding around line numbers in character widths. */
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 3c0ffa29bbd..430ffe6d56f 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -796,7 +796,7 @@ static int text_run_script(bContext *C, ReportList *reports)
/* Don't report error messages while live editing */
if (!is_live) {
- /* text may have freed its self */
+ /* text may have freed itself */
if (CTX_data_edit_text(C) == text) {
if (text->curl != curl_prev || curc_prev != text->curc) {
text_update_cursor_moved(C);
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index 41eddd32854..82a0de9b845 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -35,6 +35,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "BKE_undo_system.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -236,6 +237,64 @@ static void recent_files_menu_register(void)
WM_menutype_add(mt);
}
+static void undo_history_draw_menu(const bContext *C, Menu *menu)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->undo_stack == NULL) {
+ return;
+ }
+
+ int undo_step_count = 0;
+ int undo_step_count_all = 0;
+ for (UndoStep *us = wm->undo_stack->steps.last; us; us = us->prev) {
+ undo_step_count_all += 1;
+ 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);
+
+ undo_step_count = 0;
+
+ /* Reverse the order so the most recent state is first in the menu. */
+ int i = undo_step_count_all - 1;
+ for (UndoStep *us = wm->undo_stack->steps.last; us; us = us->prev, i--) {
+ if (us->skip) {
+ continue;
+ }
+ if (!(undo_step_count % col_size)) {
+ column = uiLayoutColumn(split, false);
+ }
+ const bool is_active = (us == wm->undo_stack->step_active);
+ uiLayout *row = uiLayoutRow(column, false);
+ uiLayoutSetEnabled(row, !is_active);
+ uiItemIntO(row,
+ IFACE_(us->name),
+ is_active ? ICON_LAYER_ACTIVE : ICON_NONE,
+ "ED_OT_undo_history",
+ "item",
+ i);
+ undo_step_count += 1;
+ }
+}
+
+static void undo_history_menu_register(void)
+{
+ MenuType *mt;
+
+ mt = MEM_callocN(sizeof(MenuType), __func__);
+ strcpy(mt->idname, "TOPBAR_MT_undo_history");
+ strcpy(mt->label, N_("Undo History"));
+ strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ mt->draw = undo_history_draw_menu;
+ WM_menutype_add(mt);
+}
+
void ED_spacetype_topbar(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype topbar");
@@ -278,6 +337,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 1711188fca7..b1ee6da1a33 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -113,9 +113,9 @@ static SpaceLink *userpref_duplicate(SpaceLink *sl)
/* add handlers, stuff you only do once or on area/region changes */
static void userpref_main_region_init(wmWindowManager *wm, ARegion *region)
{
- /* do not use here, the properties changed in userprefs do a system-wide refresh,
+ /* do not use here, the properties changed in user-preferences do a system-wide refresh,
* then scroller jumps back */
- /* region->v2d.flag &= ~V2D_IS_INIT; */
+ // region->v2d.flag &= ~V2D_IS_INIT;
region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE;
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 8822ea6af3b..0a5bebac8a8 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -48,6 +48,7 @@
#include "BKE_idprop.h"
#include "BKE_lattice.h"
#include "BKE_layer.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
@@ -1813,50 +1814,54 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
return CTX_RESULT_MEMBER_NOT_FOUND;
}
-static void view3d_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
+static void view3d_id_remap_v3d_ob_centers(View3D *v3d, const struct IDRemapper *mappings)
{
- View3D *v3d;
- ARegion *region;
- bool is_local = false;
-
- if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) {
- return;
+ if (BKE_id_remapper_apply(mappings, (ID **)&v3d->ob_center, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ /* Otherwise, bonename may remain valid...
+ * We could be smart and check this, too? */
+ v3d->ob_center_bone[0] = '\0';
}
+}
- for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) {
- if ((ID *)v3d->camera == old_id) {
- v3d->camera = (Object *)new_id;
- if (!new_id) {
- /* 3D view might be inactive, in that case needs to use slink->regionbase */
- ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase :
- &slink->regionbase;
- for (region = regionbase->first; region; region = region->next) {
- if (region->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd :
- region->regiondata;
- if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
- rv3d->persp = RV3D_PERSP;
- }
- }
+static void view3d_id_remap_v3d(ScrArea *area,
+ SpaceLink *slink,
+ View3D *v3d,
+ const struct IDRemapper *mappings,
+ const bool is_local)
+{
+ ARegion *region;
+ if (BKE_id_remapper_apply(mappings, (ID **)&v3d->camera, ID_REMAP_APPLY_DEFAULT) ==
+ ID_REMAP_RESULT_SOURCE_UNASSIGNED) {
+ /* 3D view might be inactive, in that case needs to use slink->regionbase */
+ ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase :
+ &slink->regionbase;
+ for (region = regionbase->first; region; region = region->next) {
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd :
+ region->regiondata;
+ if (rv3d && (rv3d->persp == RV3D_CAMOB)) {
+ rv3d->persp = RV3D_PERSP;
}
}
}
+ }
+}
- /* Values in local-view aren't used, see: T52663 */
- if (is_local == false) {
- if ((ID *)v3d->ob_center == old_id) {
- v3d->ob_center = (Object *)new_id;
- /* Otherwise, bonename may remain valid...
- * We could be smart and check this, too? */
- if (new_id == NULL) {
- v3d->ob_center_bone[0] = '\0';
- }
- }
- }
+static void view3d_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRemapper *mappings)
+{
- if (is_local) {
- break;
- }
+ if (!BKE_id_remapper_has_mapping_for(
+ mappings, FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_MC)) {
+ return;
+ }
+
+ View3D *view3d = (View3D *)slink;
+ view3d_id_remap_v3d(area, slink, view3d, mappings, false);
+ view3d_id_remap_v3d_ob_centers(view3d, mappings);
+ if (view3d->localvd != NULL) {
+ /* Object centers in local-view aren't used, see: T52663 */
+ view3d_id_remap_v3d(area, slink, view3d->localvd, mappings, true);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index b79303551a1..243d4033cbc 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -87,7 +87,7 @@ typedef struct {
} TransformMedian_Generic;
typedef struct {
- float location[3], bv_weight, be_weight, skin[2], crease;
+ float location[3], bv_weight, v_crease, be_weight, skin[2], e_crease;
} TransformMedian_Mesh;
typedef struct {
@@ -319,6 +319,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
BMIter iter;
const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ const int cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
@@ -335,6 +336,10 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
median->bv_weight += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_bweight_offset);
}
+ if (cd_vert_crease_offset != -1) {
+ median->v_crease += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_crease_offset);
+ }
+
if (has_skinradius) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
add_v2_v2(median->skin, vs->radius); /* Third val not used currently. */
@@ -352,7 +357,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
if (cd_edge_crease_offset != -1) {
- median->crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset);
+ median->e_crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset);
}
totedgedata++;
@@ -489,11 +494,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if (has_meshdata) {
TransformMedian_Mesh *median = &median_basis.mesh;
if (totedgedata) {
- median->crease /= (float)totedgedata;
+ median->e_crease /= (float)totedgedata;
median->be_weight /= (float)totedgedata;
}
if (tot) {
median->bv_weight /= (float)tot;
+ median->v_crease /= (float)tot;
if (has_skinradius) {
median->skin[0] /= (float)tot;
median->skin[1] /= (float)tot;
@@ -683,6 +689,23 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
TIP_("Vertex weight used by Bevel modifier"));
UI_but_number_step_size_set(but, 1);
UI_but_number_precision_set(but, 2);
+ /* customdata layer added on demand */
+ but = uiDefButF(block,
+ UI_BTYPE_NUM,
+ B_TRANSFORM_PANEL_MEDIAN,
+ tot == 1 ? IFACE_("Vertex Crease:") : IFACE_("Mean Vertex Crease:"),
+ 0,
+ yi -= buth + but_margin,
+ butw,
+ buth,
+ &ve_median->v_crease,
+ 0.0,
+ 1.0,
+ 0,
+ 0,
+ TIP_("Weight used by the Subdivision Surface modifier"));
+ UI_but_number_step_size_set(but, 1);
+ UI_but_number_precision_set(but, 2);
}
if (has_skinradius) {
UI_block_align_begin(block);
@@ -761,7 +784,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
yi -= buth + but_margin,
butw,
buth,
- &ve_median->crease,
+ &ve_median->e_crease,
0.0,
1.0,
0,
@@ -958,8 +981,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
const bool apply_vcos = (tot == 1) || (len_squared_v3(median_basis.generic.location) != 0.0f);
if ((ob->type == OB_MESH) &&
- (apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.skin[0] ||
- median_basis.mesh.skin[1] || median_basis.mesh.be_weight || median_basis.mesh.crease)) {
+ (apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.v_crease ||
+ median_basis.mesh.skin[0] || median_basis.mesh.skin[1] || median_basis.mesh.be_weight ||
+ median_basis.mesh.e_crease)) {
const TransformMedian_Mesh *median = &median_basis.mesh, *ve_median = &ve_median_basis.mesh;
Mesh *me = ob->data;
BMEditMesh *em = me->edit_mesh;
@@ -969,18 +993,21 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
BMEdge *eed;
int cd_vert_bweight_offset = -1;
+ int cd_vert_crease_offset = -1;
int cd_vert_skin_offset = -1;
int cd_edge_bweight_offset = -1;
int cd_edge_crease_offset = -1;
float scale_bv_weight = 1.0f;
+ float scale_v_crease = 1.0f;
float scale_skin[2] = {1.0f, 1.0f};
float scale_be_weight = 1.0f;
- float scale_crease = 1.0f;
+ float scale_e_crease = 1.0f;
/* Vertices */
- if (apply_vcos || median->bv_weight || median->skin[0] || median->skin[1]) {
+ if (apply_vcos || median->bv_weight || median->v_crease || median->skin[0] ||
+ median->skin[1]) {
if (median->bv_weight) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
@@ -989,6 +1016,14 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
scale_bv_weight = compute_scale_factor(ve_median->bv_weight, median->bv_weight);
}
+ if (median->v_crease) {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE);
+ cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
+ BLI_assert(cd_vert_crease_offset != -1);
+
+ scale_v_crease = compute_scale_factor(ve_median->v_crease, median->v_crease);
+ }
+
for (int i = 0; i < 2; i++) {
if (median->skin[i]) {
cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
@@ -1011,6 +1046,11 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
apply_scale_factor_clamp(b_weight, tot, ve_median->bv_weight, scale_bv_weight);
}
+ if (cd_vert_crease_offset != -1) {
+ float *crease = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset);
+ apply_scale_factor_clamp(crease, tot, ve_median->v_crease, scale_v_crease);
+ }
+
if (cd_vert_skin_offset != -1) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
@@ -1033,7 +1073,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
/* Edges */
- if (median->be_weight || median->crease) {
+ if (median->be_weight || median->e_crease) {
if (median->be_weight) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
@@ -1042,12 +1082,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
scale_be_weight = compute_scale_factor(ve_median->be_weight, median->be_weight);
}
- if (median->crease) {
+ if (median->e_crease) {
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
BLI_assert(cd_edge_crease_offset != -1);
- scale_crease = compute_scale_factor(ve_median->crease, median->crease);
+ scale_e_crease = compute_scale_factor(ve_median->e_crease, median->e_crease);
}
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
@@ -1057,9 +1097,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
apply_scale_factor_clamp(b_weight, tot, ve_median->be_weight, scale_be_weight);
}
- if (median->crease != 0.0f) {
+ if (median->e_crease != 0.0f) {
float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
- apply_scale_factor_clamp(crease, tot, ve_median->crease, scale_crease);
+ apply_scale_factor_clamp(crease, tot, ve_median->e_crease, scale_e_crease);
}
}
}
@@ -1552,7 +1592,7 @@ static void v3d_posearmature_buts(uiLayout *layout, Object *ob)
PointerRNA pchanptr;
uiLayout *col;
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (!pchan) {
uiItemL(layout, IFACE_("No Bone Active"), ICON_NONE);
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index a7d170982ed..b1f19581543 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1581,6 +1581,7 @@ void view3d_main_region_draw(const bContext *C, ARegion *region)
view3d_draw_view(C, region);
+ DRW_cache_free_old_subdiv();
DRW_cache_free_old_batches(bmain);
BKE_image_free_old_gputextures(bmain);
GPU_pass_cache_garbage_collect();
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 830f7cbeff1..80089815284 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -3216,7 +3216,7 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op))
if (obact->mode & OB_MODE_POSE) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
- bPoseChannel *pcham_act = BKE_pose_channel_active(obact_eval);
+ bPoseChannel *pcham_act = BKE_pose_channel_active_if_layer_visible(obact_eval);
if (pcham_act) {
BLI_strncpy(v3d->ob_center_bone, pcham_act->name, sizeof(v3d->ob_center_bone));
}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
index 83d3286c8b3..31ae8a92f81 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
@@ -134,7 +134,7 @@ static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmGizmoGroupType
if (ob) {
const bArmature *arm = ob->data;
if (arm->drawtype == ARM_B_BONE) {
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && pchan->bone->segments > 1) {
return true;
}
@@ -148,7 +148,7 @@ static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *g
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = BKE_object_pose_armature_get(OBACT(view_layer));
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true);
@@ -187,7 +187,7 @@ static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup
}
struct BoneSplineWidgetGroup *bspline_group = gzgroup->customdata;
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
/* Handles */
for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) {
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 7388004125c..6a1a09df316 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -115,8 +115,8 @@ struct wmNDOFMotionData;
void view3d_ndof_fly(const struct wmNDOFMotionData *ndof,
struct View3D *v3d,
struct RegionView3D *rv3d,
- const bool use_precision,
- const short protectflag,
+ bool use_precision,
+ short protectflag,
bool *r_has_translate,
bool *r_has_rotate);
#endif /* WITH_INPUT_NDOF */
@@ -203,13 +203,13 @@ void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph,
struct ScrArea *area,
struct View3D *v3d,
struct ARegion *region,
- const int smooth_viewtx,
+ int smooth_viewtx,
const V3D_SmoothParams *sview);
void ED_view3d_smooth_view(struct bContext *C,
struct View3D *v3d,
struct ARegion *region,
- const int smooth_viewtx,
+ int smooth_viewtx,
const V3D_SmoothParams *sview);
/**
@@ -274,17 +274,17 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire(struct Depsgraph *de
* Updates cameras from the `rv3d` values, optionally auto-keyframing.
*/
void ED_view3d_cameracontrol_update(struct View3DCameraControl *vctrl,
- const bool use_autokey,
+ bool use_autokey,
struct bContext *C,
- const bool do_rotate,
- const bool do_translate);
+ bool do_rotate,
+ 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);
+void ED_view3d_cameracontrol_release(struct View3DCameraControl *vctrl, bool restore);
/**
* Returns the object which is being manipulated or NULL.
*/
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index 16d9b9182cf..990b4fc85b1 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -272,8 +272,7 @@ typedef struct foreachScreenFace_userData {
static void meshobject_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
foreachScreenObjectVert_userData *data = userData;
struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index];
@@ -322,8 +321,7 @@ void meshobject_foreachScreenVert(
static void mesh_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
foreachScreenVert_userData *data = userData;
BMVert *eve = BM_vert_at_index(data->vc.em->bm, index);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index cc8aac21a6e..45899880b41 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -4040,7 +4040,9 @@ static bool lattice_circle_select(ViewContext *vc,
return data.is_changed;
}
-/* NOTE: pose-bone case is copied from editbone case... */
+/**
+ * \note logic is shared with the edit-bone case, see #armature_circle_doSelectJoint.
+ */
static bool pchan_circle_doSelectJoint(void *userData,
bPoseChannel *pchan,
const float screen_co[2])
@@ -4137,6 +4139,9 @@ static bool pose_circle_select(ViewContext *vc,
return data.is_changed;
}
+/**
+ * \note logic is shared with the pose-bone case, see #pchan_circle_doSelectJoint.
+ */
static bool armature_circle_doSelectJoint(void *userData,
EditBone *ebone,
const float screen_co[2],
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 3035d11d0e3..642de550812 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -712,9 +712,9 @@ int transformEnd(struct bContext *C, TransInfo *t);
void setTransformViewMatrices(TransInfo *t);
void setTransformViewAspect(TransInfo *t, float r_aspect[3]);
void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy);
-void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag);
+void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], eV3DProjTest flag);
void projectIntView(TransInfo *t, const float vec[3], int adr[2]);
-void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag);
+void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], eV3DProjTest flag);
void projectFloatView(TransInfo *t, const float vec[3], float adr[2]);
void applyAspectRatio(TransInfo *t, float vec[2]);
@@ -770,7 +770,7 @@ typedef enum {
} MouseInputMode;
void initMouseInput(
- TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], const bool precision);
+ TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], bool precision);
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode);
void applyMouseInput(struct TransInfo *t,
struct MouseInput *mi,
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 8f3d13176a3..4107cc3a71c 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -914,6 +914,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
case TC_SEQ_DATA:
special_aftertrans_update__sequencer(C, t);
break;
+ case TC_SEQ_IMAGE_DATA:
+ special_aftertrans_update__sequencer_image(C, t);
+ break;
case TC_TRACKING_DATA:
special_aftertrans_update__movieclip(C, t);
break;
@@ -930,7 +933,6 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
case TC_OBJECT_TEXSPACE:
case TC_PAINT_CURVE_VERTS:
case TC_PARTICLE_VERTS:
- case TC_SEQ_IMAGE_DATA:
case TC_NONE:
default:
break;
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 5ed8182857d..c40f3c28a79 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -48,9 +48,9 @@ int special_transform_moving(TransInfo *t);
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);
+bool clipUVTransform(TransInfo *t, float vec[2], bool resize);
void clipUVData(TransInfo *t);
-void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float y_fac);
+void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, float y_fac);
/**
* Called for updating while transform acts, once per redraw.
*/
@@ -83,7 +83,7 @@ void transform_around_single_fallback(TransInfo *t);
* 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);
+void posttrans_fcurve_clean(struct FCurve *fcu, int sel_flag, bool use_handle);
/**
* Little helper function for ObjectToTransData used to give certain
* constraints (ChildOf, FollowPath, and others that may be added)
@@ -125,8 +125,8 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t);
* Returns total number of bones with #BONE_TRANSFORM.
*/
int transform_convert_pose_transflags_update(Object *ob,
- const int mode,
- const short around,
+ int mode,
+ short around,
bool has_translate_rotate[2]);
/**
* When objects array is NULL, use 't->data_container' as is.
@@ -208,9 +208,9 @@ struct TransMeshDataCrazySpace {
};
void transform_convert_mesh_islands_calc(struct BMEditMesh *em,
- const bool calc_single_islands,
- const bool calc_island_center,
- const bool calc_island_axismtx,
+ bool calc_single_islands,
+ bool calc_island_center,
+ bool calc_island_axismtx,
struct TransIslandData *r_island_data);
void transform_convert_mesh_islanddata_free(struct TransIslandData *island_data);
/**
@@ -223,8 +223,8 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm,
float *dists,
int *index);
void transform_convert_mesh_mirrordata_calc(struct BMEditMesh *em,
- const bool use_select,
- const bool use_topology,
+ bool use_select,
+ bool use_topology,
const bool mirror_axis[3],
struct TransMirrorData *r_mirror_data);
void transform_convert_mesh_mirrordata_free(struct TransMirrorData *mirror_data);
@@ -304,6 +304,7 @@ void special_aftertrans_update__sequencer(bContext *C, TransInfo *t);
/* transform_convert_sequencer_image.c */
void createTransSeqImageData(TransInfo *t);
void recalcData_sequencer_image(TransInfo *t);
+void special_aftertrans_update__sequencer_image(bContext *C, TransInfo *t);
/* transform_convert_tracking.c */
void createTransTrackingData(bContext *C, TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 63aada0f797..5d0a3bd9dd1 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -427,7 +427,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
/* Rule: allow multiple Bones
* (but they must be selected, and only one ik-solver per chain should get added) */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->layer & arm->layer) {
+ if (BKE_pose_is_layer_visible(arm, pchan)) {
if (pchan->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) {
/* Rule: no IK for solitary (unconnected) bones. */
for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) {
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 255af3feca2..924e51a2b41 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -357,26 +357,6 @@ void createTransCurveVerts(TransInfo *t)
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
if (bp->hide == 0) {
if (is_prop_edit || (bp->f1 & SELECT)) {
- float axismtx[3][3];
-
- if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
- if (nu->pntsv == 1) {
- float normal[3], plane[3];
-
- BKE_nurb_bpoint_calc_normal(nu, bp, normal);
- BKE_nurb_bpoint_calc_plane(nu, bp, plane);
-
- if (createSpaceNormalTangent(axismtx, normal, plane)) {
- /* pass */
- }
- else {
- normalize_v3(normal);
- axis_dominant_v3_to_m3(axismtx, normal);
- invert_m3(axismtx);
- }
- }
- }
-
copy_v3_v3(td->iloc, bp->vec);
td->loc = bp->vec;
copy_v3_v3(td->center, td->loc);
@@ -400,9 +380,22 @@ void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
+
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
if (nu->pntsv == 1) {
- copy_m3_m3(td->axismtx, axismtx);
+ float normal[3], plane[3];
+
+ BKE_nurb_bpoint_calc_normal(nu, bp, normal);
+ BKE_nurb_bpoint_calc_plane(nu, bp, plane);
+
+ if (createSpaceNormalTangent(td->axismtx, normal, plane)) {
+ /* pass */
+ }
+ else {
+ normalize_v3(normal);
+ axis_dominant_v3_to_m3(td->axismtx, normal);
+ invert_m3(td->axismtx);
+ }
}
}
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
index 1a25cfd1efb..e26172cd764 100644
--- a/source/blender/editors/transform/transform_convert_mask.c
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -472,12 +472,7 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t)
}
if (t->scene->nodetree) {
- /* tracks can be used for stabilization nodes,
- * flush update for such nodes */
- // if (nodeUpdateID(t->scene->nodetree, &mask->id))
- {
- WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
- }
+ WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
}
/* TODO: don't key all masks. */
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index c3d95e1ad98..e00522f0f88 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1465,7 +1465,7 @@ static void VertsToTransData(TransInfo *t,
td->ext = NULL;
td->val = NULL;
td->extra = eve;
- if (t->mode == TFM_BWEIGHT) {
+ if (t->mode == TFM_BWEIGHT || t->mode == TFM_VERT_CREASE) {
td->val = bweight;
td->ival = *bweight;
}
@@ -1606,10 +1606,15 @@ void createTransEditVerts(TransInfo *t)
}
int cd_vert_bweight_offset = -1;
+ int cd_vert_crease_offset = -1;
if (t->mode == TFM_BWEIGHT) {
BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
+ else if (t->mode == TFM_VERT_CREASE) {
+ BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_CREASE);
+ cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
+ }
TransData *tob = tc->data;
TransDataMirror *td_mirror = tc->data_mirror;
@@ -1645,6 +1650,8 @@ void createTransEditVerts(TransInfo *t)
else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
float *bweight = (cd_vert_bweight_offset != -1) ?
BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
+ (cd_vert_crease_offset != -1) ?
+ BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset) :
NULL;
/* Do not use the island center in case we are using islands
diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c
index 2db3e259153..2243f66cc7f 100644
--- a/source/blender/editors/transform/transform_convert_mesh_edge.c
+++ b/source/blender/editors/transform/transform_convert_mesh_edge.c
@@ -86,8 +86,8 @@ void createTransEdge(TransInfo *t)
BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
}
- else { /* if (t->mode == TFM_CREASE) { */
- BLI_assert(t->mode == TFM_CREASE);
+ else { /* if (t->mode == TFM_EDGE_CREASE) { */
+ BLI_assert(t->mode == TFM_EDGE_CREASE);
BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
}
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index da11666d445..e8cdfaf1f40 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -31,6 +31,7 @@
#include "BKE_context.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "ED_node.h"
@@ -246,7 +247,7 @@ void special_aftertrans_update__node(bContext *C, TransInfo *t)
nodeRemoveNode(bmain, ntree, node, true);
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(C, bmain, ntree);
}
}
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 88c01321785..01eae36e846 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -34,6 +34,7 @@
#include "ED_markers.h"
+#include "SEQ_animation.h"
#include "SEQ_edit.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
@@ -302,7 +303,7 @@ static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strip
return collection;
}
-/* Query strips positioned after left edge of transformed strips boundbox. */
+/* Query strips positioned after left edge of transformed strips bound-box. */
static SeqCollection *query_right_side_strips(ListBase *seqbase, SeqCollection *transformed_strips)
{
int minframe = MAXFRAME;
@@ -351,7 +352,7 @@ static ListBase *seqbase_active_get(const TransInfo *t)
return SEQ_active_seqbase_get(ed);
}
-/* Offset all strips positioned after left edge of transformed strips boundbox by amount equal
+/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal
* to overlap of transformed strips. */
static void seq_transform_handle_expand_to_fit(TransInfo *t, SeqCollection *transformed_strips)
{
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index d5a59885014..3a5770c2863 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -38,8 +38,12 @@
#include "SEQ_transform.h"
#include "SEQ_utils.h"
+#include "ED_keyframing.h"
+
#include "UI_view2d.h"
+#include "RNA_access.h"
+
#include "transform.h"
#include "transform_convert.h"
@@ -215,3 +219,44 @@ void recalcData_sequencer_image(TransInfo *t)
SEQ_relations_invalidate_cache_preprocessed(t->scene, seq);
}
}
+
+void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *t)
+{
+ if (t->state == TRANS_CANCEL) {
+ return;
+ }
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ int i;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
+ TransDataSeq *tdseq = td->extra;
+ Sequence *seq = tdseq->seq;
+ StripTransform *transform = seq->strip->transform;
+ Scene *scene = t->scene;
+
+ RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr);
+
+ if (t->mode == TFM_ROTATION) {
+ prop = RNA_struct_find_property(&ptr, "rotation");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ if (t->mode == TFM_TRANSLATION) {
+ prop = RNA_struct_find_property(&ptr, "offset_x");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ prop = RNA_struct_find_property(&ptr, "offset_y");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ if (t->mode == TFM_RESIZE) {
+ prop = RNA_struct_find_property(&ptr, "scale_x");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ prop = RNA_struct_find_property(&ptr, "scale_y");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ }
+}
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index dc37f2796bf..f2d0fb7ac2f 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -29,8 +29,10 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "ED_clip.h"
@@ -793,8 +795,12 @@ void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
/* Tracks can be used for stabilization nodes,
* flush update for such nodes.
*/
- nodeUpdateID(t->scene->nodetree, &clip->id);
- WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
+ if (t->context != NULL) {
+ Main *bmain = CTX_data_main(C);
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
+ BKE_ntree_update_main(bmain, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
+ }
}
}
diff --git a/source/blender/editors/transform/transform_data.h b/source/blender/editors/transform/transform_data.h
index 6cfceedb389..a78c2491a1a 100644
--- a/source/blender/editors/transform/transform_data.h
+++ b/source/blender/editors/transform/transform_data.h
@@ -27,8 +27,8 @@ struct Object;
struct bConstraint;
#define TRANSDATABASIC \
- /** Extra data (mirrored element pointer, in editmode mesh to BMVert) \
- * (editbone for roll fixing) (...). */ \
+ /** Extra data (mirrored element pointer, in edit-mode mesh to #BMVert) \
+ * (edit-bone for roll fixing) (...). */ \
void *extra; \
/** Location of the data to transform. */ \
float *loc; \
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index c2ff095904d..d1cbab9ff8a 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -214,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 {
@@ -259,7 +260,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* Crease needs edge flag */
- if (ELEM(t->mode, TFM_CREASE, TFM_BWEIGHT)) {
+ if (ELEM(t->mode, TFM_EDGE_CREASE, TFM_BWEIGHT)) {
t->options |= CTX_EDGE_DATA;
}
diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
index 6e89c3de197..dee6e7281ef 100644
--- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
@@ -82,6 +82,7 @@ typedef struct GizmoExtrudeGroup {
float orient_matrix[3][3];
bool constraint_axis[3];
float value[4];
+ int orient_type;
} redo_xform;
/* Depends on object type. */
@@ -310,6 +311,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup)
RNA_float_get_array(op_xform->ptr, "orient_matrix", &ggd->redo_xform.orient_matrix[0][0]);
RNA_boolean_get_array(op_xform->ptr, "constraint_axis", ggd->redo_xform.constraint_axis);
RNA_float_get_array(op_xform->ptr, "value", ggd->redo_xform.value);
+ ggd->redo_xform.orient_type = RNA_enum_get(op_xform->ptr, "orient_type");
/* Set properties for redo. */
for (int i = 0; i < 3; i++) {
@@ -435,7 +437,8 @@ static void gizmo_mesh_extrude_invoke_prepare(const bContext *UNUSED(C),
if (gz == ggd->adjust[0]) {
RNA_boolean_set_array(&macroptr, "constraint_axis", ggd->redo_xform.constraint_axis);
RNA_float_set_array(&macroptr, "orient_matrix", &ggd->redo_xform.orient_matrix[0][0]);
- RNA_enum_set(&macroptr, "orient_type", V3D_ORIENT_NORMAL);
+ RNA_enum_set(&macroptr, "orient_matrix_type", ggd->redo_xform.orient_type);
+ RNA_enum_set(&macroptr, "orient_type", ggd->redo_xform.orient_type);
}
RNA_float_set_array(&macroptr, "value", ggd->redo_xform.value);
}
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index d2e7f9f83df..e1fea62ae54 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -1042,7 +1042,7 @@ void ElementResize(const TransInfo *t,
applyNumInput(&num_evil, values_final_evil);
float ratio = values_final_evil[0];
- *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff;
+ *td->val = td->ival * fabs(ratio) * gps->runtime.multi_frame_falloff;
CLAMP_MIN(*td->val, 0.001f);
}
}
@@ -1135,8 +1135,11 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
case TFM_PUSHPULL:
initPushPull(t);
break;
- case TFM_CREASE:
- initCrease(t);
+ case TFM_EDGE_CREASE:
+ initEgdeCrease(t);
+ break;
+ case TFM_VERT_CREASE:
+ initVertCrease(t);
break;
case TFM_BONESIZE:
initBoneSize(t);
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index ec3d5b8d0fe..16b26724c67 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -45,7 +45,7 @@ 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);
+bool transform_mode_is_changeable(int mode);
void protectedTransBits(short protectflag, float vec[3]);
void protectedSizeBits(short protectflag, float size[3]);
void constraintTransLim(const TransInfo *t, TransData *td);
@@ -69,13 +69,13 @@ void ElementRotation(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
const float mat[3][3],
- const short around);
+ short around);
void headerResize(TransInfo *t, const float vec[3], char *str, int str_size);
void ElementResize(const TransInfo *t,
const TransDataContainer *tc,
TransData *td,
const float mat[3][3]);
-void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode);
+void transform_mode_init(TransInfo *t, struct wmOperator *op, int mode);
/**
* When in modal and not set, initializes a default orientation for the mode.
*/
@@ -106,7 +106,8 @@ void initCurveShrinkFatten(TransInfo *t);
void initBevelWeight(TransInfo *t);
/* transform_mode_edge_crease.c */
-void initCrease(TransInfo *t);
+void initEgdeCrease(TransInfo *t);
+void initVertCrease(TransInfo *t);
/* transform_mode_edge_rotate_normal.c */
void initNormalRotation(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c
index debc2a1be3e..60b95a1d2da 100644
--- a/source/blender/editors/transform/transform_mode_edge_crease.c
+++ b/source/blender/editors/transform/transform_mode_edge_crease.c
@@ -157,9 +157,9 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
-void initCrease(TransInfo *t)
+static void initCrease_ex(TransInfo *t, int mode)
{
- t->mode = TFM_CREASE;
+ t->mode = mode;
t->transform = applyCrease;
initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA);
@@ -176,4 +176,13 @@ void initCrease(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+void initEgdeCrease(TransInfo *t)
+{
+ initCrease_ex(t, TFM_EDGE_CREASE);
+}
+
+void initVertCrease(TransInfo *t)
+{
+ initCrease_ex(t, TFM_VERT_CREASE);
+}
/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c
index 7a0f2743a98..223f2511c72 100644
--- a/source/blender/editors/transform/transform_mode_edge_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_slide.c
@@ -195,7 +195,7 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, const float plane_no[3], flo
/* allow some overlap to avoid missing the intersection because of float precision */
if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) {
/* likelihood of multiple intersections per ngon is quite low,
- * it would have to loop back on its self, but better support it
+ * it would have to loop back on itself, but better support it
* so check for the closest opposite edge */
const float tdist = len_v3v3(l_tmp->v->co, tvec);
if (tdist < dist) {
diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c
index 5f2a2e472c5..84ca5d3ae54 100644
--- a/source/blender/editors/transform/transform_mode_timetranslate.c
+++ b/source/blender/editors/transform/transform_mode_timetranslate.c
@@ -62,27 +62,28 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival;
float val = ival + t->values_final[0];
- float snap_val = val;
- snapFrameTransform(t, autosnap, ival, val, &snap_val);
+ snapFrameTransform(t, autosnap, ival, val, &val);
+ float delta_x = val - ival;
if (ELEM(autosnap, SACTSNAP_SECOND, SACTSNAP_TSTEP)) {
/* Convert to seconds. */
const Scene *scene = t->scene;
const double secf = FPS;
- snap_val /= secf;
+ delta_x /= secf;
+ val /= secf;
}
if (autosnap == SACTSNAP_FRAME) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", delta_x, val);
}
else if (autosnap == SACTSNAP_SECOND) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", snap_val, val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", delta_x, val);
}
else if (autosnap == SACTSNAP_TSTEP) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", snap_val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", delta_x);
}
else {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", snap_val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", delta_x);
}
}
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 19d0c6d39a3..b8b043c650f 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -225,11 +225,12 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
if (t->spacetype == SPACE_GRAPH) {
/* WORKAROUND:
* Special case where snapping is done in #recalData.
- * Update the header based on the first element. */
+ * Update the header based on the #center_local. */
const short autosnap = getAnimEdit_SnapMode(t);
- float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival;
+ float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->center_local[0];
float val = ival + dvec[0];
- snapFrameTransform(t, autosnap, ival, val, &dvec[0]);
+ snapFrameTransform(t, autosnap, ival, val, &val);
+ dvec[0] = val - ival;
}
if (t->con.mode & CON_APPLY) {
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 5ed340abf97..80feb934f1a 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -78,6 +78,7 @@ static const char OP_BONE_SIZE[] = "TRANSFORM_OT_bbone_resize";
static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
+static const char OP_VERT_CREASE[] = "TRANSFORM_OT_vert_crease";
static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
static const char OP_NORMAL_ROTATION[] = "TRANSFORM_OT_rotate_normal";
@@ -98,6 +99,7 @@ static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot);
+static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot);
static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot);
@@ -118,7 +120,8 @@ static TransformModeItem transform_modes[] = {
{OP_BONE_SIZE, TFM_BONESIZE, TRANSFORM_OT_bbone_resize},
{OP_EDGE_SLIDE, TFM_EDGE_SLIDE, TRANSFORM_OT_edge_slide},
{OP_VERT_SLIDE, TFM_VERT_SLIDE, TRANSFORM_OT_vert_slide},
- {OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease},
+ {OP_EDGE_CREASE, TFM_EDGE_CREASE, TRANSFORM_OT_edge_crease},
+ {OP_VERT_CREASE, TFM_VERT_CREASE, TRANSFORM_OT_vert_crease},
{OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight},
{OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide},
{OP_NORMAL_ROTATION, TFM_NORMAL_ROTATION, TRANSFORM_OT_rotate_normal},
@@ -139,7 +142,8 @@ const EnumPropertyItem rna_enum_transform_mode_types[] = {
{TFM_TILT, "TILT", 0, "Tilt", ""},
{TFM_TRACKBALL, "TRACKBALL", 0, "Trackball", ""},
{TFM_PUSHPULL, "PUSHPULL", 0, "Push/Pull", ""},
- {TFM_CREASE, "CREASE", 0, "Crease", ""},
+ {TFM_EDGE_CREASE, "CREASE", 0, "Crease", ""},
+ {TFM_VERT_CREASE, "VERTEX_CREASE", 0, "Vertex Crease", ""},
{TFM_MIRROR, "MIRROR", 0, "Mirror", ""},
{TFM_BONESIZE, "BONE_SIZE", 0, "Bone Size", ""},
{TFM_BONE_ENVELOPE, "BONE_ENVELOPE", 0, "Bone Envelope", ""},
@@ -1196,6 +1200,29 @@ static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
Transform_Properties(ot, P_SNAP);
}
+static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Crease";
+ ot->description = "Change the crease of vertices";
+ ot->idname = OP_VERT_CREASE;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* api callbacks */
+ ot->invoke = transform_invoke;
+ ot->exec = transform_exec;
+ ot->modal = transform_modal;
+ ot->cancel = transform_cancel;
+ ot->poll = ED_operator_editmesh;
+ ot->poll_property = transform_poll_property;
+
+ RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
+
+ WM_operatortype_props_advanced_begin(ot);
+
+ Transform_Properties(ot, P_SNAP);
+}
+
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot)
{
/* identifiers */
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index fa2485c33c2..5ac5bccd69c 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -513,7 +513,7 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
if (ob) {
if (ob->mode & OB_MODE_POSE) {
- const bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ const bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && gimbal_axis_pose(ob, pchan, r_mat)) {
break;
}
@@ -1224,7 +1224,7 @@ int getTransformOrientation_ex(ViewLayer *view_layer,
float imat[3][3], mat[3][3];
bool ok = false;
- if (activeOnly && (pchan = BKE_pose_channel_active(ob))) {
+ if (activeOnly && (pchan = BKE_pose_channel_active_if_layer_visible(ob))) {
add_v3_v3(normal, pchan->pose_mat[2]);
add_v3_v3(plane, pchan->pose_mat[1]);
ok = true;
diff --git a/source/blender/editors/transform/transform_orientations.h b/source/blender/editors/transform/transform_orientations.h
index 6e0e3d9f8c7..dd2d5bc86c5 100644
--- a/source/blender/editors/transform/transform_orientations.h
+++ b/source/blender/editors/transform/transform_orientations.h
@@ -34,8 +34,8 @@ short transform_orientation_matrix_get(struct bContext *C,
short orient_index,
const float custom[3][3],
float r_spacemtx[3][3]);
-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);
+const char *transform_orientations_spacename_get(struct TransInfo *t, short orient_type);
+void transform_orientations_current_set(struct TransInfo *t, short orient_index);
/**
* Those two fill in mat and return non-zero on success.
@@ -55,7 +55,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa
struct TransformOrientation *addMatrixSpace(struct bContext *C,
float mat[3][3],
const char *name,
- const bool overwrite);
+ bool overwrite);
void applyTransformOrientation(const struct TransformOrientation *ts,
float r_mat[3][3],
char r_name[64]);
@@ -75,5 +75,5 @@ int getTransformOrientation_ex(ViewLayer *view_layer,
struct Object *obedit,
float normal[3],
float plane[3],
- const short around);
+ short around);
int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index a09078a8222..40be8e6e641 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -499,13 +499,15 @@ 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);
}
- }
- t->tsnap.last = current;
+ t->tsnap.last = current;
+ }
if (validSnap(t)) {
t->tsnap.applySnap(t, vec);
@@ -691,6 +693,15 @@ static void initSnappingMode(TransInfo *t)
bm_face_is_snap_target,
POINTER_FROM_UINT((BM_ELEM_SELECT | BM_ELEM_HIDDEN)));
}
+ else {
+ /* Ignore hidden geometry in the general case. */
+ ED_transform_snap_object_context_set_editmesh_callbacks(
+ t->tsnap.object_context,
+ (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
+ (bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled,
+ (bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled,
+ POINTER_FROM_UINT(BM_ELEM_HIDDEN));
+ }
}
}
else if (t->spacetype == SPACE_SEQ) {
@@ -783,8 +794,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;
@@ -959,7 +977,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 bc89c7a8cda..389c1441db1 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -27,7 +27,7 @@
bool peelObjectsTransform(struct TransInfo *t,
const float mval[2],
- const bool use_peel_object,
+ bool use_peel_object,
/* return args */
float r_loc[3],
float r_no[3],
@@ -92,9 +92,9 @@ void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec);
*/
short getAnimEdit_SnapMode(TransInfo *t);
void snapFrameTransform(TransInfo *t,
- const eAnimEdit_AutoSnap autosnap,
- const float val_initial,
- const float val_final,
+ eAnimEdit_AutoSnap autosnap,
+ float val_initial,
+ float val_final,
float *r_val_final);
/**
* This function is used by Animation Editor specific transform functions to do
@@ -102,5 +102,5 @@ void snapFrameTransform(TransInfo *t,
*/
void transform_snap_anim_flush_data(TransInfo *t,
TransData *td,
- const eAnimEdit_AutoSnap autosnap,
+ eAnimEdit_AutoSnap autosnap,
float *r_val_final);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 350d3a2676c..9dc8b6cf69d 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -146,26 +146,28 @@ struct SnapObjectContext {
* If NULL the BMesh should be used. */
static Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide)
{
- Mesh *me_eval = ob_eval->data;
+ Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
bool use_hide = false;
if (BKE_object_is_in_editmode(ob_eval)) {
if (edit_mode_type == SNAP_GEOM_EDIT) {
return NULL;
}
- BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
- if ((edit_mode_type == SNAP_GEOM_FINAL) && em_eval->mesh_eval_final) {
- if (em_eval->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
+
+ if ((edit_mode_type == SNAP_GEOM_FINAL) && editmesh_eval_final) {
+ if (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return NULL;
}
- me_eval = em_eval->mesh_eval_final;
+ me_eval = editmesh_eval_final;
use_hide = true;
}
- else if ((edit_mode_type == SNAP_GEOM_CAGE) && em_eval->mesh_eval_cage) {
- if (em_eval->mesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ else if ((edit_mode_type == SNAP_GEOM_CAGE) && editmesh_eval_cage) {
+ if (editmesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
return NULL;
}
- me_eval = em_eval->mesh_eval_cage;
+ me_eval = editmesh_eval_cage;
use_hide = true;
}
}
@@ -318,12 +320,14 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx,
if (sod->treedata_mesh.tree == NULL) {
sod->treedata_mesh.vert = me_eval->mvert;
+ sod->treedata_mesh.vert_normals = BKE_mesh_vertex_normals_ensure(me_eval);
sod->treedata_mesh.loop = me_eval->mloop;
sod->treedata_mesh.looptri = BKE_mesh_runtime_looptri_ensure(me_eval);
BLI_assert(sod->has_looptris == false);
}
else {
BLI_assert(sod->treedata_mesh.vert != NULL);
+ BLI_assert(sod->treedata_mesh.vert_normals != NULL);
BLI_assert(sod->treedata_mesh.loop != NULL);
BLI_assert(sod->treedata_mesh.looptri != NULL);
sod->has_looptris = true;
@@ -343,12 +347,14 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx,
static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob_eval)
{
- BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
- if (em_eval->mesh_eval_final) {
- return &em_eval->mesh_eval_final->runtime;
+ Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval);
+ if (editmesh_eval_final) {
+ return &editmesh_eval_final->runtime;
}
- if (em_eval->mesh_eval_cage) {
- return &em_eval->mesh_eval_cage->runtime;
+
+ Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval);
+ if (editmesh_eval_cage) {
+ return &editmesh_eval_cage->runtime;
}
return &((Mesh *)ob_eval->data)->runtime;
@@ -1195,56 +1201,96 @@ static bool snap_bound_box_check_dist(const float min[3],
return true;
}
-static void cb_mvert_co_get(const int index, const void *user_data, const float **r_co)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks
+ * \{ */
+
+struct Nearest2dUserData;
+
+typedef void (*Nearest2DGetVertCoCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ const float **r_co);
+typedef void (*Nearest2DGetEdgeVertsCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ int r_v_index[2]);
+typedef void (*Nearest2DGetTriVertsCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ int r_v_index[3]);
+/* Equal the previous one */
+typedef void (*Nearest2DGetTriEdgesCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ int r_e_index[3]);
+typedef void (*Nearest2DCopyVertNoCallback)(const int index,
+ const struct Nearest2dUserData *data,
+ float r_no[3]);
+
+typedef struct Nearest2dUserData {
+ Nearest2DGetVertCoCallback get_vert_co;
+ Nearest2DGetEdgeVertsCallback get_edge_verts_index;
+ Nearest2DGetTriVertsCallback get_tri_verts_index;
+ Nearest2DGetTriEdgesCallback get_tri_edges_index;
+ Nearest2DCopyVertNoCallback copy_vert_no;
+
+ union {
+ struct {
+ struct BMesh *bm;
+ };
+ struct {
+ const struct MVert *vert;
+ const float (*vert_normals)[3];
+ const struct MEdge *edge; /* only used for #BVHTreeFromMeshEdges */
+ const struct MLoop *loop;
+ const struct MLoopTri *looptri;
+ };
+ };
+
+ bool is_persp;
+ bool use_backface_culling;
+} Nearest2dUserData;
+
+static void cb_mvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co)
{
- const BVHTreeFromMesh *data = user_data;
*r_co = data->vert[index].co;
}
-static void cb_bvert_co_get(const int index, const void *user_data, const float **r_co)
+static void cb_bvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co)
{
- const BMEditMesh *data = user_data;
BMVert *eve = BM_vert_at_index(data->bm, index);
*r_co = eve->co;
}
-static void cb_mvert_no_copy(const int index, const void *user_data, float r_no[3])
+static void cb_mvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3])
{
- const BVHTreeFromMesh *data = user_data;
- const MVert *vert = data->vert + index;
-
- normal_short_to_float_v3(r_no, vert->no);
+ copy_v3_v3(r_no, data->vert_normals[index]);
}
-static void cb_bvert_no_copy(const int index, const void *user_data, float r_no[3])
+static void cb_bvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3])
{
- const BMEditMesh *data = user_data;
BMVert *eve = BM_vert_at_index(data->bm, index);
copy_v3_v3(r_no, eve->no);
}
-static void cb_medge_verts_get(const int index, const void *user_data, int r_v_index[2])
+static void cb_medge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2])
{
- const BVHTreeFromMesh *data = user_data;
const MEdge *edge = &data->edge[index];
r_v_index[0] = edge->v1;
r_v_index[1] = edge->v2;
}
-static void cb_bedge_verts_get(const int index, const void *user_data, int r_v_index[2])
+static void cb_bedge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2])
{
- const BMEditMesh *data = user_data;
BMEdge *eed = BM_edge_at_index(data->bm, index);
r_v_index[0] = BM_elem_index_get(eed->v1);
r_v_index[1] = BM_elem_index_get(eed->v2);
}
-static void cb_mlooptri_edges_get(const int index, const void *user_data, int r_v_index[3])
+static void cb_mlooptri_edges_get(const int index, const Nearest2dUserData *data, int r_v_index[3])
{
- const BVHTreeFromMesh *data = user_data;
const MEdge *medge = data->edge;
const MLoop *mloop = data->loop;
const MLoopTri *lt = &data->looptri[index];
@@ -1261,9 +1307,8 @@ static void cb_mlooptri_edges_get(const int index, const void *user_data, int r_
}
}
-static void cb_mlooptri_verts_get(const int index, const void *user_data, int r_v_index[3])
+static void cb_mlooptri_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[3])
{
- const BVHTreeFromMesh *data = user_data;
const MLoop *loop = data->loop;
const MLoopTri *looptri = &data->looptri[index];
@@ -1332,66 +1377,6 @@ static bool test_projected_edge_dist(const struct DistProjectedAABBPrecalc *prec
precalc, clip_plane, clip_plane_len, is_persp, near_co, dist_px_sq, r_co);
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Walk DFS
- * \{ */
-
-typedef void (*Nearest2DGetVertCoCallback)(const int index,
- const void *user_data,
- const float **r_co);
-typedef void (*Nearest2DGetEdgeVertsCallback)(const int index,
- const void *user_data,
- int r_v_index[2]);
-typedef void (*Nearest2DGetTriVertsCallback)(const int index,
- const void *user_data,
- int r_v_index[3]);
-/* Equal the previous one */
-typedef void (*Nearest2DGetTriEdgesCallback)(const int index,
- const void *user_data,
- int r_e_index[3]);
-typedef void (*Nearest2DCopyVertNoCallback)(const int index, const void *user_data, float r_no[3]);
-
-typedef struct Nearest2dUserData {
- void *userdata;
- Nearest2DGetVertCoCallback get_vert_co;
- Nearest2DGetEdgeVertsCallback get_edge_verts_index;
- Nearest2DGetTriVertsCallback get_tri_verts_index;
- Nearest2DGetTriEdgesCallback get_tri_edges_index;
- Nearest2DCopyVertNoCallback copy_vert_no;
-
- bool is_persp;
- bool use_backface_culling;
-} Nearest2dUserData;
-
-static void nearest2d_data_init(SnapObjectData *sod,
- bool is_persp,
- bool use_backface_culling,
- Nearest2dUserData *r_nearest2d)
-{
- if (sod->type == SNAP_MESH) {
- r_nearest2d->userdata = &sod->treedata_mesh;
- r_nearest2d->get_vert_co = cb_mvert_co_get;
- r_nearest2d->get_edge_verts_index = cb_medge_verts_get;
- r_nearest2d->copy_vert_no = cb_mvert_no_copy;
- r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get;
- r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get;
- }
- else {
- BLI_assert(sod->type == SNAP_EDIT_MESH);
- r_nearest2d->userdata = sod->treedata_editmesh.em;
- r_nearest2d->get_vert_co = cb_bvert_co_get;
- r_nearest2d->get_edge_verts_index = cb_bedge_verts_get;
- r_nearest2d->copy_vert_no = cb_bvert_no_copy;
- r_nearest2d->get_tri_verts_index = NULL;
- r_nearest2d->get_tri_edges_index = NULL;
- }
-
- r_nearest2d->is_persp = is_persp;
- r_nearest2d->use_backface_culling = use_backface_culling;
-}
-
static void cb_snap_vert(void *userdata,
int index,
const struct DistProjectedAABBPrecalc *precalc,
@@ -1399,10 +1384,10 @@ static void cb_snap_vert(void *userdata,
const int clip_plane_len,
BVHTreeNearest *nearest)
{
- struct Nearest2dUserData *data = userdata;
+ Nearest2dUserData *data = userdata;
const float *co;
- data->get_vert_co(index, data->userdata, &co);
+ data->get_vert_co(index, data, &co);
if (test_projected_vert_dist(precalc,
clip_plane,
@@ -1411,7 +1396,7 @@ static void cb_snap_vert(void *userdata,
co,
&nearest->dist_sq,
nearest->co)) {
- data->copy_vert_no(index, data->userdata, nearest->no);
+ data->copy_vert_no(index, data, nearest->no);
nearest->index = index;
}
}
@@ -1426,11 +1411,11 @@ static void cb_snap_edge(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[2];
- data->get_edge_verts_index(index, data->userdata, vindex);
+ data->get_edge_verts_index(index, data, vindex);
const float *v_pair[2];
- data->get_vert_co(vindex[0], data->userdata, &v_pair[0]);
- data->get_vert_co(vindex[1], data->userdata, &v_pair[1]);
+ data->get_vert_co(vindex[0], data, &v_pair[0]);
+ data->get_vert_co(vindex[1], data, &v_pair[1]);
if (test_projected_edge_dist(precalc,
clip_plane,
@@ -1455,7 +1440,7 @@ static void cb_snap_edge_verts(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[2];
- data->get_edge_verts_index(index, data->userdata, vindex);
+ data->get_edge_verts_index(index, data, vindex);
for (int i = 2; i--;) {
if (vindex[i] == nearest->index) {
@@ -1472,16 +1457,16 @@ static void cb_snap_tri_edges(void *userdata,
const int clip_plane_len,
BVHTreeNearest *nearest)
{
- struct Nearest2dUserData *data = userdata;
+ Nearest2dUserData *data = userdata;
if (data->use_backface_culling) {
int vindex[3];
- data->get_tri_verts_index(index, data->userdata, vindex);
+ data->get_tri_verts_index(index, data, vindex);
const float *t0, *t1, *t2;
- data->get_vert_co(vindex[0], data->userdata, &t0);
- data->get_vert_co(vindex[1], data->userdata, &t1);
- data->get_vert_co(vindex[2], data->userdata, &t2);
+ data->get_vert_co(vindex[0], data, &t0);
+ data->get_vert_co(vindex[1], data, &t1);
+ data->get_vert_co(vindex[2], data, &t2);
float dummy[3];
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
return;
@@ -1489,7 +1474,7 @@ static void cb_snap_tri_edges(void *userdata,
}
int eindex[3];
- data->get_tri_edges_index(index, data->userdata, eindex);
+ data->get_tri_edges_index(index, data, eindex);
for (int i = 3; i--;) {
if (eindex[i] != -1) {
if (eindex[i] == nearest->index) {
@@ -1510,13 +1495,13 @@ static void cb_snap_tri_verts(void *userdata,
struct Nearest2dUserData *data = userdata;
int vindex[3];
- data->get_tri_verts_index(index, data->userdata, vindex);
+ data->get_tri_verts_index(index, data, vindex);
if (data->use_backface_culling) {
const float *t0, *t1, *t2;
- data->get_vert_co(vindex[0], data->userdata, &t0);
- data->get_vert_co(vindex[1], data->userdata, &t1);
- data->get_vert_co(vindex[2], data->userdata, &t2);
+ data->get_vert_co(vindex[0], data, &t0);
+ data->get_vert_co(vindex[1], data, &t1);
+ data->get_vert_co(vindex[2], data, &t2);
float dummy[3];
if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
return;
@@ -1531,6 +1516,39 @@ static void cb_snap_tri_verts(void *userdata,
}
}
+static void nearest2d_data_init(SnapObjectData *sod,
+ bool is_persp,
+ bool use_backface_culling,
+ Nearest2dUserData *r_nearest2d)
+{
+ if (sod->type == SNAP_MESH) {
+ r_nearest2d->get_vert_co = cb_mvert_co_get;
+ r_nearest2d->get_edge_verts_index = cb_medge_verts_get;
+ r_nearest2d->copy_vert_no = cb_mvert_no_copy;
+ r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get;
+ r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get;
+
+ r_nearest2d->vert = sod->treedata_mesh.vert;
+ r_nearest2d->vert_normals = sod->treedata_mesh.vert_normals;
+ r_nearest2d->edge = sod->treedata_mesh.edge;
+ r_nearest2d->loop = sod->treedata_mesh.loop;
+ r_nearest2d->looptri = sod->treedata_mesh.looptri;
+ }
+ else {
+ BLI_assert(sod->type == SNAP_EDIT_MESH);
+ r_nearest2d->get_vert_co = cb_bvert_co_get;
+ r_nearest2d->get_edge_verts_index = cb_bedge_verts_get;
+ r_nearest2d->copy_vert_no = cb_bvert_no_copy;
+ r_nearest2d->get_tri_verts_index = NULL;
+ r_nearest2d->get_tri_edges_index = NULL;
+
+ r_nearest2d->bm = sod->treedata_editmesh.em->bm;
+ }
+
+ r_nearest2d->is_persp = is_persp;
+ r_nearest2d->use_backface_culling = use_backface_culling;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1689,11 +1707,11 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
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);
+ nearest2d.get_edge_verts_index(*r_index, &nearest2d, vindex);
const float *v_pair[2];
- nearest2d.get_vert_co(vindex[0], nearest2d.userdata, &v_pair[0]);
- nearest2d.get_vert_co(vindex[1], nearest2d.userdata, &v_pair[1]);
+ nearest2d.get_vert_co(vindex[0], &nearest2d, &v_pair[0]);
+ nearest2d.get_vert_co(vindex[1], &nearest2d, &v_pair[1]);
struct DistProjectedAABBPrecalc neasrest_precalc;
{
@@ -1740,7 +1758,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
if (r_no) {
float imat[4][4];
invert_m4_m4(imat, obmat);
- nearest2d.copy_vert_no(vindex[v_id], nearest2d.userdata, r_no);
+ nearest2d.copy_vert_no(vindex[v_id], &nearest2d, r_no);
mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index ca8b86d525d..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"
@@ -374,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,
@@ -494,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;
}
@@ -529,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;
}
@@ -748,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)
@@ -851,7 +802,7 @@ void ED_OT_undo_history(wmOperatorType *ot)
/* api callbacks */
ot->invoke = undo_history_invoke;
ot->exec = undo_history_exec;
- ot->poll = undo_history_poll;
+ ot->poll = ed_undo_is_init_and_screenactive_poll;
RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
}
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index b339bfbdc47..90a09c87cc6 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -55,6 +55,7 @@ set(SRC
../include/ED_clip.h
../include/ED_curve.h
../include/ED_datafiles.h
+ ../include/ED_file_indexer.h
../include/ED_fileselect.h
../include/ED_geometry.h
../include/ED_gizmo_library.h
diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c
index ccbde07f5b1..3e85862a847 100644
--- a/source/blender/editors/util/ed_draw.c
+++ b/source/blender/editors/util/ed_draw.c
@@ -599,9 +599,9 @@ static void metadata_custom_draw_fields(const char *field, const char *value, vo
}
MetadataCustomDrawContext *ctx = (MetadataCustomDrawContext *)ctx_v;
char temp_str[MAX_METADATA_STR];
- BLI_snprintf(temp_str, MAX_METADATA_STR, "%s: %s", field, value);
+ SNPRINTF(temp_str, "%s: %s", field, value);
BLF_position(ctx->fontid, ctx->xmin, ctx->ymin + ctx->current_y, 0.0f);
- BLF_draw(ctx->fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(ctx->fontid, temp_str, sizeof(temp_str));
ctx->current_y += ctx->vertical_offset;
}
@@ -625,18 +625,18 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
/* first line */
if (i == 0) {
bool do_newline = false;
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[0]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[0]);
if (metadata_is_valid(ibuf, temp_str, 0, len)) {
BLF_position(fontid, xmin, ymax - vertical_offset, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
do_newline = true;
}
- len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[1]);
+ len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[1]);
if (metadata_is_valid(ibuf, temp_str, 1, len)) {
- int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ int line_width = BLF_width(fontid, temp_str, sizeof(temp_str));
BLF_position(fontid, xmax - line_width, ymax - vertical_offset, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
do_newline = true;
}
@@ -645,32 +645,32 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
}
} /* Strip */
else if (ELEM(i, 1, 2)) {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]);
if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
ofs_y += vertical_offset;
}
} /* Note (wrapped) */
else if (i == 3) {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]);
if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
struct ResultBLF info;
BLF_enable(fontid, BLF_WORD_WRAP);
BLF_wordwrap(fontid, ibuf->x - (margin * 2));
BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f);
- BLF_draw_ex(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX, &info);
+ BLF_draw_ex(fontid, temp_str, sizeof(temp_str), &info);
BLF_wordwrap(fontid, 0);
BLF_disable(fontid, BLF_WORD_WRAP);
ofs_y += vertical_offset * info.lines;
}
}
else {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]);
if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
- int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ int line_width = BLF_width(fontid, temp_str, sizeof(temp_str));
BLF_position(fontid, xmax - line_width, ymax - vertical_offset - ofs_y, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
ofs_y += vertical_offset;
}
}
@@ -687,12 +687,12 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
int ofs_x = 0;
ofs_y = ctx.current_y;
for (int i = 5; i < 10; i++) {
- int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i]);
+ int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i]);
if (metadata_is_valid(ibuf, temp_str, i, len)) {
BLF_position(fontid, xmin + ofs_x, ymin + ofs_y, 0.0f);
- BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw(fontid, temp_str, sizeof(temp_str));
- ofs_x += BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX) + UI_UNIT_X;
+ ofs_x += BLF_width(fontid, temp_str, sizeof(temp_str)) + UI_UNIT_X;
}
}
}
diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c
index b4a93eb996c..b8efbad1ad9 100644
--- a/source/blender/editors/util/ed_transverts.c
+++ b/source/blender/editors/util/ed_transverts.c
@@ -41,6 +41,7 @@
#include "BKE_editmesh.h"
#include "BKE_lattice.h"
#include "BKE_mesh_iterators.h"
+#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -168,11 +169,7 @@ void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
}
}
-static void set_mapped_co(void *vuserdata,
- int index,
- const float co[3],
- const float UNUSED(no[3]),
- const short UNUSED(no_s[3]))
+static void set_mapped_co(void *vuserdata, int index, const float co[3], const float UNUSED(no[3]))
{
void **userdata = vuserdata;
BMEditMesh *em = userdata[0];
@@ -315,9 +312,10 @@ void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const
userdata[1] = tvs->transverts;
}
- if (tvs->transverts && em->mesh_eval_cage) {
+ struct Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(obedit);
+ if (tvs->transverts && editmesh_eval_cage) {
BM_mesh_elem_table_ensure(bm, BM_VERT);
- BKE_mesh_foreach_mapped_vert(em->mesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP);
+ BKE_mesh_foreach_mapped_vert(editmesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP);
}
}
else if (obedit->type == OB_ARMATURE) {
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 8e94dc23085..0320a2a9a1a 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -35,6 +35,7 @@
#include "BKE_collection.h"
#include "BKE_global.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_multires.h"
@@ -352,6 +353,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);
@@ -361,13 +363,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);
@@ -400,7 +402,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);
@@ -433,11 +435,27 @@ void unpack_menu(bContext *C,
UI_popup_menu_end(C, pup);
}
-void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_id, ID *new_id)
+void ED_spacedata_id_remap(struct ScrArea *area,
+ struct SpaceLink *sl,
+ const struct IDRemapper *mappings)
+{
+ SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
+ if (st && st->id_remap) {
+ st->id_remap(area, sl, mappings);
+ }
+}
+
+void ED_spacedata_id_remap_single(struct ScrArea *area,
+ struct SpaceLink *sl,
+ ID *old_id,
+ ID *new_id)
{
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->id_remap) {
- st->id_remap(area, sl, old_id, new_id);
+ struct IDRemapper *mappings = BKE_id_remapper_create();
+ BKE_id_remapper_add(mappings, old_id, new_id);
+ st->id_remap(area, sl, mappings);
+ BKE_id_remapper_free(mappings);
}
}
diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c
index 38ae98c678f..2e983eeff39 100644
--- a/source/blender/editors/util/ed_util_imbuf.c
+++ b/source/blender/editors/util/ed_util_imbuf.c
@@ -278,13 +278,13 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
/* XXX node curve integration. */
#if 0
{
- ScrArea *sa, *cur = curarea;
+ ScrArea *area, *cur = curarea;
node_curvemap_sample(fp); /* sends global to node editor */
- for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_NODE) {
- areawinset(sa->win);
- scrarea_do_windraw(sa);
+ for (area = G.curscreen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_NODE) {
+ areawinset(area->win);
+ scrarea_do_windraw(area);
}
}
node_curvemap_sample(NULL); /* clears global in node editor */
@@ -385,12 +385,12 @@ static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *e
static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa == NULL) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
return;
}
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
image_sample_apply(C, op, event);
break;
@@ -432,9 +432,9 @@ void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
info->zfp);
if (info->sample_size > 1) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_IMAGE) {
+ if (area && area->spacetype == SPACE_IMAGE) {
const wmWindow *win = CTX_wm_window(C);
const wmEvent *event = win->eventstate;
@@ -482,11 +482,11 @@ void ED_imbuf_sample_exit(bContext *C, wmOperator *op)
int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
if (region->regiontype == RGN_TYPE_WINDOW) {
if (ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
return OPERATOR_PASS_THROUGH;
diff --git a/source/blender/editors/util/ed_util_ops.cc b/source/blender/editors/util/ed_util_ops.cc
index a1b17d799bc..ae37dab7bb4 100644
--- a/source/blender/editors/util/ed_util_ops.cc
+++ b/source/blender/editors/util/ed_util_ops.cc
@@ -121,6 +121,22 @@ static void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot)
FILE_SORT_DEFAULT);
}
+static bool lib_id_generate_preview_poll(bContext *C)
+{
+ if (!lib_id_preview_editing_poll(C)) {
+ return false;
+ }
+
+ const PointerRNA idptr = CTX_data_pointer_get(C, "id");
+ const ID *id = (ID *)idptr.data;
+ if (GS(id->name) == ID_NT) {
+ CTX_wm_operator_poll_msg_set(C, TIP_("Can't generate automatic preview for node group"));
+ return false;
+ }
+
+ return true;
+}
+
static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op))
{
PointerRNA idptr = CTX_data_pointer_get(C, "id");
@@ -148,13 +164,57 @@ static void ED_OT_lib_id_generate_preview(wmOperatorType *ot)
ot->idname = "ED_OT_lib_id_generate_preview";
/* api callbacks */
- ot->poll = lib_id_preview_editing_poll;
+ ot->poll = lib_id_generate_preview_poll;
ot->exec = lib_id_generate_preview_exec;
/* flags */
ot->flag = OPTYPE_INTERNAL | OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static bool lib_id_generate_preview_from_object_poll(bContext *C)
+{
+ if (!lib_id_preview_editing_poll(C)) {
+ return false;
+ }
+ if (CTX_data_active_object(C) == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+static int lib_id_generate_preview_from_object_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PointerRNA idptr = CTX_data_pointer_get(C, "id");
+ ID *id = (ID *)idptr.data;
+
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+
+ Object *object_to_render = CTX_data_active_object(C);
+
+ BKE_previewimg_id_free(id);
+ PreviewImage *preview_image = BKE_previewimg_id_ensure(id);
+ UI_icon_render_id_ex(C, nullptr, &object_to_render->id, ICON_SIZE_PREVIEW, true, preview_image);
+
+ WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr);
+ ED_assetlist_storage_tag_main_data_dirty();
+
+ return OPERATOR_FINISHED;
+}
+
+static void ED_OT_lib_id_generate_preview_from_object(wmOperatorType *ot)
+{
+ ot->name = "Generate Preview from Object";
+ ot->description = "Create a preview for this asset by rendering the active object";
+ ot->idname = "ED_OT_lib_id_generate_preview_from_object";
+
+ /* api callbacks */
+ ot->poll = lib_id_generate_preview_from_object_poll;
+ ot->exec = lib_id_generate_preview_from_object_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_INTERNAL | OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -280,6 +340,7 @@ void ED_operatortypes_edutils()
{
WM_operatortype_append(ED_OT_lib_id_load_custom_preview);
WM_operatortype_append(ED_OT_lib_id_generate_preview);
+ WM_operatortype_append(ED_OT_lib_id_generate_preview_from_object);
WM_operatortype_append(ED_OT_lib_id_fake_user_toggle);
WM_operatortype_append(ED_OT_lib_id_unlink);
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 1fa96a932ed..9646444c103 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -74,13 +74,13 @@ typedef struct UvNearestHit {
bool uv_find_nearest_vert(struct Scene *scene,
struct Object *obedit,
const float co[2],
- const float penalty_dist,
+ float penalty_dist,
struct UvNearestHit *hit);
bool uv_find_nearest_vert_multi(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
- const float penalty_dist,
+ float penalty_dist,
struct UvNearestHit *hit);
bool uv_find_nearest_edge(struct Scene *scene,
@@ -89,7 +89,7 @@ bool uv_find_nearest_edge(struct Scene *scene,
struct UvNearestHit *hit);
bool uv_find_nearest_edge_multi(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
struct UvNearestHit *hit);
@@ -106,20 +106,20 @@ bool uv_find_nearest_face_ex(struct Scene *scene,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit,
- const bool only_in_face);
+ bool only_in_face);
bool uv_find_nearest_face(struct Scene *scene,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit);
bool uv_find_nearest_face_multi_ex(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
struct UvNearestHit *hit,
- const bool only_in_face);
+ bool only_in_face);
bool uv_find_nearest_face_multi(struct Scene *scene,
struct Object **objects,
- const uint objects_len,
+ uint objects_len,
const float co[2],
struct UvNearestHit *hit);
@@ -162,14 +162,14 @@ void UV_OT_shortest_path_select(struct wmOperatorType *ot);
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);
+ 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);
+ int cd_loop_uv_offset);
void UV_OT_select_all(struct wmOperatorType *ot);
void UV_OT_select(struct wmOperatorType *ot);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 342afa847b4..64e1fa2f768 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -180,7 +180,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
if (node && is_image_texture_node(node)) {
node->id = &ima->id;
- ED_node_tag_update_nodetree(bmain, ma->nodetree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ma->nodetree);
}
}
diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt
index b7eaf018dba..d16787714c9 100644
--- a/source/blender/freestyle/CMakeLists.txt
+++ b/source/blender/freestyle/CMakeLists.txt
@@ -594,4 +594,7 @@ if(WIN32)
endif()
blender_add_lib(bf_freestyle "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
-blender_precompile_headers(bf_freestyle FRS_precomp.cpp FRS_precomp.h)
+
+if(COMMAND target_precompile_headers)
+ target_precompile_headers(bf_freestyle PRIVATE FRS_precomp.h)
+endif()
diff --git a/source/blender/freestyle/FRS_precomp.cpp b/source/blender/freestyle/FRS_precomp.cpp
deleted file mode 100644
index 7e50a47f45b..00000000000
--- a/source/blender/freestyle/FRS_precomp.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Pre-compiled headers, see: D2606. */
-#include "FRS_precomp.h"
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 0a82c237256..455d3b5b236 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -48,6 +48,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -415,7 +416,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain,
}
nodeSetActive(ntree, output_material);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, nullptr);
return ma;
}
@@ -684,9 +685,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
vertices->co[0] = svRep[0]->point2d()[0];
vertices->co[1] = svRep[0]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
- vertices->no[0] = 0;
- vertices->no[1] = 0;
- vertices->no[2] = SHRT_MAX;
+
++vertices;
++vertex_index;
@@ -694,9 +693,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
vertices->co[0] = svRep[1]->point2d()[0];
vertices->co[1] = svRep[1]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
- vertices->no[0] = 0;
- vertices->no[1] = 0;
- vertices->no[2] = SHRT_MAX;
+
++vertices;
++vertex_index;
@@ -712,9 +709,6 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
vertices->co[0] = svRep[2]->point2d()[0];
vertices->co[1] = svRep[2]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
- vertices->no[0] = 0;
- vertices->no[1] = 0;
- vertices->no[2] = SHRT_MAX;
++vertices;
++vertex_index;
@@ -820,6 +814,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
} // loop over strokes
BKE_object_materials_test(freestyle_bmain, object_mesh, (ID *)mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
#if 0 // XXX
BLI_assert(mesh->totvert == vertex_index);
diff --git a/source/blender/freestyle/intern/image/GaussianFilter.h b/source/blender/freestyle/intern/image/GaussianFilter.h
index af537cf2d86..f6bfdbd31b0 100644
--- a/source/blender/freestyle/intern/image/GaussianFilter.h
+++ b/source/blender/freestyle/intern/image/GaussianFilter.h
@@ -123,7 +123,7 @@ class GaussianFilter {
template<class Map> float GaussianFilter::getSmoothedPixel(Map *map, int x, int y)
{
- float sum = 0.0f;
+ // float sum = 0.0f;
float L = 0.0f;
int w = (int)map->width(); // soc
int h = (int)map->height(); // soc
@@ -142,7 +142,7 @@ template<class Map> float GaussianFilter::getSmoothedPixel(Map *map, int x, int
float tmpL = map->pixel(x + j, y + i);
float m = _mask[abs(i) * _storedMaskSize + abs(j)];
L += m * tmpL;
- sum += m;
+ // sum += m;
}
}
// L /= sum;
diff --git a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
index ecdba75b864..a66380f01be 100644
--- a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
+++ b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
@@ -57,8 +57,8 @@ class FrsMaterial {
const float *iAmbiant,
const float *iSpecular,
const float *iEmission,
- const float iShininess,
- const int iPriority);
+ float iShininess,
+ int iPriority);
/** Copy constructor */
inline FrsMaterial(const FrsMaterial &m);
@@ -240,7 +240,7 @@ class FrsMaterial {
* \param a:
* Alpha component
*/
- inline void setLine(const float r, const float g, const float b, const float a);
+ inline void setLine(float r, float g, float b, float a);
/** Sets the diffuse color.
* \param r:
@@ -252,7 +252,7 @@ class FrsMaterial {
* \param a:
* Alpha component
*/
- inline void setDiffuse(const float r, const float g, const float b, const float a);
+ inline void setDiffuse(float r, float g, float b, float a);
/** Sets the specular color.
* \param r:
@@ -264,7 +264,7 @@ class FrsMaterial {
* \param a:
* Alpha component
*/
- inline void setSpecular(const float r, const float g, const float b, const float a);
+ inline void setSpecular(float r, float g, float b, float a);
/** Sets the ambient color.
* \param r:
@@ -276,7 +276,7 @@ class FrsMaterial {
* \param a:
* Alpha component
*/
- inline void setAmbient(const float r, const float g, const float b, const float a);
+ inline void setAmbient(float r, float g, float b, float a);
/** Sets the emissive color.
* \param r:
@@ -288,19 +288,19 @@ class FrsMaterial {
* \param a:
* Alpha component
*/
- inline void setEmission(const float r, const float g, const float b, const float a);
+ inline void setEmission(float r, float g, float b, float a);
/** Sets the shininess.
* \param s:
* Shininess
*/
- inline void setShininess(const float s);
+ inline void setShininess(float s);
/** Sets the line color priority.
* \param priority:
* Priority
*/
- inline void setPriority(const int priority);
+ inline void setPriority(int priority);
/* operators */
inline FrsMaterial &operator=(const FrsMaterial &m);
diff --git a/source/blender/freestyle/intern/stroke/ChainingIterators.h b/source/blender/freestyle/intern/stroke/ChainingIterators.h
index 93aba258358..66e0c30bea9 100644
--- a/source/blender/freestyle/intern/stroke/ChainingIterators.h
+++ b/source/blender/freestyle/intern/stroke/ChainingIterators.h
@@ -198,7 +198,7 @@ class ChainingIterator : public ViewEdgeInternal::ViewEdgeIterator {
return "ChainingIterator";
}
- /** Inits the iterator context.
+ /** Initializes the iterator context.
* This method is called each time a new chain is started.
* It can be used to reset some history information that you might want to keep.
*/
@@ -299,7 +299,7 @@ class ChainSilhouetteIterator : public ChainingIterator {
*/
virtual int traverse(const AdjacencyIterator &it);
- /** Inits the iterator context */
+ /** Initializes the iterator context */
virtual int init()
{
return 0;
@@ -406,7 +406,7 @@ class ChainPredicateIterator : public ChainingIterator {
*/
virtual int traverse(const AdjacencyIterator &it);
- /** Inits the iterator context */
+ /** Initializes the iterator context. */
virtual int init()
{
return 0;
diff --git a/source/blender/freestyle/intern/stroke/Curve.h b/source/blender/freestyle/intern/stroke/Curve.h
index 9a05fcd380b..b26408d8183 100644
--- a/source/blender/freestyle/intern/stroke/Curve.h
+++ b/source/blender/freestyle/intern/stroke/Curve.h
@@ -540,7 +540,7 @@ class Curve : public Interface1D {
}
const SShape *occluded_shape() const;
- const bool occludee_empty() const;
+ bool occludee_empty() const;
real z_discontinuity(int iCombination = 0) const;
int shape_id() const;
const SShape *shape() const;
diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp
index c73bb739e47..cdb85817a85 100644
--- a/source/blender/freestyle/intern/stroke/Operators.cpp
+++ b/source/blender/freestyle/intern/stroke/Operators.cpp
@@ -885,7 +885,7 @@ static int __recursiveSplit(Chain *_curve,
#endif
real _min = FLT_MAX;
++it;
- real mean = 0.0f;
+ // real mean = 0.0f;
// soc unused - real variance = 0.0f;
unsigned count = 0;
CurveInternal::CurvePointIterator next = it;
@@ -904,14 +904,14 @@ static int __recursiveSplit(Chain *_curve,
if (func(it0d) < 0) {
return -1;
}
- mean += func.result;
+ // mean += func.result;
if (func.result < _min) {
_min = func.result;
split = it;
bsplit = true;
}
}
- mean /= (float)count;
+ // mean /= (float)count;
// if ((!bsplit) || (mean - _min > mean)) { // we didn't find any minimum
if (!bsplit) { // we didn't find any minimum
diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.h b/source/blender/freestyle/intern/view_map/ViewMapIO.h
index e4c42c094d0..4b737f1eb8c 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapIO.h
+++ b/source/blender/freestyle/intern/view_map/ViewMapIO.h
@@ -44,11 +44,11 @@ namespace Options {
static const unsigned char FLOAT_VECTORS = 1;
static const unsigned char NO_OCCLUDERS = 2;
-void setFlags(const unsigned char flags);
+void setFlags(unsigned char flags);
-void addFlags(const unsigned char flags);
+void addFlags(unsigned char flags);
-void rmFlags(const unsigned char flags);
+void rmFlags(unsigned char flags);
unsigned char getFlags();
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.h b/source/blender/freestyle/intern/winged_edge/WEdge.h
index adc08f60ddf..92b8bc70aa8 100644
--- a/source/blender/freestyle/intern/winged_edge/WEdge.h
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.h
@@ -874,7 +874,7 @@ class WFace {
return _VerticesNormals[index];
}
- /** Returns the tex coords of the vertex of `index`. */
+ /** Returns the texture coords of the vertex of `index`. */
inline Vec2f &GetVertexTexCoords(int index)
{
return _VerticesTexCoords[index];
@@ -1225,7 +1225,7 @@ class WShape {
* orientation and (so) the face orientation. iMaterialIndex The materialIndex for this face
* iNormalsList
* The list of normals, iNormalsList[i] corresponding to the normal of the vertex
- * iVertexList[i] for that face. iTexCoordsList The list of tex coords, iTexCoordsList[i]
+ * iVertexList[i] for that face. iTexCoordsList The list of texture coords, iTexCoordsList[i]
* corresponding to the normal of the vertex iVertexList[i] for that face.
*/
virtual WFace *MakeFace(vector<WVertex *> &iVertexList,
diff --git a/source/blender/freestyle/intern/winged_edge/WXEdge.h b/source/blender/freestyle/intern/winged_edge/WXEdge.h
index b335a364365..7ef2e7bcda2 100644
--- a/source/blender/freestyle/intern/winged_edge/WXEdge.h
+++ b/source/blender/freestyle/intern/winged_edge/WXEdge.h
@@ -783,7 +783,7 @@ class WXShape : public WShape {
* The list of normals, iNormalsList[i]
* corresponding to the normal of the vertex iVertexList[i] for that face.
* - iTexCoordsList:
- * The list of tex coords, iTexCoordsList[i]
+ * The list of texture coords, iTexCoordsList[i]
* corresponding to the normal of the vertex iVertexList[i] for that face.
*/
virtual WFace *MakeFace(vector<WVertex *> &iVertexList,
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index a591aaed34a..e869927c33b 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -60,11 +60,21 @@ class FieldInput;
struct FieldInputs;
/**
+ * Have a fixed set of base node types, because all code that works with field nodes has to
+ * understand those.
+ */
+enum class FieldNodeType {
+ Input,
+ Operation,
+ Constant,
+};
+
+/**
* A node in a field-tree. It has at least one output that can be referenced by fields.
*/
class FieldNode {
private:
- bool is_input_;
+ FieldNodeType node_type_;
protected:
/**
@@ -76,14 +86,13 @@ class FieldNode {
std::shared_ptr<const FieldInputs> field_inputs_;
public:
- FieldNode(bool is_input);
+ FieldNode(FieldNodeType node_type);
virtual ~FieldNode() = default;
virtual const CPPType &output_cpp_type(int output_index) const = 0;
- bool is_input() const;
- bool is_operation() const;
+ FieldNodeType node_type() const;
bool depends_on_input() const;
const std::shared_ptr<const FieldInputs> &field_inputs() const;
@@ -267,6 +276,20 @@ class FieldInput : public FieldNode {
const CPPType &output_cpp_type(int output_index) const override;
};
+class FieldConstant : public FieldNode {
+ private:
+ const CPPType &type_;
+ void *value_;
+
+ public:
+ FieldConstant(const CPPType &type, const void *value);
+ ~FieldConstant();
+
+ const CPPType &output_cpp_type(int output_index) const override;
+ const CPPType &type() const;
+ GPointer value() const;
+};
+
/**
* Keeps track of the inputs of a field.
*/
@@ -285,7 +308,7 @@ struct FieldInputs {
*/
class FieldContext {
public:
- ~FieldContext() = default;
+ virtual ~FieldContext() = default;
virtual GVArray get_varray_for_input(const FieldInput &field_input,
IndexMask mask,
@@ -425,7 +448,7 @@ class FieldEvaluator : NonMovable, NonCopyable {
* to avoid calculations for unnecessary elements later on. The evaluator will own the indices in
* some cases, so it must live at least as long as the returned mask.
*/
- IndexMask get_evaluated_as_mask(const int field_index);
+ IndexMask get_evaluated_as_mask(int field_index);
};
/**
@@ -468,9 +491,7 @@ template<typename T> T evaluate_constant_field(const Field<T> &field)
template<typename T> Field<T> make_constant_field(T value)
{
- auto constant_fn = std::make_unique<fn::CustomMF_Constant<T>>(std::forward<T>(value));
- auto operation = std::make_shared<FieldOperation>(std::move(constant_fn));
- return Field<T>{GField{std::move(operation), 0}};
+ return make_constant_field(CPPType::get<T>(), &value);
}
GField make_constant_field(const CPPType &type, const void *value);
@@ -552,18 +573,13 @@ template<typename T> struct ValueOrField {
/** \name #FieldNode Inline Methods
* \{ */
-inline FieldNode::FieldNode(bool is_input) : is_input_(is_input)
-{
-}
-
-inline bool FieldNode::is_input() const
+inline FieldNode::FieldNode(const FieldNodeType node_type) : node_type_(node_type)
{
- return is_input_;
}
-inline bool FieldNode::is_operation() const
+inline FieldNodeType FieldNode::node_type() const
{
- return !is_input_;
+ return node_type_;
}
inline bool FieldNode::depends_on_input() const
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
index 03e81b13714..bcb710e3472 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -47,15 +47,15 @@ class GVArrayImpl {
int64_t size_;
public:
- GVArrayImpl(const CPPType &type, const int64_t size);
+ GVArrayImpl(const CPPType &type, int64_t size);
virtual ~GVArrayImpl() = default;
const CPPType &type() const;
int64_t size() const;
- virtual void get(const int64_t index, void *r_value) const;
- virtual void get_to_uninitialized(const int64_t index, void *r_value) const = 0;
+ virtual void get(int64_t index, void *r_value) const;
+ virtual void get_to_uninitialized(int64_t index, void *r_value) const = 0;
virtual bool is_span() const;
virtual GSpan get_internal_span() const;
@@ -73,11 +73,11 @@ class GVArrayImpl {
/* A generic version of #VMutableArrayImpl. */
class GVMutableArrayImpl : public GVArrayImpl {
public:
- GVMutableArrayImpl(const CPPType &type, const int64_t size);
+ GVMutableArrayImpl(const CPPType &type, int64_t size);
- virtual void set_by_copy(const int64_t index, const void *value);
- virtual void set_by_relocate(const int64_t index, void *value);
- virtual void set_by_move(const int64_t index, void *value) = 0;
+ virtual void set_by_copy(int64_t index, const void *value);
+ virtual void set_by_relocate(int64_t index, void *value);
+ virtual void set_by_move(int64_t index, void *value) = 0;
virtual void set_all(const void *src);
@@ -173,8 +173,13 @@ class GVArrayCommon {
*/
void get_internal_single_to_uninitialized(void *r_value) const;
- void get(const int64_t index, void *r_value) const;
- void get_to_uninitialized(const int64_t index, void *r_value) const;
+ void get(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(int64_t index) const;
+ void get_to_uninitialized(int64_t index, void *r_value) const;
};
/** Generic version of #VArray. */
@@ -195,9 +200,9 @@ class GVArray : public GVArrayCommon {
template<typename ImplT, typename... Args> static GVArray For(Args &&...args);
- static GVArray ForSingle(const CPPType &type, const int64_t size, const void *value);
- static GVArray ForSingleRef(const CPPType &type, const int64_t size, const void *value);
- static GVArray ForSingleDefault(const CPPType &type, const int64_t size);
+ static GVArray ForSingle(const CPPType &type, int64_t size, const void *value);
+ static GVArray ForSingleRef(const CPPType &type, int64_t size, const void *value);
+ static GVArray ForSingleDefault(const CPPType &type, int64_t size);
static GVArray ForSpan(GSpan span);
static GVArray ForGArray(GArray<> array);
static GVArray ForEmpty(const CPPType &type);
@@ -239,9 +244,9 @@ class GVMutableArray : public GVArrayCommon {
template<typename T> bool try_assign_VMutableArray(VMutableArray<T> &varray) const;
- void set_by_copy(const int64_t index, const void *value);
- void set_by_move(const int64_t index, void *value);
- void set_by_relocate(const int64_t index, void *value);
+ void set_by_copy(int64_t index, const void *value);
+ void set_by_move(int64_t index, void *value);
+ void set_by_relocate(int64_t index, void *value);
void fill(const void *value);
/**
@@ -588,15 +593,15 @@ class GVArrayImpl_For_GSpan : public GVMutableArrayImpl {
GVArrayImpl_For_GSpan(const GMutableSpan span);
protected:
- GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size);
+ GVArrayImpl_For_GSpan(const CPPType &type, int64_t size);
public:
- void get(const int64_t index, void *r_value) const override;
- void get_to_uninitialized(const int64_t index, void *r_value) const override;
+ void get(int64_t index, void *r_value) const override;
+ void get_to_uninitialized(int64_t index, void *r_value) const override;
- void set_by_copy(const int64_t index, const void *value) override;
- void set_by_move(const int64_t index, void *value) override;
- void set_by_relocate(const int64_t index, void *value) override;
+ void set_by_copy(int64_t index, const void *value) override;
+ void set_by_move(int64_t index, void *value) override;
+ void set_by_relocate(int64_t index, void *value) override;
bool is_span() const override;
GSpan get_internal_span() const override;
@@ -691,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
{
@@ -738,8 +753,7 @@ namespace detail {
template<typename StorageT> inline GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get()
{
static_assert(std::is_base_of_v<GVArrayImpl, StorageT> ||
- std::is_same_v<StorageT, const GVArrayImpl *> ||
- std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>);
+ is_same_any_v<StorageT, const GVArrayImpl *, std::shared_ptr<const GVArrayImpl>>);
if constexpr (std::is_base_of_v<GVArrayImpl, StorageT>) {
return {[](const void *buffer) {
diff --git a/source/blender/functions/FN_generic_virtual_vector_array.hh b/source/blender/functions/FN_generic_virtual_vector_array.hh
index b80e21eaef1..b89ca22fe7e 100644
--- a/source/blender/functions/FN_generic_virtual_vector_array.hh
+++ b/source/blender/functions/FN_generic_virtual_vector_array.hh
@@ -88,10 +88,10 @@ class GVVectorArray {
}
protected:
- virtual int64_t get_vector_size_impl(const int64_t index) const = 0;
+ virtual int64_t get_vector_size_impl(int64_t index) const = 0;
- virtual void get_vector_element_impl(const int64_t index,
- const int64_t index_in_vector,
+ virtual void get_vector_element_impl(int64_t index,
+ int64_t index_in_vector,
void *r_value) const = 0;
virtual bool is_single_vector_impl() const
@@ -114,8 +114,8 @@ class GVArray_For_GVVectorArrayIndex : public GVArrayImpl {
}
protected:
- void get(const int64_t index_in_vector, void *r_value) const override;
- void get_to_uninitialized(const int64_t index_in_vector, void *r_value) const override;
+ void get(int64_t index_in_vector, void *r_value) const override;
+ void get_to_uninitialized(int64_t index_in_vector, void *r_value) const override;
};
class GVVectorArray_For_SingleGVArray : public GVVectorArray {
@@ -129,9 +129,9 @@ class GVVectorArray_For_SingleGVArray : public GVVectorArray {
}
protected:
- int64_t get_vector_size_impl(const int64_t index) const override;
- void get_vector_element_impl(const int64_t index,
- const int64_t index_in_vector,
+ int64_t get_vector_size_impl(int64_t index) const override;
+ void get_vector_element_impl(int64_t index,
+ int64_t index_in_vector,
void *r_value) const override;
bool is_single_vector_impl() const override;
@@ -148,9 +148,9 @@ class GVVectorArray_For_SingleGSpan : public GVVectorArray {
}
protected:
- int64_t get_vector_size_impl(const int64_t UNUSED(index)) const override;
- void get_vector_element_impl(const int64_t UNUSED(index),
- const int64_t index_in_vector,
+ int64_t get_vector_size_impl(int64_t UNUSED(index)) const override;
+ void get_vector_element_impl(int64_t UNUSED(index),
+ int64_t index_in_vector,
void *r_value) const override;
bool is_single_vector_impl() const override;
diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh
index a26eb1045a7..d73bc089278 100644
--- a/source/blender/functions/FN_multi_function_procedure.hh
+++ b/source/blender/functions/FN_multi_function_procedure.hh
@@ -268,6 +268,7 @@ class MFProcedure : NonCopyable, NonMovable {
Vector<MFReturnInstruction *> return_instructions_;
Vector<MFVariable *> variables_;
Vector<MFParameter> params_;
+ Vector<destruct_ptr<MultiFunction>> owned_functions_;
MFInstruction *entry_ = nullptr;
friend class MFProcedureDotExport;
@@ -284,9 +285,10 @@ class MFProcedure : NonCopyable, NonMovable {
MFReturnInstruction &new_return_instruction();
void add_parameter(MFParamType::InterfaceType interface_type, MFVariable &variable);
-
Span<ConstMFParameter> params() const;
+ template<typename T, typename... Args> const MultiFunction &construct_function(Args &&...args);
+
MFInstruction *entry();
const MFInstruction *entry() const;
void set_entry(MFInstruction &entry);
@@ -550,6 +552,15 @@ inline Span<const MFVariable *> MFProcedure::variables() const
return variables_;
}
+template<typename T, typename... Args>
+inline const MultiFunction &MFProcedure::construct_function(Args &&...args)
+{
+ destruct_ptr<T> fn = allocator_.construct<T>(std::forward<Args>(args)...);
+ const MultiFunction &fn_ref = *fn;
+ owned_functions_.append(std::move(fn));
+ return fn_ref;
+}
+
/** \} */
} // namespace blender::fn
diff --git a/source/blender/functions/intern/cpp_types.cc b/source/blender/functions/intern/cpp_types.cc
index 058fb76af2b..0bbfbc8cb10 100644
--- a/source/blender/functions/intern/cpp_types.cc
+++ b/source/blender/functions/intern/cpp_types.cc
@@ -18,9 +18,8 @@
#include "FN_field_cpp_type.hh"
#include "BLI_color.hh"
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
+#include "BLI_math_vec_types.hh"
namespace blender::fn {
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 604e5c6d13f..d6b83c42294 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -64,17 +64,26 @@ static FieldTreeInfo preprocess_field_tree(Span<GFieldRef> entry_fields)
while (!fields_to_check.is_empty()) {
GFieldRef field = fields_to_check.pop();
- if (field.node().is_input()) {
- const FieldInput &field_input = static_cast<const FieldInput &>(field.node());
- field_tree_info.deduplicated_field_inputs.add(field_input);
- continue;
- }
- BLI_assert(field.node().is_operation());
- const FieldOperation &operation = static_cast<const FieldOperation &>(field.node());
- for (const GFieldRef operation_input : operation.inputs()) {
- field_tree_info.field_users.add(operation_input, field);
- if (handled_fields.add(operation_input)) {
- fields_to_check.push(operation_input);
+ const FieldNode &field_node = field.node();
+ switch (field_node.node_type()) {
+ case FieldNodeType::Input: {
+ const FieldInput &field_input = static_cast<const FieldInput &>(field_node);
+ field_tree_info.deduplicated_field_inputs.add(field_input);
+ break;
+ }
+ case FieldNodeType::Operation: {
+ const FieldOperation &operation = static_cast<const FieldOperation &>(field_node);
+ for (const GFieldRef operation_input : operation.inputs()) {
+ field_tree_info.field_users.add(operation_input, field);
+ if (handled_fields.add(operation_input)) {
+ fields_to_check.push(operation_input);
+ }
+ }
+ break;
+ }
+ case FieldNodeType::Constant: {
+ /* Nothing to do. */
+ break;
}
}
}
@@ -179,56 +188,71 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
fields_to_check.pop();
continue;
}
- /* Field inputs should already be handled above. */
- BLI_assert(field.node().is_operation());
-
- const FieldOperation &operation = static_cast<const FieldOperation &>(field.node());
- const Span<GField> operation_inputs = operation.inputs();
-
- if (field_with_index.current_input_index < operation_inputs.size()) {
- /* Not all inputs are handled yet. Push the next input field to the stack and increment the
- * input index. */
- fields_to_check.push({operation_inputs[field_with_index.current_input_index]});
- field_with_index.current_input_index++;
- }
- else {
- /* All inputs variables are ready, now gather all variables that are used by the function
- * and call it. */
- const MultiFunction &multi_function = operation.multi_function();
- Vector<MFVariable *> variables(multi_function.param_amount());
-
- int param_input_index = 0;
- int param_output_index = 0;
- for (const int param_index : multi_function.param_indices()) {
- const MFParamType param_type = multi_function.param_type(param_index);
- const MFParamType::InterfaceType interface_type = param_type.interface_type();
- if (interface_type == MFParamType::Input) {
- const GField &input_field = operation_inputs[param_input_index];
- variables[param_index] = variable_by_field.lookup(input_field);
- param_input_index++;
- }
- else if (interface_type == MFParamType::Output) {
- const GFieldRef output_field{operation, param_output_index};
- const bool output_is_ignored =
- field_tree_info.field_users.lookup(output_field).is_empty() &&
- !output_fields.contains(output_field);
- if (output_is_ignored) {
- /* Ignored outputs don't need a variable. */
- variables[param_index] = nullptr;
- }
- else {
- /* Create a new variable for used outputs. */
- MFVariable &new_variable = procedure.new_variable(param_type.data_type());
- variables[param_index] = &new_variable;
- variable_by_field.add_new(output_field, &new_variable);
- }
- param_output_index++;
+ const FieldNode &field_node = field.node();
+ switch (field_node.node_type()) {
+ case FieldNodeType::Input: {
+ /* Field inputs should already be handled above. */
+ break;
+ }
+ case FieldNodeType::Operation: {
+ const FieldOperation &operation_node = static_cast<const FieldOperation &>(field.node());
+ const Span<GField> operation_inputs = operation_node.inputs();
+
+ if (field_with_index.current_input_index < operation_inputs.size()) {
+ /* Not all inputs are handled yet. Push the next input field to the stack and increment
+ * the input index. */
+ fields_to_check.push({operation_inputs[field_with_index.current_input_index]});
+ field_with_index.current_input_index++;
}
else {
- BLI_assert_unreachable();
+ /* All inputs variables are ready, now gather all variables that are used by the
+ * function and call it. */
+ const MultiFunction &multi_function = operation_node.multi_function();
+ Vector<MFVariable *> variables(multi_function.param_amount());
+
+ int param_input_index = 0;
+ int param_output_index = 0;
+ for (const int param_index : multi_function.param_indices()) {
+ const MFParamType param_type = multi_function.param_type(param_index);
+ const MFParamType::InterfaceType interface_type = param_type.interface_type();
+ if (interface_type == MFParamType::Input) {
+ const GField &input_field = operation_inputs[param_input_index];
+ variables[param_index] = variable_by_field.lookup(input_field);
+ param_input_index++;
+ }
+ else if (interface_type == MFParamType::Output) {
+ const GFieldRef output_field{operation_node, param_output_index};
+ const bool output_is_ignored =
+ field_tree_info.field_users.lookup(output_field).is_empty() &&
+ !output_fields.contains(output_field);
+ if (output_is_ignored) {
+ /* Ignored outputs don't need a variable. */
+ variables[param_index] = nullptr;
+ }
+ else {
+ /* Create a new variable for used outputs. */
+ MFVariable &new_variable = procedure.new_variable(param_type.data_type());
+ variables[param_index] = &new_variable;
+ variable_by_field.add_new(output_field, &new_variable);
+ }
+ param_output_index++;
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ }
+ builder.add_call_with_all_variables(multi_function, variables);
}
+ break;
+ }
+ case FieldNodeType::Constant: {
+ const FieldConstant &constant_node = static_cast<const FieldConstant &>(field_node);
+ const MultiFunction &fn = procedure.construct_function<CustomMF_GenericConstant>(
+ constant_node.type(), constant_node.value().get(), false);
+ MFVariable &new_variable = *builder.add_call<1>(fn)[0];
+ variable_by_field.add_new(field, &new_variable);
+ break;
}
- builder.add_call_with_all_variables(multi_function, variables);
}
}
}
@@ -301,17 +325,29 @@ Vector<GVArray> evaluate_fields(ResourceScope &scope,
Vector<GVArray> field_context_inputs = get_field_context_inputs(
scope, mask, context, field_tree_info.deduplicated_field_inputs);
- /* Finish fields that output an input varray directly. For those we don't have to do any further
- * processing. */
+ /* Finish fields that don't need any processing directly. */
for (const int out_index : fields_to_evaluate.index_range()) {
const GFieldRef &field = fields_to_evaluate[out_index];
- if (!field.node().is_input()) {
- continue;
+ const FieldNode &field_node = field.node();
+ switch (field_node.node_type()) {
+ case FieldNodeType::Input: {
+ const FieldInput &field_input = static_cast<const FieldInput &>(field.node());
+ const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of(
+ field_input);
+ const GVArray &varray = field_context_inputs[field_input_index];
+ r_varrays[out_index] = varray;
+ break;
+ }
+ case FieldNodeType::Constant: {
+ const FieldConstant &field_constant = static_cast<const FieldConstant &>(field.node());
+ r_varrays[out_index] = GVArray::ForSingleRef(
+ field_constant.type(), mask.min_array_size(), field_constant.value().get());
+ break;
+ }
+ case FieldNodeType::Operation: {
+ break;
+ }
}
- const FieldInput &field_input = static_cast<const FieldInput &>(field.node());
- const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of(field_input);
- const GVArray &varray = field_context_inputs[field_input_index];
- r_varrays[out_index] = varray;
}
Set<GFieldRef> varying_fields = find_varying_fields(field_tree_info, field_context_inputs);
@@ -491,9 +527,8 @@ GField make_field_constant_if_possible(GField field)
GField make_constant_field(const CPPType &type, const void *value)
{
- auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, value, true);
- auto operation = std::make_shared<FieldOperation>(std::move(constant_fn));
- return GField{std::move(operation), 0};
+ auto constant_node = std::make_shared<FieldConstant>(type, value);
+ return GField{std::move(constant_node)};
}
GVArray FieldContext::get_varray_for_input(const FieldInput &field_input,
@@ -602,7 +637,7 @@ static std::shared_ptr<const FieldInputs> combine_field_inputs(Span<GField> fiel
}
FieldOperation::FieldOperation(const MultiFunction &function, Vector<GField> inputs)
- : FieldNode(false), function_(&function), inputs_(std::move(inputs))
+ : FieldNode(FieldNodeType::Operation), function_(&function), inputs_(std::move(inputs))
{
field_inputs_ = combine_field_inputs(inputs_);
}
@@ -612,7 +647,7 @@ FieldOperation::FieldOperation(const MultiFunction &function, Vector<GField> inp
*/
FieldInput::FieldInput(const CPPType &type, std::string debug_name)
- : FieldNode(true), type_(&type), debug_name_(std::move(debug_name))
+ : FieldNode(FieldNodeType::Input), type_(&type), debug_name_(std::move(debug_name))
{
std::shared_ptr<FieldInputs> field_inputs = std::make_shared<FieldInputs>();
field_inputs->nodes.add_new(this);
@@ -621,6 +656,40 @@ FieldInput::FieldInput(const CPPType &type, std::string debug_name)
}
/* --------------------------------------------------------------------
+ * FieldConstant.
+ */
+
+FieldConstant::FieldConstant(const CPPType &type, const void *value)
+ : FieldNode(FieldNodeType::Constant), type_(type)
+{
+ value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ type.copy_construct(value, value_);
+}
+
+FieldConstant::~FieldConstant()
+{
+ type_.destruct(value_);
+ MEM_freeN(value_);
+}
+
+const CPPType &FieldConstant::output_cpp_type(int output_index) const
+{
+ BLI_assert(output_index == 0);
+ UNUSED_VARS_NDEBUG(output_index);
+ return type_;
+}
+
+const CPPType &FieldConstant::type() const
+{
+ return type_;
+}
+
+GPointer FieldConstant::value() const
+{
+ return {type_, value_};
+}
+
+/* --------------------------------------------------------------------
* FieldEvaluator.
*/
diff --git a/source/blender/functions/intern/multi_function_procedure_optimization.cc b/source/blender/functions/intern/multi_function_procedure_optimization.cc
index f220c85e535..9ad428dcbd8 100644
--- a/source/blender/functions/intern/multi_function_procedure_optimization.cc
+++ b/source/blender/functions/intern/multi_function_procedure_optimization.cc
@@ -81,7 +81,7 @@ void move_destructs_up(MFProcedure &procedure, MFInstruction &block_end_instr)
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. */
+ /* Stop when there is no previous instruction. E.g. when this is the first instruction. */
break;
}
}
diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt
index de508ddc540..f7ddd393b4d 100644
--- a/source/blender/geometry/CMakeLists.txt
+++ b/source/blender/geometry/CMakeLists.txt
@@ -30,10 +30,14 @@ set(INC
)
set(SRC
+ intern/mesh_merge_by_distance.cc
intern/mesh_to_curve_convert.cc
+ intern/point_merge_by_distance.cc
intern/realize_instances.cc
+ GEO_mesh_merge_by_distance.hh
GEO_mesh_to_curve.hh
+ GEO_point_merge_by_distance.hh
GEO_realize_instances.hh
)
diff --git a/source/blender/geometry/GEO_mesh_merge_by_distance.hh b/source/blender/geometry/GEO_mesh_merge_by_distance.hh
new file mode 100644
index 00000000000..1d64680a02b
--- /dev/null
+++ b/source/blender/geometry/GEO_mesh_merge_by_distance.hh
@@ -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.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include "BLI_index_mask.hh"
+#include "BLI_span.hh"
+
+struct Mesh;
+
+/** \file
+ * \ingroup geo
+ */
+
+namespace blender::geometry {
+
+/**
+ * Merge selected vertices into other selected vertices within the \a merge_distance. The merged
+ * indices favor speed over accuracy, since the results will depend on the order of the vertices.
+ *
+ * \returns #std::nullopt if the mesh should not be changed (no vertices are merged), in order to
+ * avoid copying the input. Otherwise returns the new mesh with merged geometry.
+ */
+std::optional<Mesh *> mesh_merge_by_distance_all(const Mesh &mesh,
+ IndexMask selection,
+ float merge_distance);
+
+/**
+ * Merge selected vertices along edges to other selected vertices. Only vertices connected by edges
+ * are considered for merging.
+ *
+ * \returns #std::nullopt if the mesh should not be changed (no vertices are merged), in order to
+ * avoid copying the input. Otherwise returns the new mesh with merged geometry.
+ */
+std::optional<Mesh *> mesh_merge_by_distance_connected(const Mesh &mesh,
+ Span<bool> selection,
+ float merge_distance,
+ bool only_loose_edges);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_point_merge_by_distance.hh b/source/blender/geometry/GEO_point_merge_by_distance.hh
new file mode 100644
index 00000000000..6766f3c559d
--- /dev/null
+++ b/source/blender/geometry/GEO_point_merge_by_distance.hh
@@ -0,0 +1,38 @@
+/*
+ * 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_index_mask.hh"
+
+#pragma once
+
+struct PointCloud;
+class PointCloudComponent;
+
+/** \file
+ * \ingroup geo
+ */
+
+namespace blender::geometry {
+
+/**
+ * Merge selected points into other selected points within the \a merge_distance. The merged
+ * indices favor speed over accuracy, since the results will depend on the order of the points.
+ */
+PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
+ const float merge_distance,
+ const IndexMask selection);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/mesh_merge_by_distance.cc b/source/blender/geometry/intern/mesh_merge_by_distance.cc
new file mode 100644
index 00000000000..1a07ebf31f6
--- /dev/null
+++ b/source/blender/geometry/intern/mesh_merge_by_distance.cc
@@ -0,0 +1,1729 @@
+/*
+ * 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_array.hh"
+#include "BLI_index_mask.hh"
+#include "BLI_kdtree.h"
+#include "BLI_math_vector.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+
+#include "GEO_mesh_merge_by_distance.hh"
+
+//#define USE_WELD_DEBUG
+//#define USE_WELD_NORMALS
+
+namespace blender::geometry {
+
+/* Indicates when the element was not computed. */
+#define OUT_OF_CONTEXT (int)(-1)
+/* Indicates if the edge or face will be collapsed. */
+#define ELEM_COLLAPSED (int)(-2)
+/* indicates whether an edge or vertex in groups_map will be merged. */
+#define ELEM_MERGED (int)(-2)
+
+/* Used to indicate a range in an array specifying a group. */
+struct WeldGroup {
+ int len;
+ int ofs;
+};
+
+/* Edge groups that will be merged. Final vertices are also indicated. */
+struct WeldGroupEdge {
+ struct WeldGroup group;
+ int v1;
+ int v2;
+};
+
+struct WeldVert {
+ /* Indexes relative to the original Mesh. */
+ int vert_dest;
+ int vert_orig;
+};
+
+struct WeldEdge {
+ union {
+ int flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ int edge_dest;
+ int edge_orig;
+ int vert_a;
+ int vert_b;
+ };
+ };
+};
+
+struct WeldLoop {
+ union {
+ int flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ int vert;
+ int edge;
+ int loop_orig;
+ int loop_skip_to;
+ };
+ };
+};
+
+struct WeldPoly {
+ union {
+ int flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ int poly_dst;
+ int poly_orig;
+ int loop_start;
+ int loop_end;
+ /* Final Polygon Size. */
+ int len;
+ /* Group of loops that will be affected. */
+ struct WeldGroup loops;
+ };
+ };
+};
+
+struct WeldMesh {
+ /* Group of vertices to be merged. */
+ Array<WeldGroup> vert_groups;
+ Array<int> vert_groups_buffer;
+
+ /* Group of edges to be merged. */
+ Array<WeldGroupEdge> edge_groups;
+ Array<int> edge_groups_buffer;
+ /* From the original index of the vertex, this indicates which group it is or is going to be
+ * merged. */
+ Array<int> edge_groups_map;
+
+ /* References all polygons and loops that will be affected. */
+ Vector<WeldLoop> wloop;
+ Vector<WeldPoly> wpoly;
+ WeldPoly *wpoly_new;
+ int wloop_len;
+ int wpoly_len;
+ int wpoly_new_len;
+
+ /* From the actual index of the element in the mesh, it indicates what is the index of the Weld
+ * element above. */
+ Array<int> loop_map;
+ Array<int> poly_map;
+
+ int vert_kill_len;
+ int edge_kill_len;
+ int loop_kill_len;
+ int poly_kill_len; /* Including the new polygons. */
+
+ /* Size of the affected polygon with more sides. */
+ int max_poly_len;
+};
+
+struct WeldLoopOfPolyIter {
+ int loop_start;
+ int loop_end;
+ Span<WeldLoop> wloop;
+ Span<MLoop> mloop;
+ Span<int> loop_map;
+ /* Weld group. */
+ int *group;
+
+ int l_curr;
+ int l_next;
+
+ /* Return */
+ int group_len;
+ int v;
+ int e;
+ char type;
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Debug Utils
+ * \{ */
+
+#ifdef USE_WELD_DEBUG
+static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
+ const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ int *group_buffer);
+
+static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter);
+
+static void weld_assert_edge_kill_len(Span<WeldEdge> wedge, const int supposed_kill_len)
+{
+ int kills = 0;
+ const WeldEdge *we = &wedge[0];
+ for (int i = wedge.size(); i--; we++) {
+ int edge_dest = we->edge_dest;
+ /* Magically includes collapsed edges. */
+ if (edge_dest != OUT_OF_CONTEXT) {
+ kills++;
+ }
+ }
+ BLI_assert(kills == supposed_kill_len);
+}
+
+static void weld_assert_poly_and_loop_kill_len(Span<WeldPoly> wpoly,
+ Span<WeldPoly> wpoly_new,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ Span<int> poly_map,
+ Span<MPoly> mpoly,
+ const int supposed_poly_kill_len,
+ const int supposed_loop_kill_len)
+{
+ int poly_kills = 0;
+ int loop_kills = mloop.size();
+ const MPoly *mp = &mpoly[0];
+ for (int i = 0; i < mpoly.size(); i++, mp++) {
+ int poly_ctx = poly_map[i];
+ if (poly_ctx != OUT_OF_CONTEXT) {
+ const WeldPoly *wp = &wpoly[poly_ctx];
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(&iter, *wp, wloop, mloop, loop_map, nullptr)) {
+ poly_kills++;
+ continue;
+ }
+ else {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ poly_kills++;
+ continue;
+ }
+ int remain = wp->len;
+ int l = wp->loop_start;
+ while (remain) {
+ int l_next = l + 1;
+ int loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag != ELEM_COLLAPSED) {
+ loop_kills--;
+ remain--;
+ }
+ }
+ else {
+ loop_kills--;
+ remain--;
+ }
+ l = l_next;
+ }
+ }
+ }
+ else {
+ loop_kills -= mp->totloop;
+ }
+ }
+
+ const WeldPoly *wp = wpoly_new.data();
+ for (int i = wpoly_new.size(); i--; wp++) {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ poly_kills++;
+ continue;
+ }
+ int remain = wp->len;
+ int l = wp->loop_start;
+ while (remain) {
+ int l_next = l + 1;
+ int loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag != ELEM_COLLAPSED) {
+ loop_kills--;
+ remain--;
+ }
+ }
+ else {
+ loop_kills--;
+ remain--;
+ }
+ l = l_next;
+ }
+ }
+
+ BLI_assert(poly_kills == supposed_poly_kill_len);
+ BLI_assert(loop_kills == supposed_loop_kill_len);
+}
+
+static void weld_assert_poly_no_vert_repetition(const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map)
+{
+ const int len = wp.len;
+ Array<int, 64> verts(len);
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) {
+ return;
+ }
+ else {
+ int i = 0;
+ while (weld_iter_loop_of_poly_next(iter)) {
+ verts[i++] = iter.v;
+ }
+ }
+ for (int i = 0; i < len; i++) {
+ int va = verts[i];
+ for (int j = i + 1; j < len; j++) {
+ int vb = verts[j];
+ BLI_assert(va != vb);
+ }
+ }
+}
+
+static void weld_assert_poly_len(const WeldPoly *wp, const Span<WeldLoop> wloop)
+{
+ if (wp->flag == ELEM_COLLAPSED) {
+ return;
+ }
+
+ int len = wp->len;
+ const WeldLoop *wl = &wloop[wp->loops.ofs];
+ BLI_assert(wp->loop_start <= wl->loop_orig);
+
+ int end_wloop = wp->loops.ofs + wp->loops.len;
+ const WeldLoop *wl_end = &wloop[end_wloop - 1];
+
+ int min_len = 0;
+ for (; wl <= wl_end; wl++) {
+ BLI_assert(wl->loop_skip_to == OUT_OF_CONTEXT); /* Not for this case. */
+ if (wl->flag != ELEM_COLLAPSED) {
+ min_len++;
+ }
+ }
+ BLI_assert(len >= min_len);
+
+ int max_len = wp->loop_end - wp->loop_start + 1;
+ BLI_assert(len <= max_len);
+}
+
+#endif /* USE_WELD_DEBUG */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vert API
+ * \{ */
+
+static Vector<WeldVert> weld_vert_ctx_alloc_and_setup(Span<int> vert_dest_map,
+ const int vert_kill_len)
+{
+ Vector<WeldVert> wvert;
+ wvert.reserve(std::min<int>(2 * vert_kill_len, vert_dest_map.size()));
+
+ for (const int i : vert_dest_map.index_range()) {
+ if (vert_dest_map[i] != OUT_OF_CONTEXT) {
+ WeldVert wv{};
+ wv.vert_dest = vert_dest_map[i];
+ wv.vert_orig = i;
+ wvert.append(wv);
+ }
+ }
+ return wvert;
+}
+
+static void weld_vert_groups_setup(Span<WeldVert> wvert,
+ Span<int> vert_dest_map,
+ MutableSpan<int> r_vert_groups_map,
+ Array<int> &r_vert_groups_buffer,
+ Array<WeldGroup> &r_vert_groups)
+{
+ /* Get weld vert groups. */
+
+ int wgroups_len = 0;
+ for (const int i : vert_dest_map.index_range()) {
+ const int vert_dest = vert_dest_map[i];
+ if (vert_dest != OUT_OF_CONTEXT) {
+ if (vert_dest != i) {
+ r_vert_groups_map[i] = ELEM_MERGED;
+ }
+ else {
+ r_vert_groups_map[i] = wgroups_len;
+ wgroups_len++;
+ }
+ }
+ else {
+ r_vert_groups_map[i] = OUT_OF_CONTEXT;
+ }
+ }
+
+ r_vert_groups.reinitialize(wgroups_len);
+ r_vert_groups.fill({0, 0});
+ MutableSpan<WeldGroup> wgroups = r_vert_groups;
+
+ for (const WeldVert &wv : wvert) {
+ int group_index = r_vert_groups_map[wv.vert_dest];
+ wgroups[group_index].len++;
+ }
+
+ int ofs = 0;
+ for (WeldGroup &wg : wgroups) {
+ wg.ofs = ofs;
+ ofs += wg.len;
+ }
+
+ BLI_assert(ofs == wvert.size());
+
+ r_vert_groups_buffer.reinitialize(ofs);
+ for (const WeldVert &wv : wvert) {
+ int group_index = r_vert_groups_map[wv.vert_dest];
+ r_vert_groups_buffer[wgroups[group_index].ofs++] = wv.vert_orig;
+ }
+
+ for (WeldGroup &wg : wgroups) {
+ wg.ofs -= wg.len;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edge API
+ * \{ */
+
+static Vector<WeldEdge> weld_edge_ctx_alloc(Span<MEdge> medge,
+ Span<int> vert_dest_map,
+ MutableSpan<int> r_edge_dest_map,
+ MutableSpan<int> r_edge_ctx_map)
+{
+ /* Edge Context. */
+ int wedge_len = 0;
+
+ Vector<WeldEdge> wedge;
+ wedge.reserve(medge.size());
+
+ for (const int i : medge.index_range()) {
+ int v1 = medge[i].v1;
+ int v2 = medge[i].v2;
+ int v_dest_1 = vert_dest_map[v1];
+ int v_dest_2 = vert_dest_map[v2];
+ if ((v_dest_1 != OUT_OF_CONTEXT) || (v_dest_2 != OUT_OF_CONTEXT)) {
+ WeldEdge we{};
+ we.vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1;
+ we.vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2;
+ we.edge_dest = OUT_OF_CONTEXT;
+ we.edge_orig = i;
+ wedge.append(we);
+ r_edge_dest_map[i] = i;
+ r_edge_ctx_map[i] = wedge_len++;
+ }
+ else {
+ r_edge_dest_map[i] = OUT_OF_CONTEXT;
+ r_edge_ctx_map[i] = OUT_OF_CONTEXT;
+ }
+ }
+
+ return wedge;
+}
+
+static void weld_edge_ctx_setup(MutableSpan<WeldGroup> r_vlinks,
+ MutableSpan<int> r_edge_dest_map,
+ MutableSpan<WeldEdge> r_wedge,
+ int *r_edge_kiil_len)
+{
+ /* Setup Edge Overlap. */
+ int edge_kill_len = 0;
+
+ MutableSpan<WeldGroup> v_links = r_vlinks;
+
+ for (WeldEdge &we : r_wedge) {
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
+
+ if (dst_vert_a == dst_vert_b) {
+ BLI_assert(we.edge_dest == OUT_OF_CONTEXT);
+ r_edge_dest_map[we.edge_orig] = ELEM_COLLAPSED;
+ we.flag = ELEM_COLLAPSED;
+ edge_kill_len++;
+ continue;
+ }
+
+ v_links[dst_vert_a].len++;
+ v_links[dst_vert_b].len++;
+ }
+
+ int link_len = 0;
+ for (WeldGroup &vl : r_vlinks) {
+ vl.ofs = link_len;
+ link_len += vl.len;
+ }
+
+ if (link_len > 0) {
+ Array<int> link_edge_buffer(link_len);
+
+ for (const int i : r_wedge.index_range()) {
+ const WeldEdge &we = r_wedge[i];
+ if (we.flag == ELEM_COLLAPSED) {
+ continue;
+ }
+
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
+
+ link_edge_buffer[v_links[dst_vert_a].ofs++] = i;
+ link_edge_buffer[v_links[dst_vert_b].ofs++] = i;
+ }
+
+ for (WeldGroup &vl : r_vlinks) {
+ /* Fix offset */
+ vl.ofs -= vl.len;
+ }
+
+ for (const int i : r_wedge.index_range()) {
+ const WeldEdge &we = r_wedge[i];
+ if (we.edge_dest != OUT_OF_CONTEXT) {
+ /* No need to retest edges.
+ * (Already includes collapsed edges). */
+ continue;
+ }
+
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
+
+ struct WeldGroup *link_a = &v_links[dst_vert_a];
+ struct WeldGroup *link_b = &v_links[dst_vert_b];
+
+ int edges_len_a = link_a->len;
+ int edges_len_b = link_b->len;
+
+ if (edges_len_a <= 1 || edges_len_b <= 1) {
+ continue;
+ }
+
+ int *edges_ctx_a = &link_edge_buffer[link_a->ofs];
+ int *edges_ctx_b = &link_edge_buffer[link_b->ofs];
+ int edge_orig = we.edge_orig;
+
+ for (; edges_len_a--; edges_ctx_a++) {
+ int e_ctx_a = *edges_ctx_a;
+ if (e_ctx_a == i) {
+ continue;
+ }
+ while (edges_len_b && *edges_ctx_b < e_ctx_a) {
+ edges_ctx_b++;
+ edges_len_b--;
+ }
+ if (edges_len_b == 0) {
+ break;
+ }
+ int e_ctx_b = *edges_ctx_b;
+ if (e_ctx_a == e_ctx_b) {
+ WeldEdge *we_b = &r_wedge[e_ctx_b];
+ BLI_assert(ELEM(we_b->vert_a, dst_vert_a, dst_vert_b));
+ BLI_assert(ELEM(we_b->vert_b, dst_vert_a, dst_vert_b));
+ BLI_assert(we_b->edge_dest == OUT_OF_CONTEXT);
+ BLI_assert(we_b->edge_orig != edge_orig);
+ r_edge_dest_map[we_b->edge_orig] = edge_orig;
+ we_b->edge_dest = edge_orig;
+ edge_kill_len++;
+ }
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_edge_kill_len(r_wedge, edge_kill_len);
+#endif
+ }
+
+ *r_edge_kiil_len = edge_kill_len;
+}
+
+static void weld_edge_groups_setup(const int medge_len,
+ const int edge_kill_len,
+ MutableSpan<WeldEdge> wedge,
+ Span<int> wedge_map,
+ MutableSpan<int> r_edge_groups_map,
+ Array<int> &r_edge_groups_buffer,
+ Array<WeldGroupEdge> &r_edge_groups)
+{
+ /* Get weld edge groups. */
+ int wgroups_len = wedge.size() - edge_kill_len;
+ r_edge_groups.reinitialize(wgroups_len);
+ r_edge_groups.fill({{0}});
+ MutableSpan<WeldGroupEdge> wegroups = r_edge_groups;
+
+ wgroups_len = 0;
+ for (const int i : IndexRange(medge_len)) {
+ int edge_ctx = wedge_map[i];
+ if (edge_ctx != OUT_OF_CONTEXT) {
+ WeldEdge *we = &wedge[edge_ctx];
+ int edge_dest = we->edge_dest;
+ if (edge_dest != OUT_OF_CONTEXT) {
+ BLI_assert(edge_dest != we->edge_orig);
+ r_edge_groups_map[i] = ELEM_MERGED;
+ }
+ else {
+ we->edge_dest = we->edge_orig;
+ wegroups[wgroups_len].v1 = we->vert_a;
+ wegroups[wgroups_len].v2 = we->vert_b;
+ r_edge_groups_map[i] = wgroups_len;
+ wgroups_len++;
+ }
+ }
+ else {
+ r_edge_groups_map[i] = OUT_OF_CONTEXT;
+ }
+ }
+
+ BLI_assert(wgroups_len == wedge.size() - edge_kill_len);
+
+ if (wgroups_len == 0) {
+ /* All edges in the context are collapsed. */
+ return;
+ }
+
+ for (const WeldEdge &we : wedge) {
+ if (we.flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ int group_index = r_edge_groups_map[we.edge_dest];
+ wegroups[group_index].group.len++;
+ }
+
+ int ofs = 0;
+ for (WeldGroupEdge &wegrp : wegroups) {
+ wegrp.group.ofs = ofs;
+ ofs += wegrp.group.len;
+ }
+
+ r_edge_groups_buffer.reinitialize(ofs);
+ for (const WeldEdge &we : wedge) {
+ if (we.flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ int group_index = r_edge_groups_map[we.edge_dest];
+ r_edge_groups_buffer[wegroups[group_index].group.ofs++] = we.edge_orig;
+ }
+
+ for (WeldGroupEdge &wegrp : wegroups) {
+ wegrp.group.ofs -= wegrp.group.len;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Poly and Loop API
+ * \{ */
+
+static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter &iter,
+ const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ int *group_buffer)
+{
+ if (wp.flag == ELEM_COLLAPSED) {
+ return false;
+ }
+
+ iter.loop_start = wp.loop_start;
+ iter.loop_end = wp.loop_end;
+ iter.wloop = wloop;
+ iter.mloop = mloop;
+ iter.loop_map = loop_map;
+ iter.group = group_buffer;
+
+ int group_len = 0;
+ if (group_buffer) {
+ /* First loop group needs more attention. */
+ int loop_start, loop_end, l;
+ loop_start = iter.loop_start;
+ loop_end = l = iter.loop_end;
+ while (l >= loop_start) {
+ const int loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->flag == ELEM_COLLAPSED) {
+ l--;
+ continue;
+ }
+ }
+ break;
+ }
+ if (l != loop_end) {
+ group_len = loop_end - l;
+ int i = 0;
+ while (l < loop_end) {
+ iter.group[i++] = ++l;
+ }
+ }
+ }
+ iter.group_len = group_len;
+
+ iter.l_next = iter.loop_start;
+#ifdef USE_WELD_DEBUG
+ iter.v = OUT_OF_CONTEXT;
+#endif
+ return true;
+}
+
+static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter &iter)
+{
+ const int loop_end = iter.loop_end;
+ Span<WeldLoop> wloop = iter.wloop;
+ Span<int> loop_map = iter.loop_map;
+ int l = iter.l_curr = iter.l_next;
+ if (l == iter.loop_start) {
+ /* `grupo_len` is already calculated in the first loop */
+ }
+ else {
+ iter.group_len = 0;
+ }
+ while (l <= loop_end) {
+ int l_next = l + 1;
+ const int loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag == ELEM_COLLAPSED) {
+ if (iter.group) {
+ iter.group[iter.group_len++] = l;
+ }
+ l = l_next;
+ continue;
+ }
+#ifdef USE_WELD_DEBUG
+ BLI_assert(iter.v != wl->vert);
+#endif
+ iter.v = wl->vert;
+ iter.e = wl->edge;
+ iter.type = 1;
+ }
+ else {
+ const MLoop &ml = iter.mloop[l];
+#ifdef USE_WELD_DEBUG
+ BLI_assert((uint)iter.v != ml.v);
+#endif
+ iter.v = ml.v;
+ iter.e = ml.e;
+ iter.type = 0;
+ }
+ if (iter.group) {
+ iter.group[iter.group_len++] = l;
+ }
+ iter.l_next = l_next;
+ return true;
+ }
+
+ return false;
+}
+
+static void weld_poly_loop_ctx_alloc(Span<MPoly> mpoly,
+ Span<MLoop> mloop,
+ Span<int> vert_dest_map,
+ Span<int> edge_dest_map,
+ WeldMesh *r_weld_mesh)
+{
+ /* Loop/Poly Context. */
+ Array<int> loop_map(mloop.size());
+ Array<int> poly_map(mpoly.size());
+ int wloop_len = 0;
+ int wpoly_len = 0;
+ int max_ctx_poly_len = 4;
+
+ Vector<WeldLoop> wloop;
+ wloop.reserve(mloop.size());
+
+ Vector<WeldPoly> wpoly;
+ wpoly.reserve(mpoly.size());
+
+ int maybe_new_poly = 0;
+
+ for (const int i : mpoly.index_range()) {
+ const MPoly &mp = mpoly[i];
+ const int loopstart = mp.loopstart;
+ const int totloop = mp.totloop;
+
+ int vert_ctx_len = 0;
+
+ int prev_wloop_len = wloop_len;
+ for (const int i_loop : mloop.index_range().slice(loopstart, totloop)) {
+ int v = mloop[i_loop].v;
+ int e = mloop[i_loop].e;
+ int v_dest = vert_dest_map[v];
+ int e_dest = edge_dest_map[e];
+ bool is_vert_ctx = v_dest != OUT_OF_CONTEXT;
+ bool is_edge_ctx = e_dest != OUT_OF_CONTEXT;
+ if (is_vert_ctx) {
+ vert_ctx_len++;
+ }
+ if (is_vert_ctx || is_edge_ctx) {
+ WeldLoop wl{};
+ wl.vert = is_vert_ctx ? v_dest : v;
+ wl.edge = is_edge_ctx ? e_dest : e;
+ wl.loop_orig = i_loop;
+ wl.loop_skip_to = OUT_OF_CONTEXT;
+ wloop.append(wl);
+
+ loop_map[i_loop] = wloop_len++;
+ }
+ else {
+ loop_map[i_loop] = OUT_OF_CONTEXT;
+ }
+ }
+ if (wloop_len != prev_wloop_len) {
+ int loops_len = wloop_len - prev_wloop_len;
+ WeldPoly wp{};
+ wp.poly_dst = OUT_OF_CONTEXT;
+ wp.poly_orig = i;
+ wp.loops.len = loops_len;
+ wp.loops.ofs = prev_wloop_len;
+ wp.loop_start = loopstart;
+ wp.loop_end = loopstart + totloop - 1;
+ wp.len = totloop;
+ wpoly.append(wp);
+
+ poly_map[i] = wpoly_len++;
+ if (totloop > 5 && vert_ctx_len > 1) {
+ int max_new = (totloop / 3) - 1;
+ vert_ctx_len /= 2;
+ maybe_new_poly += MIN2(max_new, vert_ctx_len);
+ CLAMP_MIN(max_ctx_poly_len, totloop);
+ }
+ }
+ else {
+ poly_map[i] = OUT_OF_CONTEXT;
+ }
+ }
+
+ if (mpoly.size() < (wpoly_len + maybe_new_poly)) {
+ wpoly.resize(wpoly_len + maybe_new_poly);
+ }
+
+ WeldPoly *poly_new = wpoly.data() + wpoly_len;
+
+ r_weld_mesh->wloop = std::move(wloop);
+ r_weld_mesh->wpoly = std::move(wpoly);
+ r_weld_mesh->wpoly_new = poly_new;
+ r_weld_mesh->wloop_len = wloop_len;
+ r_weld_mesh->wpoly_len = wpoly_len;
+ r_weld_mesh->wpoly_new_len = 0;
+ r_weld_mesh->loop_map = std::move(loop_map);
+ r_weld_mesh->poly_map = std::move(poly_map);
+ r_weld_mesh->max_poly_len = max_ctx_poly_len;
+}
+
+static void weld_poly_split_recursive(Span<int> vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ const Span<MLoop> mloop,
+#endif
+ int ctx_verts_len,
+ WeldPoly *r_wp,
+ WeldMesh *r_weld_mesh,
+ int *r_poly_kill,
+ int *r_loop_kill)
+{
+ int poly_len = r_wp->len;
+ if (poly_len > 3 && ctx_verts_len > 1) {
+ const int ctx_loops_len = r_wp->loops.len;
+ const int ctx_loops_ofs = r_wp->loops.ofs;
+ MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop;
+ WeldPoly *wpoly_new = r_weld_mesh->wpoly_new;
+
+ int loop_kill = 0;
+
+ WeldLoop *poly_loops = &wloop[ctx_loops_ofs];
+ WeldLoop *wla = &poly_loops[0];
+ WeldLoop *wla_prev = &poly_loops[ctx_loops_len - 1];
+ while (wla_prev->flag == ELEM_COLLAPSED) {
+ wla_prev--;
+ }
+ const int la_len = ctx_loops_len - 1;
+ for (int la = 0; la < la_len; la++, wla++) {
+ wa_continue:
+ if (wla->flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ int vert_a = wla->vert;
+ /* Only test vertices that will be merged. */
+ if (vert_dest_map[vert_a] != OUT_OF_CONTEXT) {
+ int lb = la + 1;
+ WeldLoop *wlb = wla + 1;
+ WeldLoop *wlb_prev = wla;
+ int killed_ab = 0;
+ ctx_verts_len = 1;
+ for (; lb < ctx_loops_len; lb++, wlb++) {
+ BLI_assert(wlb->loop_skip_to == OUT_OF_CONTEXT);
+ if (wlb->flag == ELEM_COLLAPSED) {
+ killed_ab++;
+ continue;
+ }
+ int vert_b = wlb->vert;
+ if (vert_dest_map[vert_b] != OUT_OF_CONTEXT) {
+ ctx_verts_len++;
+ }
+ if (vert_a == vert_b) {
+ const int dist_a = wlb->loop_orig - wla->loop_orig - killed_ab;
+ const int dist_b = poly_len - dist_a;
+
+ BLI_assert(dist_a != 0 && dist_b != 0);
+ if (dist_a == 1 || dist_b == 1) {
+ BLI_assert(dist_a != dist_b);
+ BLI_assert((wla->flag == ELEM_COLLAPSED) || (wlb->flag == ELEM_COLLAPSED));
+ }
+ else {
+ WeldLoop *wl_tmp = nullptr;
+ if (dist_a == 2) {
+ wl_tmp = wlb_prev;
+ BLI_assert(wla->flag != ELEM_COLLAPSED);
+ BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
+ wla->flag = ELEM_COLLAPSED;
+ wl_tmp->flag = ELEM_COLLAPSED;
+ loop_kill += 2;
+ poly_len -= 2;
+ }
+ if (dist_b == 2) {
+ if (wl_tmp != nullptr) {
+ r_wp->flag = ELEM_COLLAPSED;
+ *r_poly_kill += 1;
+ }
+ else {
+ wl_tmp = wla_prev;
+ BLI_assert(wlb->flag != ELEM_COLLAPSED);
+ BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
+ wlb->flag = ELEM_COLLAPSED;
+ wl_tmp->flag = ELEM_COLLAPSED;
+ }
+ loop_kill += 2;
+ poly_len -= 2;
+ }
+ if (wl_tmp == nullptr) {
+ const int new_loops_len = lb - la;
+ const int new_loops_ofs = ctx_loops_ofs + la;
+
+ WeldPoly *new_wp = &wpoly_new[r_weld_mesh->wpoly_new_len++];
+ new_wp->poly_dst = OUT_OF_CONTEXT;
+ new_wp->poly_orig = r_wp->poly_orig;
+ new_wp->loops.len = new_loops_len;
+ new_wp->loops.ofs = new_loops_ofs;
+ new_wp->loop_start = wla->loop_orig;
+ new_wp->loop_end = wlb_prev->loop_orig;
+ new_wp->len = dist_a;
+ weld_poly_split_recursive(vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ mloop,
+#endif
+ ctx_verts_len,
+ new_wp,
+ r_weld_mesh,
+ r_poly_kill,
+ r_loop_kill);
+ BLI_assert(dist_b == poly_len - dist_a);
+ poly_len = dist_b;
+ if (wla_prev->loop_orig > wla->loop_orig) {
+ /* New start. */
+ r_wp->loop_start = wlb->loop_orig;
+ }
+ else {
+ /* The `loop_start` doesn't change but some loops must be skipped. */
+ wla_prev->loop_skip_to = wlb->loop_orig;
+ }
+ wla = wlb;
+ la = lb;
+ goto wa_continue;
+ }
+ break;
+ }
+ }
+ if (wlb->flag != ELEM_COLLAPSED) {
+ wlb_prev = wlb;
+ }
+ }
+ }
+ if (wla->flag != ELEM_COLLAPSED) {
+ wla_prev = wla;
+ }
+ }
+ r_wp->len = poly_len;
+ *r_loop_kill += loop_kill;
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_no_vert_repetition(*r_wp, wloop, mloop, r_weld_mesh->loop_map);
+#endif
+ }
+}
+
+static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
+#ifdef USE_WELD_DEBUG
+ Span<MPoly> mpoly,
+#endif
+ const int mvert_len,
+ Span<int> vert_dest_map,
+ const int remain_edge_ctx_len,
+ MutableSpan<WeldGroup> r_vlinks,
+ WeldMesh *r_weld_mesh)
+{
+ MutableSpan<WeldPoly> wpoly = r_weld_mesh->wpoly;
+ MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop;
+ WeldPoly *wpoly_new = r_weld_mesh->wpoly_new;
+ int wpoly_len = r_weld_mesh->wpoly_len;
+ int wpoly_new_len = 0;
+ int poly_kill_len = 0;
+ int loop_kill_len = 0;
+
+ Span<int> loop_map = r_weld_mesh->loop_map;
+
+ if (remain_edge_ctx_len) {
+
+ /* Setup Poly/Loop. Note that `wpoly_len` may be different than `wpoly.size()` here. */
+ for (const int i : IndexRange(wpoly_len)) {
+ WeldPoly &wp = wpoly[i];
+ const int ctx_loops_len = wp.loops.len;
+ const int ctx_loops_ofs = wp.loops.ofs;
+
+ int poly_len = wp.len;
+ int ctx_verts_len = 0;
+ WeldLoop *wl = &wloop[ctx_loops_ofs];
+ for (int l = ctx_loops_len; l--; wl++) {
+ const int edge_dest = wl->edge;
+ if (edge_dest == ELEM_COLLAPSED) {
+ wl->flag = ELEM_COLLAPSED;
+ if (poly_len == 3) {
+ wp.flag = ELEM_COLLAPSED;
+ poly_kill_len++;
+ loop_kill_len += 3;
+ poly_len = 0;
+ break;
+ }
+ loop_kill_len++;
+ poly_len--;
+ }
+ else {
+ const int vert_dst = wl->vert;
+ if (vert_dest_map[vert_dst] != OUT_OF_CONTEXT) {
+ ctx_verts_len++;
+ }
+ }
+ }
+
+ if (poly_len) {
+ wp.len = poly_len;
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_len(wp, wloop);
+#endif
+
+ weld_poly_split_recursive(vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ mloop,
+#endif
+ ctx_verts_len,
+ &wp,
+ r_weld_mesh,
+ &poly_kill_len,
+ &loop_kill_len);
+
+ wpoly_new_len = r_weld_mesh->wpoly_new_len;
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_and_loop_kill_len(wpoly,
+ {wpoly_new, wpoly_new_len},
+ wloop,
+ mloop,
+ loop_map,
+ r_weld_mesh->poly_map,
+ mpoly,
+ poly_kill_len,
+ loop_kill_len);
+#endif
+
+ /* Setup Polygon Overlap. */
+
+ const int wpoly_and_new_len = wpoly_len + wpoly_new_len;
+
+ r_vlinks.fill({0, 0});
+ MutableSpan<WeldGroup> v_links = r_vlinks;
+
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
+ WeldLoopOfPolyIter iter;
+ if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) {
+ while (weld_iter_loop_of_poly_next(iter)) {
+ v_links[iter.v].len++;
+ }
+ }
+ }
+
+ int link_len = 0;
+ for (const int i : IndexRange(mvert_len)) {
+ v_links[i].ofs = link_len;
+ link_len += v_links[i].len;
+ }
+
+ if (link_len) {
+ Array<int> link_poly_buffer(link_len);
+
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
+ WeldLoopOfPolyIter iter;
+ if (weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr)) {
+ while (weld_iter_loop_of_poly_next(iter)) {
+ link_poly_buffer[v_links[iter.v].ofs++] = i;
+ }
+ }
+ }
+
+ for (WeldGroup &vl : r_vlinks) {
+ /* Fix offset */
+ vl.ofs -= vl.len;
+ }
+
+ int polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b;
+ polys_len_b = p_ctx_b = 0; /* silence warnings */
+
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
+ /* No need to retest poly.
+ * (Already includes collapsed polygons). */
+ continue;
+ }
+
+ WeldLoopOfPolyIter iter;
+ weld_iter_loop_of_poly_begin(iter, wp, wloop, mloop, loop_map, nullptr);
+ weld_iter_loop_of_poly_next(iter);
+ struct WeldGroup *link_a = &v_links[iter.v];
+ polys_len_a = link_a->len;
+ if (polys_len_a == 1) {
+ BLI_assert(link_poly_buffer[link_a->ofs] == i);
+ continue;
+ }
+ int wp_len = wp.len;
+ polys_ctx_a = &link_poly_buffer[link_a->ofs];
+ for (; polys_len_a--; polys_ctx_a++) {
+ p_ctx_a = *polys_ctx_a;
+ if (p_ctx_a == i) {
+ continue;
+ }
+
+ WeldPoly *wp_tmp = &wpoly[p_ctx_a];
+ if (wp_tmp->len != wp_len) {
+ continue;
+ }
+
+ WeldLoopOfPolyIter iter_b = iter;
+ while (weld_iter_loop_of_poly_next(iter_b)) {
+ struct WeldGroup *link_b = &v_links[iter_b.v];
+ polys_len_b = link_b->len;
+ if (polys_len_b == 1) {
+ BLI_assert(link_poly_buffer[link_b->ofs] == i);
+ polys_len_b = 0;
+ break;
+ }
+
+ polys_ctx_b = &link_poly_buffer[link_b->ofs];
+ for (; polys_len_b; polys_len_b--, polys_ctx_b++) {
+ p_ctx_b = *polys_ctx_b;
+ if (p_ctx_b < p_ctx_a) {
+ continue;
+ }
+ if (p_ctx_b >= p_ctx_a) {
+ if (p_ctx_b > p_ctx_a) {
+ polys_len_b = 0;
+ }
+ break;
+ }
+ }
+ if (polys_len_b == 0) {
+ break;
+ }
+ }
+ if (polys_len_b == 0) {
+ continue;
+ }
+ BLI_assert(p_ctx_a > i);
+ BLI_assert(p_ctx_a == p_ctx_b);
+ BLI_assert(wp_tmp->poly_dst == OUT_OF_CONTEXT);
+ BLI_assert(wp_tmp != &wp);
+ wp_tmp->poly_dst = wp.poly_orig;
+ loop_kill_len += wp_tmp->len;
+ poly_kill_len++;
+ }
+ }
+ }
+ }
+ else {
+ poly_kill_len = r_weld_mesh->wpoly_len;
+ loop_kill_len = r_weld_mesh->wloop_len;
+
+ for (WeldPoly &wp : wpoly) {
+ wp.flag = ELEM_COLLAPSED;
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_and_loop_kill_len(wpoly,
+ {wpoly_new, wpoly_new_len},
+ wloop,
+ mloop,
+ loop_map,
+ r_weld_mesh->poly_map,
+ mpoly,
+ poly_kill_len,
+ loop_kill_len);
+#endif
+
+ r_weld_mesh->wpoly_new = wpoly_new;
+ r_weld_mesh->poly_kill_len = poly_kill_len;
+ r_weld_mesh->loop_kill_len = loop_kill_len;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh API
+ * \{ */
+
+static void weld_mesh_context_create(const Mesh &mesh,
+ MutableSpan<int> vert_dest_map,
+ const int vert_kill_len,
+ WeldMesh *r_weld_mesh)
+{
+ Span<MEdge> medge{mesh.medge, mesh.totedge};
+ Span<MPoly> mpoly{mesh.mpoly, mesh.totpoly};
+ Span<MLoop> mloop{mesh.mloop, mesh.totloop};
+ const int mvert_len = mesh.totvert;
+
+ Vector<WeldVert> wvert = weld_vert_ctx_alloc_and_setup(vert_dest_map, vert_kill_len);
+ r_weld_mesh->vert_kill_len = vert_kill_len;
+
+ Array<int> edge_dest_map(medge.size());
+ Array<int> edge_ctx_map(medge.size());
+ Vector<WeldEdge> wedge = weld_edge_ctx_alloc(medge, vert_dest_map, edge_dest_map, edge_ctx_map);
+
+ Array<WeldGroup> v_links(mvert_len, {0, 0});
+ weld_edge_ctx_setup(v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_len);
+
+ weld_poly_loop_ctx_alloc(mpoly, mloop, vert_dest_map, edge_dest_map, r_weld_mesh);
+
+ weld_poly_loop_ctx_setup(mloop,
+#ifdef USE_WELD_DEBUG
+ mpoly,
+
+#endif
+ mvert_len,
+ vert_dest_map,
+ wedge.size() - r_weld_mesh->edge_kill_len,
+ v_links,
+ r_weld_mesh);
+
+ weld_vert_groups_setup(wvert,
+ vert_dest_map,
+ vert_dest_map,
+ r_weld_mesh->vert_groups_buffer,
+ r_weld_mesh->vert_groups);
+
+ weld_edge_groups_setup(medge.size(),
+ r_weld_mesh->edge_kill_len,
+ wedge,
+ edge_ctx_map,
+ edge_dest_map,
+ r_weld_mesh->edge_groups_buffer,
+ r_weld_mesh->edge_groups);
+
+ r_weld_mesh->edge_groups_map = std::move(edge_dest_map);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name CustomData
+ * \{ */
+
+static void customdata_weld(
+ const CustomData *source, CustomData *dest, const int *src_indices, int count, int dest_index)
+{
+ if (count == 1) {
+ CustomData_copy_data(source, dest, src_indices[0], dest_index, 1);
+ return;
+ }
+
+ CustomData_interp(source, dest, (const int *)src_indices, nullptr, nullptr, count, dest_index);
+
+ int src_i, dest_i;
+ int j;
+
+ float co[3] = {0.0f, 0.0f, 0.0f};
+#ifdef USE_WELD_NORMALS
+ float no[3] = {0.0f, 0.0f, 0.0f};
+#endif
+ int crease = 0;
+ int bweight = 0;
+ short flag = 0;
+
+ /* interpolates a layer at a time */
+ dest_i = 0;
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
+ const int type = source->layers[src_i].type;
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while (dest_i < dest->totlayer && dest->layers[dest_i].type < type) {
+ dest_i++;
+ }
+
+ /* if there are no more dest layers, we're done */
+ if (dest_i == dest->totlayer) {
+ break;
+ }
+
+ /* if we found a matching layer, add the data */
+ if (dest->layers[dest_i].type == type) {
+ void *src_data = source->layers[src_i].data;
+
+ if (type == CD_MVERT) {
+ for (j = 0; j < count; j++) {
+ MVert *mv_src = &((MVert *)src_data)[src_indices[j]];
+ add_v3_v3(co, mv_src->co);
+#ifdef USE_WELD_NORMALS
+ short *mv_src_no = mv_src->no;
+ no[0] += mv_src_no[0];
+ no[1] += mv_src_no[1];
+ no[2] += mv_src_no[2];
+#endif
+ bweight += mv_src->bweight;
+ flag |= mv_src->flag;
+ }
+ }
+ else if (type == CD_MEDGE) {
+ for (j = 0; j < count; j++) {
+ MEdge *me_src = &((MEdge *)src_data)[src_indices[j]];
+ crease += me_src->crease;
+ bweight += me_src->bweight;
+ flag |= me_src->flag;
+ }
+ }
+ else if (CustomData_layer_has_interp(dest, dest_i)) {
+ /* Already calculated.
+ * TODO: Optimize by exposing `typeInfo->interp`. */
+ }
+ else if (CustomData_layer_has_math(dest, dest_i)) {
+ const int size = CustomData_sizeof(type);
+ void *dst_data = dest->layers[dest_i].data;
+ void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ for (j = 0; j < count; j++) {
+ CustomData_data_add(
+ type, v_dst, POINTER_OFFSET(src_data, (size_t)src_indices[j] * size));
+ }
+ }
+ else {
+ CustomData_copy_layer_type_data(source, dest, type, src_indices[0], dest_index, 1);
+ }
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ dest_i++;
+ }
+ }
+
+ float fac = 1.0f / count;
+
+ for (dest_i = 0; dest_i < dest->totlayer; dest_i++) {
+ CustomDataLayer *layer_dst = &dest->layers[dest_i];
+ const int type = layer_dst->type;
+ if (type == CD_MVERT) {
+ MVert *mv = &((MVert *)layer_dst->data)[dest_index];
+ mul_v3_fl(co, fac);
+ bweight *= fac;
+ CLAMP_MAX(bweight, 255);
+
+ copy_v3_v3(mv->co, co);
+#ifdef USE_WELD_NORMALS
+ mul_v3_fl(no, fac);
+ short *mv_no = mv->no;
+ mv_no[0] = (short)no[0];
+ mv_no[1] = (short)no[1];
+ mv_no[2] = (short)no[2];
+#endif
+
+ mv->flag = (char)flag;
+ mv->bweight = (char)bweight;
+ }
+ else if (type == CD_MEDGE) {
+ MEdge *me = &((MEdge *)layer_dst->data)[dest_index];
+ crease *= fac;
+ bweight *= fac;
+ CLAMP_MAX(crease, 255);
+ CLAMP_MAX(bweight, 255);
+
+ me->crease = (char)crease;
+ me->bweight = (char)bweight;
+ me->flag = flag;
+ }
+ else if (CustomData_layer_has_interp(dest, dest_i)) {
+ /* Already calculated. */
+ }
+ else if (CustomData_layer_has_math(dest, dest_i)) {
+ const int size = CustomData_sizeof(type);
+ void *dst_data = layer_dst->data;
+ void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ CustomData_data_multiply(type, v_dst, fac);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Vertex Merging
+ * \{ */
+
+static Mesh *create_merged_mesh(const Mesh &mesh,
+ MutableSpan<int> vert_dest_map,
+ const int removed_vertex_count)
+{
+ Span<MPoly> mpoly{mesh.mpoly, mesh.totpoly};
+ Span<MLoop> mloop{mesh.mloop, mesh.totloop};
+ const int totvert = mesh.totvert;
+ const int totedge = mesh.totedge;
+ const int totloop = mesh.totloop;
+ const int totpoly = mesh.totpoly;
+
+ WeldMesh weld_mesh;
+ weld_mesh_context_create(mesh, vert_dest_map, removed_vertex_count, &weld_mesh);
+
+ const int result_nverts = totvert - weld_mesh.vert_kill_len;
+ const int result_nedges = totedge - weld_mesh.edge_kill_len;
+ const int result_nloops = totloop - weld_mesh.loop_kill_len;
+ const int result_npolys = totpoly - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len;
+
+ Mesh *result = BKE_mesh_new_nomain_from_template(
+ &mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
+
+ /* Vertices. */
+
+ /* Be careful when editing this array, to avoid new allocations it uses the same buffer as
+ * #vert_dest_map. This map will be used to adjust the edges, polys and loops. */
+ MutableSpan<int> vert_final = vert_dest_map;
+
+ int dest_index = 0;
+ for (int i = 0; i < totvert; i++) {
+ int source_index = i;
+ int count = 0;
+ while (i < totvert && vert_dest_map[i] == OUT_OF_CONTEXT) {
+ vert_final[i] = dest_index + count;
+ count++;
+ i++;
+ }
+ if (count) {
+ CustomData_copy_data(&mesh.vdata, &result->vdata, source_index, dest_index, count);
+ dest_index += count;
+ }
+ if (i == totvert) {
+ break;
+ }
+ if (vert_dest_map[i] != ELEM_MERGED) {
+ struct WeldGroup *wgroup = &weld_mesh.vert_groups[vert_dest_map[i]];
+ customdata_weld(&mesh.vdata,
+ &result->vdata,
+ &weld_mesh.vert_groups_buffer[wgroup->ofs],
+ wgroup->len,
+ dest_index);
+ vert_final[i] = dest_index;
+ dest_index++;
+ }
+ }
+
+ BLI_assert(dest_index == result_nverts);
+
+ /* Edges. */
+
+ /* Be careful when editing this array, to avoid new allocations it uses the same buffer as
+ * #edge_groups_map. This map will be used to adjust the polys and loops. */
+ MutableSpan<int> edge_final = weld_mesh.edge_groups_map;
+
+ dest_index = 0;
+ for (int i = 0; i < totedge; i++) {
+ const int source_index = i;
+ int count = 0;
+ while (i < totedge && weld_mesh.edge_groups_map[i] == OUT_OF_CONTEXT) {
+ edge_final[i] = dest_index + count;
+ count++;
+ i++;
+ }
+ if (count) {
+ CustomData_copy_data(&mesh.edata, &result->edata, source_index, dest_index, count);
+ MEdge *me = &result->medge[dest_index];
+ dest_index += count;
+ for (; count--; me++) {
+ me->v1 = vert_final[me->v1];
+ me->v2 = vert_final[me->v2];
+ }
+ }
+ if (i == totedge) {
+ break;
+ }
+ if (weld_mesh.edge_groups_map[i] != ELEM_MERGED) {
+ struct WeldGroupEdge *wegrp = &weld_mesh.edge_groups[weld_mesh.edge_groups_map[i]];
+ customdata_weld(&mesh.edata,
+ &result->edata,
+ &weld_mesh.edge_groups_buffer[wegrp->group.ofs],
+ wegrp->group.len,
+ dest_index);
+ MEdge *me = &result->medge[dest_index];
+ me->v1 = vert_final[wegrp->v1];
+ me->v2 = vert_final[wegrp->v2];
+ /* "For now, assume that all merged edges are loose. This flag will be cleared in the
+ * Polys/Loops step". */
+ me->flag |= ME_LOOSEEDGE;
+
+ edge_final[i] = dest_index;
+ dest_index++;
+ }
+ }
+
+ BLI_assert(dest_index == result_nedges);
+
+ /* Polys/Loops. */
+
+ MPoly *r_mp = &result->mpoly[0];
+ MLoop *r_ml = &result->mloop[0];
+ int r_i = 0;
+ int loop_cur = 0;
+ Array<int, 64> group_buffer(weld_mesh.max_poly_len);
+ for (const int i : mpoly.index_range()) {
+ const MPoly &mp = mpoly[i];
+ const int loop_start = loop_cur;
+ const int poly_ctx = weld_mesh.poly_map[i];
+ if (poly_ctx == OUT_OF_CONTEXT) {
+ int mp_loop_len = mp.totloop;
+ CustomData_copy_data(&mesh.ldata, &result->ldata, mp.loopstart, loop_cur, mp_loop_len);
+ loop_cur += mp_loop_len;
+ for (; mp_loop_len--; r_ml++) {
+ r_ml->v = vert_final[r_ml->v];
+ r_ml->e = edge_final[r_ml->e];
+ }
+ }
+ else {
+ const WeldPoly &wp = weld_mesh.wpoly[poly_ctx];
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(
+ iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
+ continue;
+ }
+
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
+ continue;
+ }
+ while (weld_iter_loop_of_poly_next(iter)) {
+ customdata_weld(
+ &mesh.ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur);
+ int v = vert_final[iter.v];
+ int e = edge_final[iter.e];
+ r_ml->v = v;
+ r_ml->e = e;
+ r_ml++;
+ loop_cur++;
+ if (iter.type) {
+ result->medge[e].flag &= ~ME_LOOSEEDGE;
+ }
+ BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
+ }
+ }
+
+ CustomData_copy_data(&mesh.pdata, &result->pdata, i, r_i, 1);
+ r_mp->loopstart = loop_start;
+ r_mp->totloop = loop_cur - loop_start;
+ r_mp++;
+ r_i++;
+ }
+
+ for (const int i : IndexRange(weld_mesh.wpoly_new_len)) {
+ const WeldPoly &wp = weld_mesh.wpoly_new[i];
+ const int loop_start = loop_cur;
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(
+ iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
+ continue;
+ }
+
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
+ continue;
+ }
+ while (weld_iter_loop_of_poly_next(iter)) {
+ customdata_weld(&mesh.ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur);
+ int v = vert_final[iter.v];
+ int e = edge_final[iter.e];
+ r_ml->v = v;
+ r_ml->e = e;
+ r_ml++;
+ loop_cur++;
+ if (iter.type) {
+ result->medge[e].flag &= ~ME_LOOSEEDGE;
+ }
+ BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
+ }
+
+ r_mp->loopstart = loop_start;
+ r_mp->totloop = loop_cur - loop_start;
+ r_mp++;
+ r_i++;
+ }
+
+ BLI_assert((int)r_i == result_npolys);
+ BLI_assert(loop_cur == result_nloops);
+
+ /* We could only update the normals of the elements in context, but the next modifier can make it
+ * dirty anyway which would make the work useless. */
+ BKE_mesh_normals_tag_dirty(result);
+
+ return result;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Merge Map Creation
+ * \{ */
+
+std::optional<Mesh *> mesh_merge_by_distance_all(const Mesh &mesh,
+ const IndexMask selection,
+ const float merge_distance)
+{
+ Array<int> vert_dest_map(mesh.totvert, OUT_OF_CONTEXT);
+
+ KDTree_3d *tree = BLI_kdtree_3d_new(selection.size());
+
+ for (const int i : selection) {
+ BLI_kdtree_3d_insert(tree, i, mesh.mvert[i].co);
+ }
+
+ BLI_kdtree_3d_balance(tree);
+ const int vert_kill_len = BLI_kdtree_3d_calc_duplicates_fast(
+ tree, merge_distance, false, vert_dest_map.data());
+ BLI_kdtree_3d_free(tree);
+
+ if (vert_kill_len == 0) {
+ return std::nullopt;
+ }
+
+ return create_merged_mesh(mesh, vert_dest_map, vert_kill_len);
+}
+
+struct WeldVertexCluster {
+ float co[3];
+ int merged_verts;
+};
+
+std::optional<Mesh *> mesh_merge_by_distance_connected(const Mesh &mesh,
+ Span<bool> selection,
+ const float merge_distance,
+ const bool only_loose_edges)
+{
+ Span<MVert> verts{mesh.mvert, mesh.totvert};
+ Span<MEdge> edges{mesh.medge, mesh.totedge};
+
+ int vert_kill_len = 0;
+
+ /* From the original index of the vertex.
+ * This indicates which vert it is or is going to be merged. */
+ Array<int> vert_dest_map(mesh.totvert, OUT_OF_CONTEXT);
+
+ Array<WeldVertexCluster> vert_clusters(mesh.totvert);
+
+ for (const int i : verts.index_range()) {
+ WeldVertexCluster &vc = vert_clusters[i];
+ copy_v3_v3(vc.co, verts[i].co);
+ vc.merged_verts = 0;
+ }
+ const float merge_dist_sq = square_f(merge_distance);
+
+ range_vn_i(vert_dest_map.data(), mesh.totvert, 0);
+
+ /* Collapse Edges that are shorter than the threshold. */
+ for (const int i : edges.index_range()) {
+ int v1 = edges[i].v1;
+ int v2 = edges[i].v2;
+
+ if (only_loose_edges && (edges[i].flag & ME_LOOSEEDGE) == 0) {
+ continue;
+ }
+ while (v1 != vert_dest_map[v1]) {
+ v1 = vert_dest_map[v1];
+ }
+ while (v2 != vert_dest_map[v2]) {
+ v2 = vert_dest_map[v2];
+ }
+ if (v1 == v2) {
+ continue;
+ }
+ if (!selection.is_empty() && (!selection[v1] || !selection[v2])) {
+ continue;
+ }
+ if (v1 > v2) {
+ SWAP(int, v1, v2);
+ }
+ WeldVertexCluster *v1_cluster = &vert_clusters[v1];
+ WeldVertexCluster *v2_cluster = &vert_clusters[v2];
+
+ float edgedir[3];
+ sub_v3_v3v3(edgedir, v2_cluster->co, v1_cluster->co);
+ const float dist_sq = len_squared_v3(edgedir);
+ if (dist_sq <= merge_dist_sq) {
+ float influence = (v2_cluster->merged_verts + 1) /
+ (float)(v1_cluster->merged_verts + v2_cluster->merged_verts + 2);
+ madd_v3_v3fl(v1_cluster->co, edgedir, influence);
+
+ v1_cluster->merged_verts += v2_cluster->merged_verts + 1;
+ vert_dest_map[v2] = v1;
+ vert_kill_len++;
+ }
+ }
+
+ if (vert_kill_len == 0) {
+ return std::nullopt;
+ }
+
+ for (const int i : IndexRange(mesh.totvert)) {
+ if (i == vert_dest_map[i]) {
+ vert_dest_map[i] = OUT_OF_CONTEXT;
+ }
+ else {
+ int v = i;
+ while ((v != vert_dest_map[v]) && (vert_dest_map[v] != OUT_OF_CONTEXT)) {
+ v = vert_dest_map[v];
+ }
+ vert_dest_map[v] = v;
+ vert_dest_map[i] = v;
+ }
+ }
+
+ return create_merged_mesh(mesh, vert_dest_map, vert_kill_len);
+}
+
+/** \} */
+
+} // 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 0cbec35ec7a..965c09984fa 100644
--- a/source/blender/geometry/intern/mesh_to_curve_convert.cc
+++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc
@@ -16,6 +16,7 @@
#include "BLI_array.hh"
#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
#include "BLI_task.hh"
#include "DNA_mesh_types.h"
@@ -41,11 +42,22 @@ static void copy_attribute_to_points(const VArray<T> &source_data,
}
}
-static void copy_attributes_to_points(CurveEval &curve,
- const MeshComponent &mesh_component,
- Span<Vector<int>> point_to_vert_maps)
+static std::unique_ptr<CurveEval> create_curve_from_vert_indices(
+ const MeshComponent &mesh_component, Span<Vector<int>> vert_indices, IndexRange cyclic_splines)
{
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ curve->resize(vert_indices.size());
+
+ MutableSpan<SplinePtr> splines = curve->splines();
+
+ for (const int i : vert_indices.index_range()) {
+ splines[i] = std::make_unique<PolySpline>();
+ splines[i]->resize(vert_indices[i].size());
+ }
+ for (const int i : cyclic_splines) {
+ splines[i]->set_cyclic(true);
+ }
+
Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
/* Copy builtin control point attributes. */
@@ -54,27 +66,44 @@ static void copy_attributes_to_points(CurveEval &curve,
"tilt", ATTR_DOMAIN_POINT, 0.0f);
threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
for (const int i : range) {
- copy_attribute_to_points<float>(
- tilt_attribute, point_to_vert_maps[i], splines[i]->tilts());
+ copy_attribute_to_points<float>(tilt_attribute, vert_indices[i], splines[i]->tilts());
}
});
source_attribute_ids.remove_contained("tilt");
}
+ else {
+ for (SplinePtr &spline : splines) {
+ spline->tilts().fill(0.0f);
+ }
+ }
+
if (source_attribute_ids.contains("radius")) {
const VArray<float> radius_attribute = mesh_component.attribute_get_for_read<float>(
"radius", ATTR_DOMAIN_POINT, 1.0f);
threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
for (const int i : range) {
- copy_attribute_to_points<float>(
- radius_attribute, point_to_vert_maps[i], splines[i]->radii());
+ copy_attribute_to_points<float>(radius_attribute, vert_indices[i], splines[i]->radii());
}
});
source_attribute_ids.remove_contained("radius");
}
+ else {
+ for (SplinePtr &spline : splines) {
+ spline->radii().fill(1.0f);
+ }
+ }
+
+ VArray<float3> mesh_positions = mesh_component.attribute_get_for_read(
+ "position", ATTR_DOMAIN_POINT, float3(0));
+ threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ copy_attribute_to_points(mesh_positions, vert_indices[i], splines[i]->positions());
+ }
+ });
for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) {
- /* Don't copy attributes that are built-in on meshes but not on curves. */
if (mesh_component.attribute_is_builtin(attribute_id)) {
+ /* Don't copy attributes that are built-in on meshes but not on curves. */
continue;
}
@@ -104,24 +133,27 @@ static void copy_attributes_to_points(CurveEval &curve,
attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
using T = decltype(dummy);
copy_attribute_to_points<T>(
- mesh_attribute.typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>());
+ mesh_attribute.typed<T>(), vert_indices[i], spline_attribute->typed<T>());
});
}
});
}
- curve.assert_valid_point_attributes();
+ curve->assert_valid_point_attributes();
+ return curve;
}
struct CurveFromEdgesOutput {
- std::unique_ptr<CurveEval> curve;
- Vector<Vector<int>> point_to_vert_maps;
+ /** The indices in the mesh for each control point of each result splines. */
+ Vector<Vector<int>> vert_indices;
+ /** A subset of splines that should be set cyclic. */
+ IndexRange cyclic_splines;
};
-static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int, int>> edges)
+static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
+ Span<std::pair<int, int>> edges)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- Vector<Vector<int>> point_to_vert_maps;
+ Vector<Vector<int>> vert_indices;
/* Compute the number of edges connecting to each vertex. */
Array<int> neighbor_count(verts.size(), 0);
@@ -173,19 +205,15 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
continue;
}
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- Vector<int> point_to_vert_map;
-
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ Vector<int> spline_indices;
+ spline_indices.append(current_vert);
/* Follow connected edges until we read a vertex with more than two connected edges. */
while (true) {
int last_vert = current_vert;
current_vert = next_vert;
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ spline_indices.append(current_vert);
unused_edges[current_vert]--;
unused_edges[last_vert]--;
@@ -199,12 +227,13 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
next_vert = (last_vert == next_a) ? next_b : next_a;
}
- spline->attributes.reallocate(spline->size());
- curve->add_spline(std::move(spline));
- point_to_vert_maps.append(std::move(point_to_vert_map));
+ vert_indices.append(std::move(spline_indices));
}
}
+ /* All splines added after this are cyclic. */
+ const int cyclic_start = vert_indices.size();
+
/* All remaining edges are part of cyclic splines (we skipped vertices with two edges before). */
for (const int start_vert : verts.index_range()) {
if (unused_edges[start_vert] != 2) {
@@ -214,20 +243,16 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
int current_vert = start_vert;
int next_vert = neighbors[neighbor_offsets[current_vert]];
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- Vector<int> point_to_vert_map;
- spline->set_cyclic(true);
+ Vector<int> spline_indices;
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ spline_indices.append(current_vert);
/* Follow connected edges until we loop back to the start vertex. */
while (next_vert != start_vert) {
const int last_vert = current_vert;
current_vert = next_vert;
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ spline_indices.append(current_vert);
unused_edges[current_vert]--;
unused_edges[last_vert]--;
@@ -237,13 +262,12 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
next_vert = (last_vert == next_a) ? next_b : next_a;
}
- spline->attributes.reallocate(spline->size());
- curve->add_spline(std::move(spline));
- point_to_vert_maps.append(std::move(point_to_vert_map));
+ vert_indices.append(std::move(spline_indices));
}
- curve->attributes.reallocate(curve->splines().size());
- return {std::move(curve), std::move(point_to_vert_maps)};
+ const int final_size = vert_indices.size();
+
+ return {std::move(vert_indices), IndexRange(cyclic_start, final_size - cyclic_start)};
}
/**
@@ -266,9 +290,11 @@ std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_compo
const Mesh &mesh = *mesh_component.get_for_read();
Vector<std::pair<int, int>> selected_edges = get_selected_edges(*mesh_component.get_for_read(),
selection);
- CurveFromEdgesOutput output = edges_to_curve({mesh.mvert, mesh.totvert}, selected_edges);
- copy_attributes_to_points(*output.curve, mesh_component, output.point_to_vert_maps);
- return std::move(output.curve);
+ CurveFromEdgesOutput output = edges_to_curve_point_indices({mesh.mvert, mesh.totvert},
+ selected_edges);
+
+ return create_curve_from_vert_indices(
+ mesh_component, output.vert_indices, output.cyclic_splines);
}
} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/point_merge_by_distance.cc b/source/blender/geometry/intern/point_merge_by_distance.cc
new file mode 100644
index 00000000000..daa08a3bce6
--- /dev/null
+++ b/source/blender/geometry/intern/point_merge_by_distance.cc
@@ -0,0 +1,183 @@
+/*
+ * 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_kdtree.h"
+#include "BLI_task.hh"
+
+#include "DNA_pointcloud_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_pointcloud.h"
+
+#include "GEO_point_merge_by_distance.hh"
+
+namespace blender::geometry {
+
+PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
+ const float merge_distance,
+ const IndexMask selection)
+{
+ const PointCloud &src_pointcloud = *src_points.get_for_read();
+ const int src_size = src_pointcloud.totpoint;
+ Span<float3> positions{reinterpret_cast<float3 *>(src_pointcloud.co), src_size};
+
+ /* Create the KD tree based on only the selected points, to speed up merge detection and
+ * balancing. */
+ KDTree_3d *tree = BLI_kdtree_3d_new(selection.size());
+ for (const int i : selection.index_range()) {
+ BLI_kdtree_3d_insert(tree, i, positions[selection[i]]);
+ }
+ BLI_kdtree_3d_balance(tree);
+
+ /* Find the duplicates in the KD tree. Because the tree only contains the selected points, the
+ * resulting indices are indices into the selection, rather than indices of the source point
+ * cloud. */
+ Array<int> selection_merge_indices(selection.size(), -1);
+ const int duplicate_count = BLI_kdtree_3d_calc_duplicates_fast(
+ tree, merge_distance, false, selection_merge_indices.data());
+ BLI_kdtree_3d_free(tree);
+
+ /* Create the new point cloud and add it to a temporary component for the attribute API. */
+ const int dst_size = src_size - duplicate_count;
+ PointCloud *dst_pointcloud = BKE_pointcloud_new_nomain(dst_size);
+ PointCloudComponent dst_points;
+ dst_points.replace(dst_pointcloud, GeometryOwnershipType::Editable);
+
+ /* By default, every point is just "merged" with itself. Then fill in the results of the merge
+ * finding, converting from indices into the selection to indices into the full input point
+ * cloud. */
+ Array<int> merge_indices(src_size);
+ for (const int i : merge_indices.index_range()) {
+ merge_indices[i] = i;
+ }
+ for (const int i : selection_merge_indices.index_range()) {
+ const int merge_index = selection_merge_indices[i];
+ if (merge_index != -1) {
+ const int src_merge_index = selection[merge_index];
+ const int src_index = selection[i];
+ merge_indices[src_index] = src_merge_index;
+ }
+ }
+
+ /* For every source index, find the corresponding index in the result by iterating through the
+ * source indices and counting how many merges happened before that point. */
+ int merged_points = 0;
+ Array<int> src_to_dst_indices(src_size);
+ for (const int i : IndexRange(src_size)) {
+ src_to_dst_indices[i] = i - merged_points;
+ if (merge_indices[i] != i) {
+ merged_points++;
+ }
+ }
+
+ /* In order to use a contiguous array as the storage for every destination point's source
+ * indices, first the number of source points must be counted for every result point. */
+ Array<int> point_merge_counts(dst_size, 0);
+ for (const int i : IndexRange(src_size)) {
+ const int merge_index = merge_indices[i];
+ const int dst_index = src_to_dst_indices[merge_index];
+ point_merge_counts[dst_index]++;
+ }
+
+ /* This array stores an offset into `merge_map` for every result point. */
+ Array<int> map_offsets(dst_size + 1);
+ int offset = 0;
+ for (const int i : IndexRange(dst_size)) {
+ map_offsets[i] = offset;
+ offset += point_merge_counts[i];
+ }
+ map_offsets.last() = offset;
+
+ point_merge_counts.fill(0);
+
+ /* This array stores all of the source indices for every result point. The size is the source
+ * size because every input point is either merged with another or copied directly. */
+ Array<int> merge_map(src_size);
+ for (const int i : IndexRange(src_size)) {
+ const int merge_index = merge_indices[i];
+ const int dst_index = src_to_dst_indices[merge_index];
+
+ const IndexRange point_range(map_offsets[dst_index],
+ map_offsets[dst_index + 1] - map_offsets[dst_index]);
+ MutableSpan<int> point_merge_indices = merge_map.as_mutable_span().slice(point_range);
+ point_merge_indices[point_merge_counts[dst_index]] = i;
+ point_merge_counts[dst_index]++;
+ }
+
+ Set<bke::AttributeIDRef> attributes = src_points.attribute_ids();
+
+ /* Transfer the ID attribute if it exists, using the ID of the first merged point. */
+ if (attributes.contains("id")) {
+ VArray<int> src = src_points.attribute_get_for_read<int>("id", ATTR_DOMAIN_POINT, 0);
+ bke::OutputAttribute_Typed<int> dst = dst_points.attribute_try_get_for_output_only<int>(
+ "id", ATTR_DOMAIN_POINT);
+ Span<int> src_ids = src.get_internal_span();
+ MutableSpan<int> dst_ids = dst.as_span();
+
+ threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) {
+ for (const int i_dst : range) {
+ const IndexRange point_range(map_offsets[i_dst],
+ map_offsets[i_dst + 1] - map_offsets[i_dst]);
+ dst_ids[i_dst] = src_ids[point_range.first()];
+ }
+ });
+
+ dst.save();
+ attributes.remove_contained("id");
+ }
+
+ /* Transfer all other attributes. */
+ for (const bke::AttributeIDRef &id : attributes) {
+ if (!id.should_be_kept()) {
+ continue;
+ }
+
+ bke::ReadAttributeLookup src_attribute = src_points.attribute_try_get_for_read(id);
+ attribute_math::convert_to_static_type(src_attribute.varray.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ bke::OutputAttribute_Typed<T> dst_attribute =
+ dst_points.attribute_try_get_for_output_only<T>(id, ATTR_DOMAIN_POINT);
+ Span<T> src = src_attribute.varray.get_internal_span().typed<T>();
+ MutableSpan<T> dst = dst_attribute.as_span();
+
+ threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) {
+ for (const int i_dst : range) {
+ /* Create a separate mixer for every point to avoid allocating temporary buffers
+ * in the mixer the size of the result point cloud and to improve memory locality. */
+ attribute_math::DefaultMixer<T> mixer{dst.slice(i_dst, 1)};
+
+ const IndexRange point_range(map_offsets[i_dst],
+ map_offsets[i_dst + 1] - map_offsets[i_dst]);
+ Span<int> src_merge_indices = merge_map.as_span().slice(point_range);
+ for (const int i_src : src_merge_indices) {
+ mixer.mix_in(0, src[i_src]);
+ }
+
+ mixer.finalize();
+ }
+ });
+
+ dst_attribute.save();
+ }
+ });
+ }
+
+ return dst_pointcloud;
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index ae513bf88e9..4022794d53f 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -1167,7 +1167,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
const std::optional<GSpan> src_span_opt = src_point_attributes.get_for_read(attribute_id);
- void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), __func__);
+ void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), "Curve Attribute");
if (src_span_opt.has_value()) {
const GSpan src_span = *src_span_opt;
cpp_type.copy_construct_n(src_span.data(), dst_buffer, spline_size);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index f6a85919de4..c583a45a27d 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -40,6 +40,8 @@
#include "MOD_gpencil_modifiertypes.h"
#include "MOD_gpencil_util.h"
+#include "DEG_depsgraph_query.h"
+
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
{
#define INIT_GP_TYPE(typeName) \
@@ -73,7 +75,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
bool is_stroke_affected_by_modifier(Object *ob,
char *mlayername,
- const Material *material,
+ Material *material,
const int mpassindex,
const int gpl_passindex,
const int minpoints,
@@ -84,8 +86,8 @@ bool is_stroke_affected_by_modifier(Object *ob,
const bool inv3,
const bool inv4)
{
- Material *ma = BKE_gpencil_material(ob, gps->mat_nr + 1);
- MaterialGPencilStyle *gp_style = ma->gp_style;
+ Material *ma_gps = BKE_gpencil_material(ob, gps->mat_nr + 1);
+ MaterialGPencilStyle *gp_style = ma_gps->gp_style;
/* omit if filter by layer */
if (mlayername[0] != '\0') {
@@ -102,13 +104,16 @@ bool is_stroke_affected_by_modifier(Object *ob,
}
/* Omit if filter by material. */
if (material != NULL) {
+ /* Requires to use the original material to compare the same pointer address. */
+ Material *ma_md_orig = (Material *)DEG_get_original_id(&material->id);
+ Material *ma_gps_orig = (Material *)DEG_get_original_id(&ma_gps->id);
if (inv4 == false) {
- if (material != ma) {
+ if (ma_md_orig != ma_gps_orig) {
return false;
}
}
else {
- if (material == ma) {
+ if (ma_md_orig == ma_gps_orig) {
return false;
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index 59ed11a02f3..22893bdb184 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -34,16 +34,16 @@ struct bGPDstroke;
*/
bool is_stroke_affected_by_modifier(struct Object *ob,
char *mlayername,
- const struct Material *material,
- const int mpassindex,
- const int gpl_passindex,
- const int minpoints,
+ struct Material *material,
+ int mpassindex,
+ int gpl_passindex,
+ int minpoints,
bGPDlayer *gpl,
bGPDstroke *gps,
- const bool inv1,
- const bool inv2,
- const bool inv3,
- const bool inv4);
+ bool inv1,
+ bool inv2,
+ bool inv3,
+ bool inv4);
/**
* Verify if valid vertex group *and return weight.
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index b35ebd4be9a..6a3a27a6630 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -314,7 +314,9 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "source_object", 0, NULL, ICON_OBJECT_DATA);
}
else if (source_type == LRT_SOURCE_COLLECTION) {
- uiItemR(layout, ptr, "source_collection", 0, NULL, ICON_OUTLINER_COLLECTION);
+ uiLayout *sub = uiLayoutRow(layout, true);
+ uiItemR(sub, ptr, "source_collection", 0, NULL, ICON_OUTLINER_COLLECTION);
+ uiItemR(sub, ptr, "use_invert_collection", 0, "", ICON_ARROW_LEFTRIGHT);
}
else {
/* Source is Scene. */
@@ -407,6 +409,7 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_clip_plane_boundaries", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_crease_on_smooth", 0, IFACE_("Crease On Smooth"), ICON_NONE);
uiItemR(col, ptr, "use_crease_on_sharp", 0, IFACE_("Crease On Sharp"), ICON_NONE);
+ uiItemR(col, ptr, "use_back_face_culling", 0, NULL, ICON_NONE);
}
static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -578,6 +581,7 @@ static void face_mark_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "use_face_mark_invert", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "use_face_mark_boundaries", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_face_mark_keep_contour", 0, NULL, ICON_NONE);
}
static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -605,6 +609,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_fuzzy_all", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_loose_edge_chain", 0, IFACE_("Loose Edges"), ICON_NONE);
uiItemR(col, ptr, "use_loose_as_contour", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_detail_preserve", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "use_geometry_space_chain", 0, IFACE_("Geometry Space"), ICON_NONE);
uiItemR(layout,
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index 2ef72da03fd..cb17d1d5f1a 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -300,14 +300,18 @@ typedef struct LineartRenderBuffer {
bool use_loose_edge_chain;
bool use_geometry_space_chain;
bool use_image_boundary_trimming;
+ bool use_back_face_culling;
bool filter_face_mark;
bool filter_face_mark_invert;
bool filter_face_mark_boundaries;
+ bool filter_face_mark_keep_contour;
bool force_crease;
bool sharp_as_crease;
+ bool chain_preserve_details;
+
/* Keep an copy of these data so when line art is running it's self-contained. */
bool cam_is_persp;
float cam_obmat[4][4];
@@ -450,10 +454,10 @@ typedef struct LineartBoundingArea {
ListBase up;
ListBase bp;
- int16_t triangle_count;
- int16_t max_triangle_count;
- int16_t line_count;
- int16_t max_line_count;
+ uint16_t triangle_count;
+ uint16_t max_triangle_count;
+ uint16_t line_count;
+ uint16_t max_line_count;
/* Use array for speeding up multiple accesses. */
struct LineartTriangle **linked_triangles;
@@ -655,7 +659,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb);
* implemented yet.
*/
void MOD_lineart_chain_connect(LineartRenderBuffer *rb);
-void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold);
+void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, float threshold);
void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb);
/**
* This should always be the last stage!, see the end of
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index 0deb8b1c335..78ad895c93e 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -571,6 +571,57 @@ static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartEdg
}
}
+static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
+ LineartEdgeChainItem *last_matching_eci,
+ float distance_threshold,
+ bool preserve_details,
+ LineartEdgeChainItem **r_next_eci)
+{
+ float dist_accum = 0;
+
+ int fixed_occ = last_matching_eci->occlusion;
+ unsigned char fixed_mask = last_matching_eci->material_mask_bits;
+
+ LineartEdgeChainItem *can_skip_to = NULL;
+ LineartEdgeChainItem *last_eci = last_matching_eci;
+ for (LineartEdgeChainItem *eci = last_matching_eci->next; eci; eci = eci->next) {
+ dist_accum += len_v2v2(last_eci->pos, eci->pos);
+ if (dist_accum > distance_threshold) {
+ break;
+ }
+ last_eci = eci;
+ /* The reason for this is because we don't want visible segments to be "skipped" into
+ * connecting with invisible segments. */
+ if (eci->occlusion < fixed_occ) {
+ break;
+ }
+ if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) {
+ can_skip_to = eci;
+ }
+ }
+ if (can_skip_to) {
+ /* Either mark all in-between segments with the same occlusion and mask or delete those
+ * different ones. */
+ LineartEdgeChainItem *next_eci;
+ for (LineartEdgeChainItem *eci = last_matching_eci->next; eci != can_skip_to; eci = next_eci) {
+ next_eci = eci->next;
+ if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) {
+ continue;
+ }
+ if (preserve_details) {
+ eci->material_mask_bits = fixed_mask;
+ eci->occlusion = fixed_occ;
+ }
+ else {
+ BLI_remlink(&ec->chain, eci);
+ }
+ }
+ *r_next_eci = can_skip_to;
+ return true;
+ }
+ return false;
+}
+
void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
{
LineartEdgeChain *ec, *new_ec;
@@ -597,6 +648,13 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
if (lineart_point_overlapping(next_eci, eci->pos[0], eci->pos[1], 1e-5)) {
continue;
}
+ if (lineart_chain_fix_ambiguous_segments(ec,
+ eci->prev,
+ rb->chaining_image_threshold,
+ rb->chain_preserve_details,
+ &next_eci)) {
+ continue;
+ }
}
else {
/* Set the same occlusion level for the end vertex, so when further connection is needed
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index d9a32711833..5434f7768b2 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -327,7 +327,12 @@ BLI_INLINE bool lineart_occlusion_is_adjacent_intersection(LineartEdge *e, Linea
static void lineart_bounding_area_triangle_add(LineartRenderBuffer *rb,
LineartBoundingArea *ba,
LineartTriangle *tri)
-{
+{ /* In case of too many triangles concentrating in one point, do not add anymore, these triangles
+ * will be either narrower than a single pixel, or will still be added into the list of other
+ * less dense areas. */
+ if (ba->triangle_count >= 65535) {
+ return;
+ }
if (ba->triangle_count >= ba->max_triangle_count) {
LineartTriangle **new_array = lineart_mem_acquire(
&rb->render_data_pool, sizeof(LineartTriangle *) * ba->max_triangle_count * 2);
@@ -343,6 +348,12 @@ static void lineart_bounding_area_line_add(LineartRenderBuffer *rb,
LineartBoundingArea *ba,
LineartEdge *e)
{
+ /* In case of too many lines concentrating in one point, do not add anymore, these lines will
+ * be either shorter than a single pixel, or will still be added into the list of other less
+ * dense areas. */
+ if (ba->line_count >= 65535) {
+ return;
+ }
if (ba->line_count >= ba->max_line_count) {
LineartEdge **new_array = lineart_mem_acquire(&rb->render_data_pool,
sizeof(LineartEdge *) * ba->max_line_count * 2);
@@ -1335,6 +1346,10 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
/* Select the triangle in the array. */
tri = (void *)(((uchar *)eln->pointer) + rb->triangle_size * i);
+ if (tri->flags & LRT_CULL_DISCARD) {
+ continue;
+ }
+
LRT_CULL_DECIDE_INSIDE
LRT_CULL_ENSURE_MEMORY
lineart_triangle_cull_single(rb,
@@ -1478,6 +1493,7 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
FreestyleEdge *fel, *fer;
bool face_mark_filtered = false;
uint16_t edge_flag_result = 0;
+ bool only_contour = false;
if (use_freestyle_face && rb->filter_face_mark) {
fel = CustomData_bmesh_get(&bm_if_freestyle->pdata, ll->f->head.data, CD_FREESTYLE_FACE);
@@ -1502,7 +1518,12 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
face_mark_filtered = !face_mark_filtered;
}
if (!face_mark_filtered) {
- return 0;
+ if (rb->filter_face_mark_keep_contour) {
+ only_contour = true;
+ }
+ else {
+ return 0;
+ }
}
}
@@ -1525,8 +1546,31 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
double dot_1 = 0, dot_2 = 0;
double result;
- if (rb->cam_is_persp) {
- sub_v3_v3v3_db(view_vector, l->gloc, rb->camera_pos);
+ if (rb->use_contour || rb->use_back_face_culling) {
+
+ if (rb->cam_is_persp) {
+ sub_v3_v3v3_db(view_vector, rb->camera_pos, l->gloc);
+ }
+ else {
+ view_vector = rb->view_vector;
+ }
+
+ dot_1 = dot_v3v3_db(view_vector, tri1->gn);
+ dot_2 = dot_v3v3_db(view_vector, tri2->gn);
+
+ if (rb->use_contour && (result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
+ edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
+ }
+
+ /* Because the ray points towards the camera, so back-face is when dot value being negative. */
+ if (rb->use_back_face_culling) {
+ if (dot_1 < 0) {
+ tri1->flags |= LRT_CULL_DISCARD;
+ }
+ if (dot_2 < 0) {
+ tri2->flags |= LRT_CULL_DISCARD;
+ }
+ }
}
else {
view_vector = rb->view_vector;
@@ -1539,6 +1583,12 @@ static uint16_t lineart_identify_feature_line(LineartRenderBuffer *rb,
edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
}
+ /* For when face mark filtering decided that we discard the face but keep_contour option is on.
+ * so we still have correct full contour around the object. */
+ if (only_contour) {
+ return edge_flag_result;
+ }
+
if (rb->use_crease) {
if (rb->sharp_as_crease && !BM_elem_flag_test(e, BM_ELEM_SMOOTH)) {
edge_flag_result |= LRT_EDGE_FLAG_CREASE;
@@ -1766,7 +1816,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
use_crease = cosf(M_PI - orig_ob->lineart.crease_threshold);
}
- if (obi->original_me->flag & ME_AUTOSMOOTH) {
+ else if (obi->original_me->flag & ME_AUTOSMOOTH) {
use_crease = cosf(obi->original_me->smoothresh);
use_auto_smooth = true;
}
@@ -1864,7 +1914,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
bm);
if (eflag) {
/* Only allocate for feature lines (instead of all lines) to save memory.
- * If allow duplicated edges, one edge gets added multiple times if it has multiple types. */
+ * If allow duplicated edges, one edge gets added multiple times if it has multiple types.
+ */
allocate_la_e += rb->allow_duplicated_types ? lineart_edge_type_duplication_count(eflag) : 1;
}
/* Here we just use bm's flag for when loading actual lines, then we don't need to call
@@ -1959,13 +2010,12 @@ static uchar lineart_intersection_mask_check(Collection *c, Object *ob)
}
}
- if (c->children.first == NULL) {
- if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
- if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_MASK) {
- return c->lineart_intersection_mask;
- }
+ if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
+ if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_MASK) {
+ return c->lineart_intersection_mask;
}
}
+
return 0;
}
@@ -2059,8 +2109,8 @@ static bool lineart_geometry_check_visible(double (*model_view_proj)[4],
}
bool cond[6] = {true, true, true, true, true, true};
- /* Because for a point to be inside clip space, it must satisfy `-Wc <= XYCc <= Wc`, here if all
- * verts falls to the same side of the clip space border, we know it's outside view. */
+ /* Because for a point to be inside clip space, it must satisfy `-Wc <= XYCc <= Wc`, here if
+ * all verts falls to the same side of the clip space border, we know it's outside view. */
for (int i = 0; i < 8; i++) {
cond[0] &= (co[i][0] < -co[i][3]);
cond[1] &= (co[i][0] > co[i][3]);
@@ -2135,7 +2185,8 @@ static void lineart_main_load_geometries(
int thread_count = rb->thread_count;
- /* This memory is in render buffer memory pool. so we don't need to free those after loading. */
+ /* This memory is in render buffer memory pool. so we don't need to free those after loading.
+ */
LineartObjectLoadTaskInfo *olti = lineart_mem_acquire(
&rb->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count);
@@ -2418,8 +2469,9 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
dot_f = dot_v3v3_db(Cv, tri->gn);
/* NOTE(Yiming): When we don't use `dot_f==0` here, it's theoretically possible that _some_
- * faces in perspective mode would get erroneously caught in this condition where they really are
- * legit faces that would produce occlusion, but haven't encountered those yet in my test files.
+ * faces in perspective mode would get erroneously caught in this condition where they really
+ * are legit faces that would produce occlusion, but haven't encountered those yet in my test
+ * files.
*/
if (fabs(dot_f) < FLT_EPSILON) {
return false;
@@ -2486,8 +2538,9 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
return false; \
}
- /* Determine the pair of edges that the line has crossed. The "|" symbol in the comment indicates
- * triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision tolerance. */
+ /* Determine the pair of edges that the line has crossed. The "|" symbol in the comment
+ * indicates triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision
+ * tolerance. */
if (st_l == 2) {
/* Left side is in the triangle. */
@@ -2574,8 +2627,12 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
}
else {
- INTERSECT_JUST_GREATER(is, order, is[LCross], LCross);
- INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ if (LCross >= 0) {
+ INTERSECT_JUST_GREATER(is, order, is[LCross], LCross);
+ if (LCross >= 0) {
+ INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ }
+ }
}
}
}
@@ -2930,15 +2987,7 @@ static LineartEdge *lineart_triangle_intersect(LineartRenderBuffer *rb,
result->intersection_mask = (tri->intersection_mask | testing->intersection_mask);
lineart_prepend_edge_direct(&rb->intersection.first, result);
- int r1, r2, c1, c2, row, col;
- if (lineart_get_edge_bounding_areas(rb, result, &r1, &r2, &c1, &c2)) {
- for (row = r1; row != r2 + 1; row++) {
- for (col = c1; col != c2 + 1; col++) {
- lineart_bounding_area_link_edge(
- rb, &rb->initial_bounding_areas[row * LRT_BA_ROWS + col], result);
- }
- }
- }
+
return result;
}
@@ -3152,6 +3201,14 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->force_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SMOOTH_SURFACES) != 0;
rb->sharp_as_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SHARP_EDGES) != 0;
+ rb->chain_preserve_details = (lmd->calculation_flags & LRT_CHAIN_PRESERVE_DETAILS) != 0;
+
+ /* This is used to limit calculation to a certain level to save time, lines who have higher
+ * occlusion levels will get ignored. */
+ rb->max_occlusion_level = lmd->level_end_override;
+
+ rb->use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0;
+
int16_t edge_types = lmd->edge_types_override;
rb->use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
@@ -3165,6 +3222,8 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
rb->filter_face_mark = (lmd->calculation_flags & LRT_FILTER_FACE_MARK) != 0;
rb->filter_face_mark_boundaries = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_BOUNDARIES) !=
0;
+ rb->filter_face_mark_keep_contour = (lmd->calculation_flags &
+ LRT_FILTER_FACE_MARK_KEEP_CONTOUR) != 0;
rb->chain_data_pool = &lc->chain_data_pool;
@@ -3409,7 +3468,6 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb,
LineartBoundingArea *ba = lineart_mem_acquire(&rb->render_data_pool,
sizeof(LineartBoundingArea) * 4);
LineartTriangle *tri;
- LineartEdge *e;
ba[0].l = root->cx;
ba[0].r = root->r;
@@ -3475,11 +3533,6 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb,
}
}
- for (int i = 0; i < root->line_count; i++) {
- e = root->linked_lines[i];
- lineart_bounding_area_link_edge(rb, root, e);
- }
-
rb->bounding_area_count += 3;
}
@@ -4176,12 +4229,6 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
* See definition of LineartTriangleThread for details. */
rb->triangle_size = lineart_triangle_size_get(scene, rb);
- /* This is used to limit calculation to a certain level to save time, lines who have higher
- * occlusion levels will get ignored. */
- rb->max_occlusion_level = (lmd->flags & LRT_GPENCIL_USE_CACHE) ?
- lmd->level_end_override :
- (lmd->use_multiple_levels ? lmd->level_end : lmd->level_start);
-
/* FIXME(Yiming): See definition of int #LineartRenderBuffer::_source_type for detailed. */
rb->_source_type = lmd->source_type;
rb->_source_collection = lmd->source_collection;
@@ -4253,8 +4300,8 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
if (rb->chain_smooth_tolerance > FLT_EPSILON) {
/* Keeping UI range of 0-1 for ease of read while scaling down the actual value for best
- * effective range in image-space (Coordinate only goes from -1 to 1). This value is somewhat
- * arbitrary, but works best for the moment. */
+ * effective range in image-space (Coordinate only goes from -1 to 1). This value is
+ * somewhat arbitrary, but works best for the moment. */
MOD_lineart_smooth_chains(rb, rb->chain_smooth_tolerance / 50);
}
@@ -4363,8 +4410,15 @@ static void lineart_gpencil_generate(LineartCache *cache,
continue;
}
if (orig_col && ec->object_ref) {
- if (!BKE_collection_has_object_recursive_instanced(orig_col, (Object *)ec->object_ref)) {
- continue;
+ if (BKE_collection_has_object_recursive_instanced(orig_col, (Object *)ec->object_ref)) {
+ if (modifier_flags & LRT_GPENCIL_INVERT_COLLECTION) {
+ continue;
+ }
+ }
+ else {
+ if (!(modifier_flags & LRT_GPENCIL_INVERT_COLLECTION)) {
+ continue;
+ }
}
}
if (mask_switches & LRT_GPENCIL_MATERIAL_MASK_ENABLE) {
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 4868096e594..49b6b478148 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -83,6 +83,8 @@ set(SRC
intern/gpu_select_sample_query.cc
intern/gpu_shader.cc
intern/gpu_shader_builtin.c
+ intern/gpu_shader_create_info.cc
+ intern/gpu_shader_dependency.cc
intern/gpu_shader_interface.cc
intern/gpu_shader_log.cc
intern/gpu_state.cc
@@ -135,6 +137,7 @@ set(SRC
GPU_primitive.h
GPU_select.h
GPU_shader.h
+ GPU_shader_shared.h
GPU_state.h
GPU_texture.h
GPU_uniform_buffer.h
@@ -159,6 +162,8 @@ set(SRC
intern/gpu_private.h
intern/gpu_query.hh
intern/gpu_select_private.h
+ intern/gpu_shader_create_info.hh
+ intern/gpu_shader_create_info_private.hh
intern/gpu_shader_interface.hh
intern/gpu_shader_private.hh
intern/gpu_state_private.hh
@@ -197,187 +202,261 @@ if(NOT WITH_SYSTEM_GLEW)
)
endif()
-data_to_c_simple(shaders/gpu_shader_depth_only_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_uniform_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_checker_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_diag_stripes_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_simple_lighting_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_flat_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_flat_id_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_area_borders_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_area_borders_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_widget_base_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_widget_base_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_nodelink_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_nodelink_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_flat_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_line_dashed_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_image_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_image_rect_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_image_multi_rect_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_desaturate_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_overlays_merge_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_modulate_alpha_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_shuffle_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_varying_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_normal_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_polyline_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_polyline_geom.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_polyline_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_passthrough_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_point_uniform_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_point_uniform_color_aa_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_point_varying_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_points_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_facedots_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_edges_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_edges_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_faces_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_edituvs_stretch_vert.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_text_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_text_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_keyframe_shape_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_keyframe_shape_frag.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_codegen_lib.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
-
-data_to_c_simple(shaders/material/gpu_shader_material_add_shader.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_ambient_occlusion.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_anisotropic.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_attribute.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_background.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_bevel.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_wavelength.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_blackbody.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_bright_contrast.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_bump.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_camera.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_clamp.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_color_ramp.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_color_util.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_combine_hsv.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_combine_rgb.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_combine_xyz.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_diffuse.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_displacement.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_eevee_specular.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_emission.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_float_curve.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_fractal_noise.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_fresnel.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_gamma.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_geometry.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_glass.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_glossy.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_hair_info.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_hash.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_holdout.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_hue_sat_val.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_invert.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_layer_weight.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_light_falloff.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_light_path.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_mapping.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_map_range.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_math.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_math_util.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_mix_rgb.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_mix_shader.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_noise.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_normal.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_normal_map.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_object_info.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_output_aov.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_output_material.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_output_world.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_particle_info.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_principled.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_refraction.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_rgb_curves.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_rgb_to_bw.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_separate_hsv.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_separate_rgb.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_separate_xyz.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_set.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_shader_to_rgba.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_squeeze.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_subsurface_scattering.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tangent.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_brick.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_checker.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_environment.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_gradient.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_image.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_magic.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_musgrave.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_noise.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_sky.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_texture_coordinates.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_voronoi.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_wave.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_tex_white_noise.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_toon.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_translucent.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_transparent.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_uv_map.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_vector_curves.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_vector_displacement.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_vector_math.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_vector_rotate.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_velvet.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_vertex_color.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_volume_absorption.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_volume_info.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_volume_principled.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_volume_scatter.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_wireframe.glsl SRC)
-data_to_c_simple(shaders/material/gpu_shader_material_world_normals.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_gpencil_stroke_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_gpencil_stroke_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_gpencil_stroke_geom.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_colorspace_lib.glsl SRC)
-
-data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC)
+set(GLSL_SRC
+ GPU_shader_shared.h
+
+ shaders/gpu_shader_depth_only_frag.glsl
+ shaders/gpu_shader_uniform_color_frag.glsl
+ shaders/gpu_shader_checker_frag.glsl
+ shaders/gpu_shader_diag_stripes_frag.glsl
+ shaders/gpu_shader_simple_lighting_frag.glsl
+ shaders/gpu_shader_flat_color_frag.glsl
+ shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl
+ shaders/gpu_shader_flat_id_frag.glsl
+ shaders/gpu_shader_2D_vert.glsl
+ shaders/gpu_shader_2D_area_borders_vert.glsl
+ shaders/gpu_shader_2D_area_borders_frag.glsl
+ shaders/gpu_shader_2D_widget_base_vert.glsl
+ shaders/gpu_shader_2D_widget_base_frag.glsl
+ shaders/gpu_shader_2D_widget_shadow_vert.glsl
+ shaders/gpu_shader_2D_widget_shadow_frag.glsl
+ shaders/gpu_shader_2D_nodelink_frag.glsl
+ shaders/gpu_shader_2D_nodelink_vert.glsl
+ shaders/gpu_shader_2D_flat_color_vert.glsl
+ shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
+ shaders/gpu_shader_2D_line_dashed_frag.glsl
+ shaders/gpu_shader_2D_smooth_color_vert.glsl
+ shaders/gpu_shader_2D_smooth_color_frag.glsl
+ shaders/gpu_shader_2D_image_vert.glsl
+ shaders/gpu_shader_2D_image_rect_vert.glsl
+ shaders/gpu_shader_2D_image_multi_rect_vert.glsl
+ shaders/gpu_shader_image_frag.glsl
+ shaders/gpu_shader_image_desaturate_frag.glsl
+ shaders/gpu_shader_image_overlays_merge_frag.glsl
+ shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
+ shaders/gpu_shader_image_modulate_alpha_frag.glsl
+ shaders/gpu_shader_image_shuffle_color_frag.glsl
+ shaders/gpu_shader_image_color_frag.glsl
+ shaders/gpu_shader_image_varying_color_frag.glsl
+ shaders/gpu_shader_3D_image_vert.glsl
+ shaders/gpu_shader_3D_vert.glsl
+ shaders/gpu_shader_3D_normal_vert.glsl
+ shaders/gpu_shader_3D_flat_color_vert.glsl
+ shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
+ shaders/gpu_shader_3D_polyline_frag.glsl
+ shaders/gpu_shader_3D_polyline_geom.glsl
+ shaders/gpu_shader_3D_polyline_vert.glsl
+ shaders/gpu_shader_3D_smooth_color_vert.glsl
+ shaders/gpu_shader_3D_smooth_color_frag.glsl
+ shaders/gpu_shader_3D_passthrough_vert.glsl
+ shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl
+
+ shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
+
+ shaders/gpu_shader_point_uniform_color_aa_frag.glsl
+ shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl
+ shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl
+ shaders/gpu_shader_point_varying_color_frag.glsl
+ shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl
+ shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl
+ shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl
+ shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl
+ shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl
+ shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl
+
+ shaders/gpu_shader_text_vert.glsl
+ shaders/gpu_shader_text_frag.glsl
+ shaders/gpu_shader_keyframe_shape_vert.glsl
+ shaders/gpu_shader_keyframe_shape_frag.glsl
+
+ shaders/gpu_shader_codegen_lib.glsl
+
+ shaders/gpu_shader_geometry.glsl
+
+ shaders/material/gpu_shader_material_add_shader.glsl
+ shaders/material/gpu_shader_material_ambient_occlusion.glsl
+ shaders/material/gpu_shader_material_anisotropic.glsl
+ shaders/material/gpu_shader_material_attribute.glsl
+ shaders/material/gpu_shader_material_background.glsl
+ shaders/material/gpu_shader_material_bevel.glsl
+ shaders/material/gpu_shader_material_wavelength.glsl
+ shaders/material/gpu_shader_material_blackbody.glsl
+ shaders/material/gpu_shader_material_bright_contrast.glsl
+ shaders/material/gpu_shader_material_bump.glsl
+ shaders/material/gpu_shader_material_camera.glsl
+ shaders/material/gpu_shader_material_clamp.glsl
+ shaders/material/gpu_shader_material_color_ramp.glsl
+ shaders/material/gpu_shader_material_color_util.glsl
+ shaders/material/gpu_shader_material_combine_hsv.glsl
+ shaders/material/gpu_shader_material_combine_rgb.glsl
+ shaders/material/gpu_shader_material_combine_xyz.glsl
+ shaders/material/gpu_shader_material_diffuse.glsl
+ shaders/material/gpu_shader_material_displacement.glsl
+ shaders/material/gpu_shader_material_eevee_specular.glsl
+ shaders/material/gpu_shader_material_emission.glsl
+ shaders/material/gpu_shader_material_float_curve.glsl
+ shaders/material/gpu_shader_material_fractal_noise.glsl
+ shaders/material/gpu_shader_material_fresnel.glsl
+ shaders/material/gpu_shader_material_gamma.glsl
+ shaders/material/gpu_shader_material_geometry.glsl
+ shaders/material/gpu_shader_material_glass.glsl
+ shaders/material/gpu_shader_material_glossy.glsl
+ shaders/material/gpu_shader_material_hair_info.glsl
+ shaders/material/gpu_shader_material_hash.glsl
+ shaders/material/gpu_shader_material_holdout.glsl
+ shaders/material/gpu_shader_material_hue_sat_val.glsl
+ shaders/material/gpu_shader_material_invert.glsl
+ shaders/material/gpu_shader_material_layer_weight.glsl
+ shaders/material/gpu_shader_material_light_falloff.glsl
+ shaders/material/gpu_shader_material_light_path.glsl
+ shaders/material/gpu_shader_material_mapping.glsl
+ shaders/material/gpu_shader_material_map_range.glsl
+ shaders/material/gpu_shader_material_math.glsl
+ shaders/material/gpu_shader_material_math_util.glsl
+ shaders/material/gpu_shader_material_mix_rgb.glsl
+ shaders/material/gpu_shader_material_mix_shader.glsl
+ shaders/material/gpu_shader_material_noise.glsl
+ shaders/material/gpu_shader_material_normal.glsl
+ shaders/material/gpu_shader_material_normal_map.glsl
+ shaders/material/gpu_shader_material_object_info.glsl
+ shaders/material/gpu_shader_material_output_aov.glsl
+ shaders/material/gpu_shader_material_output_material.glsl
+ shaders/material/gpu_shader_material_output_world.glsl
+ shaders/material/gpu_shader_material_particle_info.glsl
+ shaders/material/gpu_shader_material_point_info.glsl
+ shaders/material/gpu_shader_material_principled.glsl
+ shaders/material/gpu_shader_material_refraction.glsl
+ shaders/material/gpu_shader_material_rgb_curves.glsl
+ shaders/material/gpu_shader_material_rgb_to_bw.glsl
+ shaders/material/gpu_shader_material_separate_hsv.glsl
+ shaders/material/gpu_shader_material_separate_rgb.glsl
+ shaders/material/gpu_shader_material_separate_xyz.glsl
+ shaders/material/gpu_shader_material_set.glsl
+ shaders/material/gpu_shader_material_shader_to_rgba.glsl
+ shaders/material/gpu_shader_material_squeeze.glsl
+ shaders/material/gpu_shader_material_subsurface_scattering.glsl
+ shaders/material/gpu_shader_material_tangent.glsl
+ shaders/material/gpu_shader_material_tex_brick.glsl
+ shaders/material/gpu_shader_material_tex_checker.glsl
+ shaders/material/gpu_shader_material_tex_environment.glsl
+ shaders/material/gpu_shader_material_tex_gradient.glsl
+ shaders/material/gpu_shader_material_tex_image.glsl
+ shaders/material/gpu_shader_material_tex_magic.glsl
+ shaders/material/gpu_shader_material_tex_musgrave.glsl
+ shaders/material/gpu_shader_material_tex_noise.glsl
+ shaders/material/gpu_shader_material_tex_sky.glsl
+ shaders/material/gpu_shader_material_texture_coordinates.glsl
+ shaders/material/gpu_shader_material_tex_voronoi.glsl
+ shaders/material/gpu_shader_material_tex_wave.glsl
+ shaders/material/gpu_shader_material_tex_white_noise.glsl
+ shaders/material/gpu_shader_material_toon.glsl
+ shaders/material/gpu_shader_material_translucent.glsl
+ shaders/material/gpu_shader_material_transparent.glsl
+ shaders/material/gpu_shader_material_uv_map.glsl
+ shaders/material/gpu_shader_material_vector_curves.glsl
+ shaders/material/gpu_shader_material_vector_displacement.glsl
+ shaders/material/gpu_shader_material_vector_math.glsl
+ shaders/material/gpu_shader_material_vector_rotate.glsl
+ shaders/material/gpu_shader_material_velvet.glsl
+ shaders/material/gpu_shader_material_vertex_color.glsl
+ shaders/material/gpu_shader_material_volume_absorption.glsl
+ shaders/material/gpu_shader_material_volume_info.glsl
+ shaders/material/gpu_shader_material_volume_principled.glsl
+ shaders/material/gpu_shader_material_volume_scatter.glsl
+ shaders/material/gpu_shader_material_wireframe.glsl
+ shaders/material/gpu_shader_material_world_normals.glsl
+
+ shaders/gpu_shader_gpencil_stroke_vert.glsl
+ shaders/gpu_shader_gpencil_stroke_frag.glsl
+ shaders/gpu_shader_gpencil_stroke_geom.glsl
+
+ shaders/gpu_shader_cfg_world_clip_lib.glsl
+ shaders/gpu_shader_colorspace_lib.glsl
+
+ shaders/gpu_shader_common_obinfos_lib.glsl
+
+ intern/gpu_shader_shared_utils.h
+)
+
+set(GLSL_C)
+foreach(GLSL_FILE ${GLSL_SRC})
+ data_to_c_simple(${GLSL_FILE} GLSL_C)
+endforeach()
+
+blender_add_lib(bf_gpu_shaders "${GLSL_C}" "" "" "")
+
+list(APPEND LIB
+ bf_gpu_shaders
+)
+
+set(GLSL_SOURCE_CONTENT "")
+foreach(GLSL_FILE ${GLSL_SRC})
+ get_filename_component(GLSL_FILE_NAME ${GLSL_FILE} NAME)
+ string(REPLACE "." "_" GLSL_FILE_NAME_UNDERSCORES ${GLSL_FILE_NAME})
+ string(APPEND GLSL_SOURCE_CONTENT "SHADER_SOURCE\(datatoc_${GLSL_FILE_NAME_UNDERSCORES}, \"${GLSL_FILE_NAME}\", \"${GLSL_FILE}\"\)\n")
+endforeach()
+
+set(glsl_source_list_file "${CMAKE_CURRENT_BINARY_DIR}/glsl_gpu_source_list.h")
+file(GENERATE OUTPUT ${glsl_source_list_file} CONTENT "${GLSL_SOURCE_CONTENT}")
+list(APPEND SRC ${glsl_source_list_file})
+list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR})
+
+set(SHADER_CREATE_INFOS
+../draw/engines/workbench/shaders/infos/workbench_composite_info.hh
+../draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh
+../draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh
+../draw/engines/workbench/shaders/infos/workbench_effect_dof_info.hh
+../draw/engines/workbench/shaders/infos/workbench_effect_outline_info.hh
+../draw/engines/workbench/shaders/infos/workbench_merge_infront_info.hh
+../draw/engines/workbench/shaders/infos/workbench_prepass_info.hh
+../draw/engines/workbench/shaders/infos/workbench_shadow_info.hh
+../draw/engines/workbench/shaders/infos/workbench_transparent_resolve_info.hh
+../draw/engines/workbench/shaders/infos/workbench_volume_info.hh
+../draw/intern/shaders/draw_fullscreen_info.hh
+../draw/intern/shaders/draw_object_infos_info.hh
+../draw/intern/shaders/draw_view_info.hh
+../draw/intern/shaders/draw_hair_refine_info.hh
+
+shaders/infos/gpu_clip_planes_info.hh
+shaders/infos/gpu_shader_2D_area_borders_info.hh
+shaders/infos/gpu_shader_2D_checker_info.hh
+shaders/infos/gpu_shader_2D_diag_stripes_info.hh
+shaders/infos/gpu_shader_2D_flat_color_info.hh
+shaders/infos/gpu_shader_2D_image_color_info.hh
+shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh
+shaders/infos/gpu_shader_2D_image_info.hh
+shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh
+shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh
+shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
+shaders/infos/gpu_shader_2D_image_rect_color_info.hh
+shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh
+shaders/infos/gpu_shader_2D_nodelink_info.hh
+shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh
+shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh
+shaders/infos/gpu_shader_2D_point_varying_size_varying_color_info.hh
+shaders/infos/gpu_shader_2D_smooth_color_info.hh
+shaders/infos/gpu_shader_2D_uniform_color_info.hh
+shaders/infos/gpu_shader_3D_depth_only_info.hh
+shaders/infos/gpu_shader_3D_flat_color_info.hh
+shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh
+shaders/infos/gpu_shader_3D_point_info.hh
+shaders/infos/gpu_shader_3D_smooth_color_info.hh
+shaders/infos/gpu_shader_3D_uniform_color_info.hh
+shaders/infos/gpu_shader_gpencil_stroke_info.hh
+shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh
+shaders/infos/gpu_shader_keyframe_shape_info.hh
+shaders/infos/gpu_shader_simple_lighting_info.hh
+shaders/infos/gpu_shader_text_info.hh
+shaders/infos/gpu_srgb_to_framebuffer_space_info.hh
+)
+
+set(SHADER_CREATE_INFOS_CONTENT "")
+foreach(DESCRIPTOR_FILE ${SHADER_CREATE_INFOS})
+string(APPEND SHADER_CREATE_INFOS_CONTENT "#include \"${DESCRIPTOR_FILE}\"\n")
+endforeach()
+set(shader_create_info_list_file "${CMAKE_CURRENT_BINARY_DIR}/gpu_shader_create_info_list.hh")
+file(GENERATE OUTPUT ${shader_create_info_list_file} CONTENT "${SHADER_CREATE_INFOS_CONTENT}")
if(WITH_MOD_FLUID)
add_definitions(-DWITH_FLUID)
@@ -390,11 +469,48 @@ if(WITH_IMAGE_DDS)
endif()
blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+target_link_libraries(bf_gpu PUBLIC
+ bf_draw_shaders
+ bf_gpu_shaders
+)
if(CXX_WARN_NO_SUGGEST_OVERRIDE)
target_compile_options(bf_gpu PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wsuggest-override>)
endif()
+
+
+if(WITH_GPU_SHADER_BUILDER)
+ add_executable(shader_builder
+ intern/gpu_shader_builder.cc
+ intern/gpu_shader_builder_stubs.cc
+ ${shader_create_info_list_file}
+ )
+
+ target_link_libraries(shader_builder PUBLIC
+ bf_blenkernel
+ ${PLATFORM_LINKLIBS}
+ )
+ target_include_directories(shader_builder PRIVATE ${INC} ${CMAKE_CURRENT_BINARY_DIR})
+
+ set(BAKED_CREATE_INFOS_FILE ${CMAKE_CURRENT_BINARY_DIR}/shader_baked.hh)
+
+ add_custom_command(
+ OUTPUT
+ ${BAKED_CREATE_INFOS_FILE}
+ COMMAND
+ "$<TARGET_FILE:shader_builder>" ${BAKED_CREATE_INFOS_FILE}
+ DEPENDS shader_builder
+ )
+ set(GPU_SHADER_INFO_SRC
+ intern/gpu_shader_info_baked.cc
+ ${BAKED_CREATE_INFOS_FILE}
+ )
+
+ blender_add_lib(bf_gpu_shader_infos "${GPU_SHADER_INFO_SRC}" "" "" "")
+endif()
+
+
if(WITH_GTESTS)
if(WITH_OPENGL_DRAW_TESTS)
set(TEST_SRC
@@ -407,10 +523,8 @@ if(WITH_GTESTS)
tests/gpu_testing.hh
)
set(TEST_INC
- "../../../intern/ghost/"
)
set(TEST_LIB
-
)
include(GTestTesting)
blender_add_test_lib(bf_gpu_tests "${TEST_SRC}" "${INC};${TEST_INC}" "${INC_SYS}" "${LIB};${TEST_LIB}")
diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h
index a8bc4f271c9..b193b45d65c 100644
--- a/source/blender/gpu/GPU_batch.h
+++ b/source/blender/gpu/GPU_batch.h
@@ -30,6 +30,7 @@
#include "GPU_index_buffer.h"
#include "GPU_shader.h"
+#include "GPU_uniform_buffer.h"
#include "GPU_vertex_buffer.h"
#define GPU_BATCH_VBO_MAX_LEN 16
@@ -170,6 +171,8 @@ void GPU_batch_program_set_builtin_with_config(GPUBatch *batch,
GPU_shader_uniform_4fv_array((batch)->shader, name, len, val);
#define GPU_batch_uniform_mat4(batch, name, val) \
GPU_shader_uniform_mat4((batch)->shader, name, val);
+#define GPU_batch_uniformbuf_bind(batch, name, ubo) \
+ GPU_uniformbuf_bind(ubo, GPU_shader_get_uniform_block_binding((batch)->shader, name));
#define GPU_batch_texture_bind(batch, name, tex) \
GPU_texture_bind(tex, GPU_shader_get_texture_binding((batch)->shader, name));
diff --git a/source/blender/gpu/GPU_batch_presets.h b/source/blender/gpu/GPU_batch_presets.h
index 73c9172f2ba..1681db8126a 100644
--- a/source/blender/gpu/GPU_batch_presets.h
+++ b/source/blender/gpu/GPU_batch_presets.h
@@ -39,10 +39,10 @@ extern "C" {
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,
+struct GPUBatch *GPU_batch_preset_panel_drag_widget(float pixelsize,
const float col_high[4],
const float col_dark[4],
- const float width) ATTR_WARN_UNUSED_RESULT;
+ float width) ATTR_WARN_UNUSED_RESULT;
/**
* To be used with procedural placement inside shader.
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 9ba283bf65f..0a1d9c3b6d5 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -61,7 +61,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct MPoly *mpoly,
const struct MVert *mvert,
const int *face_indices,
const int *sculpt_face_sets,
- const int face_indices_len,
+ int face_indices_len,
const struct Mesh *mesh);
/**
@@ -96,13 +96,14 @@ enum {
*/
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const struct MVert *mvert,
+ const float (*vert_normals)[3],
const float *vmask,
const struct MLoopCol *vcol,
const int *sculpt_face_sets,
- const int face_sets_color_seed,
- const int face_sets_color_default,
+ int face_sets_color_seed,
+ int face_sets_color_default,
const struct MPropCol *vtcol,
- const int update_flags);
+ int update_flags);
/**
* Creates a vertex buffer (coordinate, normal, color) and,
@@ -114,7 +115,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
struct GSet *bm_faces,
struct GSet *bm_unique_verts,
struct GSet *bm_other_verts,
- const int update_flags);
+ int update_flags);
/**
* Threaded: do not call any functions that use OpenGL calls!
@@ -126,10 +127,10 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
int *grid_indices,
int totgrid,
const int *sculpt_face_sets,
- const int face_sets_color_seed,
- const int face_sets_color_default,
+ int face_sets_color_seed,
+ int face_sets_color_default,
const struct CCGKey *key,
- const int update_flags);
+ int update_flags);
/**
* Finish update. Not thread safe, must run in OpenGL main thread.
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index 5189fa1ae41..5e67441be27 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -40,6 +40,8 @@ typedef enum eGPUBackendType {
void GPU_backend_init(eGPUBackendType backend);
void GPU_backend_exit(void);
+eGPUBackendType GPU_backend_get_type(void);
+
/** Opaque type hiding blender::gpu::Context. */
typedef struct GPUContext GPUContext;
diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h
index a175fc65ba4..1b288d19c4a 100644
--- a/source/blender/gpu/GPU_immediate.h
+++ b/source/blender/gpu/GPU_immediate.h
@@ -122,6 +122,7 @@ void immUniformMatrix4fv(const char *name, const float data[4][4]);
void immBindTexture(const char *name, GPUTexture *tex);
void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState state);
+void immBindUniformBuf(const char *name, GPUUniformBuf *ubo);
/* Convenience functions for setting "uniform vec4 color". */
/* The RGB functions have implicit alpha = 1.0. */
diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h
index 102bd6c284c..cd45913158d 100644
--- a/source/blender/gpu/GPU_immediate_util.h
+++ b/source/blender/gpu/GPU_immediate_util.h
@@ -148,7 +148,7 @@ void imm_draw_cube_wire_3d(uint pos, const float center[3], const float aspect[3
void imm_draw_cube_corners_3d(uint pos,
const float center[3],
const float aspect[3],
- const float factor);
+ float factor);
/**
* Draw a cylinder. Replacement for #gluCylinder.
diff --git a/source/blender/gpu/GPU_index_buffer.h b/source/blender/gpu/GPU_index_buffer.h
index e4f1709173e..0f83e590597 100644
--- a/source/blender/gpu/GPU_index_buffer.h
+++ b/source/blender/gpu/GPU_index_buffer.h
@@ -53,6 +53,8 @@ void GPU_indexbuf_init_ex(GPUIndexBufBuilder *, GPUPrimType, uint index_len, uin
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len);
GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len);
+void GPU_indexbuf_init_build_on_device(GPUIndexBuf *elem, uint index_len);
+
/*
* Thread safe.
*
@@ -82,6 +84,16 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *);
void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding);
+/* Upload data to the GPU (if not built on the device) and bind the buffer to its default target.
+ */
+void GPU_indexbuf_use(GPUIndexBuf *elem);
+
+/* Partially update the GPUIndexBuf which was already sent to the device, or built directly on the
+ * device. The data needs to be compatible with potential compression applied to the original
+ * indices when the index buffer was built, i.e., if the data was compressed to use shorts instead
+ * of ints, shorts should passed here. */
+void GPU_indexbuf_update_sub(GPUIndexBuf *elem, uint start, uint len, const void *data);
+
/* Create a sub-range of an existing index-buffer. */
GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length);
void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem,
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index ea3028e539b..3555b957d67 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -24,6 +24,7 @@
#pragma once
#include "DNA_customdata_types.h" /* for CustomDataType */
+#include "DNA_image_types.h"
#include "DNA_listBase.h"
#include "BLI_sys_types.h" /* for bool */
@@ -170,7 +171,7 @@ bool GPU_stack_link(GPUMaterial *mat,
GPUNodeLink *GPU_uniformbuf_link_out(struct GPUMaterial *mat,
struct bNode *node,
struct GPUNodeStack *stack,
- const int index);
+ int index);
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link, int hash);
@@ -196,8 +197,8 @@ GPUMaterial *GPU_material_from_nodetree(struct Scene *scene,
struct bNodeTree *ntree,
struct ListBase *gpumaterials,
const void *engine_type,
- const int options,
- const bool is_volume_shader,
+ int options,
+ bool is_volume_shader,
const char *vert_code,
const char *geom_code,
const char *frag_lib,
@@ -256,7 +257,8 @@ typedef struct GPUMaterialAttribute {
typedef struct GPUMaterialTexture {
struct GPUMaterialTexture *next, *prev;
struct Image *ima;
- struct ImageUser *iuser;
+ struct ImageUser iuser;
+ bool iuser_available;
struct GPUTexture **colorband;
char sampler_name[32]; /* Name of sampler in GLSL. */
char tiled_mapping_name[32]; /* Name of tile mapping sampler in GLSL. */
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 5c373551494..972758febd4 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -30,6 +30,8 @@ extern "C" {
struct GPUIndexBuf;
struct GPUVertBuf;
+/** Opaque type hiding #blender::gpu::shader::ShaderCreateInfo */
+typedef struct GPUShaderCreateInfo GPUShaderCreateInfo;
/** Opaque type hiding #blender::gpu::Shader */
typedef struct GPUShader GPUShader;
@@ -62,10 +64,12 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
const char *computecode,
const char *libcode,
const char *defines,
- const eGPUShaderTFBType tf_type,
+ eGPUShaderTFBType tf_type,
const char **tf_names,
- const int tf_count,
+ int tf_count,
const char *shname);
+GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info);
+GPUShader *GPU_shader_create_from_info_name(const char *info_name);
struct GPU_ShaderCreateFromArray_Params {
const char **vert, **geom, **frag, **defs;
@@ -145,9 +149,14 @@ typedef enum {
} GPUUniformBuiltin;
typedef enum {
+ /** Deprecated */
GPU_UNIFORM_BLOCK_VIEW = 0, /* viewBlock */
GPU_UNIFORM_BLOCK_MODEL, /* modelBlock */
GPU_UNIFORM_BLOCK_INFO, /* infoBlock */
+ /** New ones */
+ GPU_UNIFORM_BLOCK_DRW_VIEW,
+ GPU_UNIFORM_BLOCK_DRW_MODEL,
+ GPU_UNIFORM_BLOCK_DRW_INFOS,
GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */
} GPUUniformBlockBuiltin;
@@ -294,14 +303,6 @@ typedef enum eGPUBuiltinShader {
GPU_SHADER_3D_IMAGE_MODULATE_ALPHA,
/* points */
/**
- * Draw round points with a hardcoded size.
- * Take a single color for all the vertices and a 2D position for each vertex.
- *
- * \param color: uniform vec4
- * \param pos: in vec2
- */
- GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR,
- /**
* Draw round points with a constant size.
* Take a single color for all the vertices and a 2D position for each vertex.
*
@@ -322,34 +323,6 @@ typedef enum eGPUBuiltinShader {
*/
GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
/**
- * Draw round points with a constant size and an outline.
- * Take a 2D position and a color for each vertex.
- *
- * \param size: uniform float
- * \param outlineWidth: uniform float
- * \param outlineColor: uniform vec4
- * \param color: in vec4
- * \param pos: in vec2
- */
- GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA,
- /**
- * Draw round points with a constant size and an outline.
- * Take a 2D position and a color for each vertex.
- *
- * \param size: in float
- * \param color: in vec4
- * \param pos: in vec2
- */
- GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR,
- /**
- * Draw round points with a hardcoded size.
- * Take a single color for all the vertices and a 3D position for each vertex.
- *
- * \param color: uniform vec4
- * \param pos: in vec3
- */
- GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR,
- /**
* Draw round points with a hardcoded size.
* Take a single color for all the vertices and a 3D position for each vertex.
*
@@ -368,26 +341,6 @@ typedef enum eGPUBuiltinShader {
GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
/**
* Draw round points with a constant size and an outline.
- * Take a single color for all the vertices and a 3D position for each vertex.
- *
- * \param size: uniform float
- * \param outlineWidth: uniform float
- * \param color: uniform vec4
- * \param outlineColor: uniform vec4
- * \param pos: in vec3
- */
- GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
- /**
- * Draw round points with a constant size and an outline.
- * Take a single color for all the vertices and a 3D position for each vertex.
- *
- * \param color: uniform vec4
- * \param size: in float
- * \param pos: in vec3
- */
- GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR,
- /**
- * Draw round points with a constant size and an outline.
* Take a 3D position and a color for each vertex.
*
* \param size: in float
@@ -403,23 +356,14 @@ typedef enum eGPUBuiltinShader {
/* grease pencil drawing */
GPU_SHADER_GPENCIL_STROKE,
/* specialized for widget drawing */
- GPU_SHADER_2D_AREA_EDGES,
+ GPU_SHADER_2D_AREA_BORDERS,
GPU_SHADER_2D_WIDGET_BASE,
GPU_SHADER_2D_WIDGET_BASE_INST,
GPU_SHADER_2D_WIDGET_SHADOW,
GPU_SHADER_2D_NODELINK,
GPU_SHADER_2D_NODELINK_INST,
- /* specialized for edituv drawing */
- GPU_SHADER_2D_UV_UNIFORM_COLOR,
- GPU_SHADER_2D_UV_VERTS,
- GPU_SHADER_2D_UV_FACEDOTS,
- GPU_SHADER_2D_UV_EDGES,
- GPU_SHADER_2D_UV_EDGES_SMOOTH,
- GPU_SHADER_2D_UV_FACES,
- GPU_SHADER_2D_UV_FACES_STRETCH_AREA,
- GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE,
} eGPUBuiltinShader;
-#define GPU_SHADER_BUILTIN_LEN (GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE + 1)
+#define GPU_SHADER_BUILTIN_LEN (GPU_SHADER_2D_NODELINK_INST + 1)
/** Support multiple configurations. */
typedef enum eGPUShaderConfig {
diff --git a/source/blender/gpu/GPU_shader_shared.h b/source/blender/gpu/GPU_shader_shared.h
new file mode 100644
index 00000000000..eeca7ee6caa
--- /dev/null
+++ b/source/blender/gpu/GPU_shader_shared.h
@@ -0,0 +1,84 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#ifndef USE_GPU_SHADER_CREATE_INFO
+# include "intern/gpu_shader_shared_utils.h"
+#endif
+
+struct NodeLinkData {
+ float4 colors[3];
+ /* bezierPts Is actually a float2, but due to std140 each element needs to be aligned to 16
+ * bytes. */
+ float4 bezierPts[4];
+ bool1 doArrow;
+ bool1 doMuted;
+ float dim_factor;
+ float thickness;
+ float dash_factor;
+ float dash_alpha;
+ float expandSize;
+ float arrowSize;
+};
+BLI_STATIC_ASSERT_ALIGN(struct NodeLinkData, 16)
+
+struct NodeLinkInstanceData {
+ float4 colors[6];
+ float expandSize;
+ float arrowSize;
+ float2 _pad;
+};
+BLI_STATIC_ASSERT_ALIGN(struct NodeLinkInstanceData, 16)
+
+struct GPencilStrokeData {
+ float2 viewport;
+ float pixsize;
+ float objscale;
+ float pixfactor;
+ int xraymode;
+ int caps_start;
+ int caps_end;
+ bool1 keep_size;
+ bool1 fill_stroke;
+ float2 _pad;
+};
+BLI_STATIC_ASSERT_ALIGN(struct GPencilStrokeData, 16)
+
+struct GPUClipPlanes {
+ float4x4 ModelMatrix;
+ float4 world[6];
+};
+BLI_STATIC_ASSERT_ALIGN(struct GPUClipPlanes, 16)
+
+struct SimpleLightingData {
+ float4 color;
+ float3 light;
+ float _pad;
+};
+BLI_STATIC_ASSERT_ALIGN(struct SimpleLightingData, 16)
+
+#define MAX_CALLS 16
+
+struct MultiRectCallData {
+ float4 calls_data[MAX_CALLS * 3];
+};
+BLI_STATIC_ASSERT_ALIGN(struct MultiRectCallData, 16)
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index fa70a8934db..22cd7eab927 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -40,9 +40,11 @@ typedef enum eGPUBarrier {
GPU_BARRIER_SHADER_IMAGE_ACCESS = (1 << 0),
GPU_BARRIER_TEXTURE_FETCH = (1 << 1),
GPU_BARRIER_SHADER_STORAGE = (1 << 2),
+ GPU_BARRIER_VERTEX_ATTRIB_ARRAY = (1 << 3),
+ GPU_BARRIER_ELEMENT_ARRAY = (1 << 4),
} eGPUBarrier;
-ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_SHADER_STORAGE)
+ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_ELEMENT_ARRAY)
/**
* Defines the fixed pipeline blending equation.
@@ -54,7 +56,7 @@ ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_SHADER_STORAGE)
*/
typedef enum eGPUBlend {
GPU_BLEND_NONE = 0,
- /** Premult variants will _NOT_ multiply rgb output by alpha. */
+ /** Pre-multiply variants will _NOT_ multiply rgb output by alpha. */
GPU_BLEND_ALPHA,
GPU_BLEND_ALPHA_PREMULT,
GPU_BLEND_ADDITIVE,
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 54e9bde70d8..d65115541fa 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -281,7 +281,7 @@ void GPU_texture_free(GPUTexture *tex);
void GPU_texture_ref(GPUTexture *tex);
void GPU_texture_bind(GPUTexture *tex, int unit);
-void GPU_texture_bind_ex(GPUTexture *tex, eGPUSamplerState state, int unit, const bool set_number);
+void GPU_texture_bind_ex(GPUTexture *tex, eGPUSamplerState state, int unit, bool set_number);
void GPU_texture_unbind(GPUTexture *tex);
void GPU_texture_unbind_all(void);
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index 62a495abfb3..43a8e7fc4cb 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -91,6 +91,8 @@ void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts);
void GPU_vertbuf_init_with_format_ex(GPUVertBuf *, const GPUVertFormat *, GPUUsageType);
+void GPU_vertbuf_init_build_on_device(GPUVertBuf *verts, GPUVertFormat *format, uint v_len);
+
#define GPU_vertbuf_init_with_format(verts, format) \
GPU_vertbuf_init_with_format_ex(verts, format, GPU_USAGE_STATIC)
@@ -172,6 +174,7 @@ const GPUVertFormat *GPU_vertbuf_get_format(const GPUVertBuf *verts);
uint GPU_vertbuf_get_vertex_alloc(const GPUVertBuf *verts);
uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts);
GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts);
+void GPU_vertbuf_tag_dirty(GPUVertBuf *verts);
/**
* Should be rename to #GPU_vertbuf_data_upload.
@@ -179,12 +182,14 @@ GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts);
void GPU_vertbuf_use(GPUVertBuf *);
void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding);
+void GPU_vertbuf_wrap_handle(GPUVertBuf *verts, uint64_t handle);
+
/**
* XXX: do not use!
* This is just a wrapper for the use of the Hair refine workaround.
* To be used with #GPU_vertbuf_use().
*/
-void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data);
+void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data);
/* Metrics */
uint GPU_vertbuf_get_memory_usage(void);
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index c4948d68298..917b87efeaa 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -40,10 +40,10 @@ extern "C" {
typedef struct GHash GHash;
typedef struct GPUViewport GPUViewport;
-struct GPUFrameBuffer;
+struct DRWData;
struct DefaultFramebufferList;
struct DefaultTextureList;
-struct DRWData;
+struct GPUFrameBuffer;
GPUViewport *GPU_viewport_create(void);
GPUViewport *GPU_viewport_stereo_create(void);
diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh
index 73792215569..00645f34173 100644
--- a/source/blender/gpu/intern/gpu_backend.hh
+++ b/source/blender/gpu/intern/gpu_backend.hh
@@ -42,24 +42,24 @@ class VertBuf;
class GPUBackend {
public:
- virtual ~GPUBackend(){};
+ virtual ~GPUBackend() = default;
- static GPUBackend *get(void);
+ static GPUBackend *get();
- virtual void samplers_update(void) = 0;
+ virtual void samplers_update() = 0;
virtual void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) = 0;
virtual Context *context_alloc(void *ghost_window) = 0;
- virtual Batch *batch_alloc(void) = 0;
+ virtual Batch *batch_alloc() = 0;
virtual DrawList *drawlist_alloc(int list_length) = 0;
virtual FrameBuffer *framebuffer_alloc(const char *name) = 0;
- virtual IndexBuf *indexbuf_alloc(void) = 0;
- virtual QueryPool *querypool_alloc(void) = 0;
+ virtual IndexBuf *indexbuf_alloc() = 0;
+ virtual QueryPool *querypool_alloc() = 0;
virtual Shader *shader_alloc(const char *name) = 0;
virtual Texture *texture_alloc(const char *name) = 0;
virtual UniformBuf *uniformbuf_alloc(int size, const char *name) = 0;
- virtual VertBuf *vertbuf_alloc(void) = 0;
+ virtual VertBuf *vertbuf_alloc() = 0;
};
} // namespace gpu
diff --git a/source/blender/gpu/intern/gpu_batch_private.hh b/source/blender/gpu/intern/gpu_batch_private.hh
index eed96864f20..4c2f221e9b6 100644
--- a/source/blender/gpu/intern/gpu_batch_private.hh
+++ b/source/blender/gpu/intern/gpu_batch_private.hh
@@ -47,7 +47,7 @@ class Batch : public GPUBatch {
virtual void draw(int v_first, int v_count, int i_first, int i_count) = 0;
/* Convenience casts. */
- IndexBuf *elem_(void) const
+ IndexBuf *elem_() const
{
return unwrap(elem);
}
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index bd24616820a..dd53bea4eca 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -210,6 +210,7 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt,
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const MVert *mvert,
+ const float (*vert_normals)[3],
const float *vmask,
const MLoopCol *vcol,
const int *sculpt_face_sets,
@@ -292,7 +293,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
if (buffers->smooth) {
- copy_v3_v3_short(no, v->no);
+ normal_float_to_short_v3(no, vert_normals[vtri[j]]);
}
copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no);
diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh
index 95cf7fd335d..1f94b6715f1 100644
--- a/source/blender/gpu/intern/gpu_capabilities_private.hh
+++ b/source/blender/gpu/intern/gpu_capabilities_private.hh
@@ -29,10 +29,10 @@ namespace blender::gpu {
/**
* This includes both hardware capabilities & workarounds.
- * Try to limit these to the implementation codebase (i.e.: gpu/opengl/).
+ * Try to limit these to the implementation code-base (i.e.: `gpu/opengl/`).
* Only add workarounds here if they are common to all implementation or
* if you need access to it outside of the GPU module.
- * Same goes for capabilities (i.e.: texture size)
+ * Same goes for capabilities (i.e.: texture size).
*/
struct GPUCapabilities {
int max_texture_size = 0;
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index f0046e879a0..568462ec2a6 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -65,7 +65,7 @@ extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
* same for 2 different Materials. Unused GPUPasses are free by Garbage collection.
*/
-/* Only use one linklist that contains the GPUPasses grouped by hash. */
+/* Only use one linked-list that contains the GPUPasses grouped by hash. */
static GPUPass *pass_cache = NULL;
static SpinLock pass_cache_spin;
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index 5af15d1bc3d..98714269402 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -186,6 +186,15 @@ void GPU_backend_exit()
g_backend = nullptr;
}
+eGPUBackendType GPU_backend_get_type()
+{
+ if (g_backend && dynamic_cast<GLBackend *>(g_backend) != nullptr) {
+ return GPU_BACKEND_OPENGL;
+ }
+
+ return GPU_BACKEND_NONE;
+}
+
GPUBackend *GPUBackend::get()
{
return g_backend;
diff --git a/source/blender/gpu/intern/gpu_context_private.hh b/source/blender/gpu/intern/gpu_context_private.hh
index 82753b44c51..d99555b3bf5 100644
--- a/source/blender/gpu/intern/gpu_context_private.hh
+++ b/source/blender/gpu/intern/gpu_context_private.hh
@@ -75,22 +75,22 @@ class Context {
Context();
virtual ~Context();
- static Context *get(void);
+ static Context *get();
- virtual void activate(void) = 0;
- virtual void deactivate(void) = 0;
+ virtual void activate() = 0;
+ virtual void deactivate() = 0;
/* Will push all pending commands to the GPU. */
- virtual void flush(void) = 0;
+ virtual void flush() = 0;
/* Will wait until the GPU has finished executing all command. */
- virtual void finish(void) = 0;
+ virtual void finish() = 0;
virtual void memory_statistics_get(int *total_mem, int *free_mem) = 0;
virtual void debug_group_begin(const char *, int){};
- virtual void debug_group_end(void){};
+ virtual void debug_group_end(){};
- bool is_active_on_thread(void);
+ bool is_active_on_thread();
};
/* Syntactic sugar. */
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index 3404eb67e28..5b1eac2e82f 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -563,7 +563,7 @@ static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs)
GPUOffScreen *GPU_offscreen_create(
int width, int height, bool depth, eGPUTextureFormat format, char err_out[256])
{
- GPUOffScreen *ofs = (GPUOffScreen *)MEM_callocN(sizeof(GPUOffScreen), __func__);
+ GPUOffScreen *ofs = MEM_cnew<GPUOffScreen>(__func__);
/* Sometimes areas can have 0 height or width and this will
* create a 1D texture which we don't want. */
diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh
index 2b00c239af4..a936e889e57 100644
--- a/source/blender/gpu/intern/gpu_framebuffer_private.hh
+++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh
@@ -188,24 +188,24 @@ class FrameBuffer {
copy_v4_v4_int(r_scissor, scissor_);
}
- inline bool scissor_test_get(void) const
+ inline bool scissor_test_get() const
{
return scissor_test_;
}
- inline void viewport_reset(void)
+ inline void viewport_reset()
{
int viewport_rect[4] = {0, 0, width_, height_};
viewport_set(viewport_rect);
}
- inline void scissor_reset(void)
+ inline void scissor_reset()
{
int scissor_rect[4] = {0, 0, width_, height_};
scissor_set(scissor_rect);
}
- inline GPUTexture *depth_tex(void) const
+ inline GPUTexture *depth_tex() const
{
if (attachments_[GPU_FB_DEPTH_ATTACHMENT].tex) {
return attachments_[GPU_FB_DEPTH_ATTACHMENT].tex;
diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc
index 7ca93252683..e28776c87b3 100644
--- a/source/blender/gpu/intern/gpu_immediate.cc
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -629,6 +629,12 @@ void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState s
GPU_texture_bind_ex(tex, state, binding, true);
}
+void immBindUniformBuf(const char *name, GPUUniformBuf *ubo)
+{
+ int binding = GPU_shader_get_uniform_block_binding(imm->shader, name);
+ GPU_uniformbuf_bind(ubo, binding);
+}
+
/* --- convenience functions for setting "uniform vec4 color" --- */
void immUniformColor4f(float r, float g, float b, float a)
diff --git a/source/blender/gpu/intern/gpu_immediate_private.hh b/source/blender/gpu/intern/gpu_immediate_private.hh
index 382f70eeec4..bc1ae403c52 100644
--- a/source/blender/gpu/intern/gpu_immediate_private.hh
+++ b/source/blender/gpu/intern/gpu_immediate_private.hh
@@ -68,11 +68,11 @@ class Immediate {
Immediate(){};
virtual ~Immediate(){};
- virtual uchar *begin(void) = 0;
- virtual void end(void) = 0;
+ virtual uchar *begin() = 0;
+ virtual void end() = 0;
};
} // namespace blender::gpu
-void immActivate(void);
-void immDeactivate(void);
+void immActivate();
+void immDeactivate();
diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc
index 3472cc24a74..895b2a8461b 100644
--- a/source/blender/gpu/intern/gpu_index_buffer.cc
+++ b/source/blender/gpu/intern/gpu_index_buffer.cc
@@ -74,11 +74,16 @@ void GPU_indexbuf_init(GPUIndexBufBuilder *builder,
GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len)
{
GPUIndexBuf *elem_ = GPU_indexbuf_calloc();
- IndexBuf *elem = unwrap(elem_);
- elem->init_build_on_device(index_len);
+ GPU_indexbuf_init_build_on_device(elem_, index_len);
return elem_;
}
+void GPU_indexbuf_init_build_on_device(GPUIndexBuf *elem, uint index_len)
+{
+ IndexBuf *elem_ = unwrap(elem);
+ elem_->init_build_on_device(index_len);
+}
+
void GPU_indexbuf_join(GPUIndexBufBuilder *builder_to, const GPUIndexBufBuilder *builder_from)
{
BLI_assert(builder_to->data == builder_from->data);
@@ -410,9 +415,19 @@ int GPU_indexbuf_primitive_len(GPUPrimType prim_type)
return indices_per_primitive(prim_type);
}
+void GPU_indexbuf_use(GPUIndexBuf *elem)
+{
+ unwrap(elem)->upload_data();
+}
+
void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding)
{
unwrap(elem)->bind_as_ssbo(binding);
}
+void GPU_indexbuf_update_sub(GPUIndexBuf *elem, uint start, uint len, const void *data)
+{
+ unwrap(elem)->update_sub(start, len, data);
+}
+
/** \} */
diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh
index ed7dd830c8c..4bb46689727 100644
--- a/source/blender/gpu/intern/gpu_index_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh
@@ -77,26 +77,30 @@ class IndexBuf {
void init_subrange(IndexBuf *elem_src, uint start, uint length);
void init_build_on_device(uint index_len);
- uint32_t index_len_get(void) const
+ uint32_t index_len_get() const
{
return index_len_;
}
/* Return size in byte of the drawable data buffer range. Actual buffer size might be bigger. */
- size_t size_get(void) const
+ size_t size_get() const
{
return index_len_ * to_bytesize(index_type_);
};
- bool is_init(void) const
+ bool is_init() const
{
return is_init_;
};
+ virtual void upload_data() = 0;
+
virtual void bind_as_ssbo(uint binding) = 0;
virtual const uint32_t *read() const = 0;
uint32_t *unmap(const uint32_t *mapped_memory) const;
+ virtual void update_sub(uint start, uint len, const void *data) = 0;
+
private:
inline void squeeze_indices_short(uint min_idx, uint max_idx);
inline uint index_range(uint *r_min, uint *r_max);
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index 0eb2fe57c28..5815fb10b0c 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -32,6 +32,8 @@
#include "intern/gpu_codegen.h"
#include "intern/gpu_material_library.h"
#include "intern/gpu_private.h"
+#include "intern/gpu_shader_create_info_private.hh"
+#include "intern/gpu_shader_dependency_private.h"
/**
* although the order of initialization and shutdown should not matter
@@ -49,6 +51,9 @@ void GPU_init(void)
initialized = true;
+ gpu_shader_dependency_init();
+ gpu_shader_create_info_init();
+
gpu_codegen_init();
gpu_material_library_init();
@@ -70,6 +75,9 @@ void GPU_exit(void)
gpu_material_library_exit();
gpu_codegen_exit();
+ gpu_shader_dependency_exit();
+ gpu_shader_create_info_exit();
+
initialized = false;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 3804f2f0dd1..11c61e4cf72 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -44,6 +44,8 @@
#include "BKE_node.h"
#include "BKE_scene.h"
+#include "NOD_shader.h"
+
#include "GPU_material.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
@@ -84,7 +86,7 @@ struct GPUMaterial {
bool has_volume_output;
bool has_surface_output;
- /* Only used by Eevee to know which bsdf are used. */
+ /* Only used by Eevee to know which BSDF are used. */
eGPUMatFlag flag;
/* Used by 2.8 pipeline */
@@ -604,7 +606,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
/* Caller must re-use materials. */
BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
- /* HACK: Eevee assume this to create Ghash keys. */
+ /* HACK: Eevee assume this to create #GHash keys. */
BLI_assert(sizeof(GPUPass) > 16);
/* allocate material */
diff --git a/source/blender/gpu/intern/gpu_material_library.c b/source/blender/gpu/intern/gpu_material_library.c
index 74e0270c42a..712ab44adb3 100644
--- a/source/blender/gpu/intern/gpu_material_library.c
+++ b/source/blender/gpu/intern/gpu_material_library.c
@@ -91,6 +91,7 @@ extern char datatoc_gpu_shader_material_output_aov_glsl[];
extern char datatoc_gpu_shader_material_output_material_glsl[];
extern char datatoc_gpu_shader_material_output_world_glsl[];
extern char datatoc_gpu_shader_material_particle_info_glsl[];
+extern char datatoc_gpu_shader_material_point_info_glsl[];
extern char datatoc_gpu_shader_material_principled_glsl[];
extern char datatoc_gpu_shader_material_refraction_glsl[];
extern char datatoc_gpu_shader_material_rgb_curves_glsl[];
@@ -295,7 +296,7 @@ static GPUMaterialLibrary gpu_shader_material_glass_library = {
static GPUMaterialLibrary gpu_shader_material_hair_info_library = {
.code = datatoc_gpu_shader_material_hair_info_glsl,
- .dependencies = {NULL},
+ .dependencies = {&gpu_shader_material_hash_library, NULL},
};
static GPUMaterialLibrary gpu_shader_material_holdout_library = {
@@ -388,6 +389,11 @@ static GPUMaterialLibrary gpu_shader_material_particle_info_library = {
.dependencies = {NULL},
};
+static GPUMaterialLibrary gpu_shader_material_point_info_library = {
+ .code = datatoc_gpu_shader_material_point_info_glsl,
+ .dependencies = {&gpu_shader_material_hash_library, NULL},
+};
+
static GPUMaterialLibrary gpu_shader_material_principled_library = {
.code = datatoc_gpu_shader_material_principled_glsl,
.dependencies = {NULL},
@@ -644,6 +650,7 @@ static GPUMaterialLibrary *gpu_material_libraries[] = {
&gpu_shader_material_output_material_library,
&gpu_shader_material_output_world_library,
&gpu_shader_material_particle_info_library,
+ &gpu_shader_material_point_info_library,
&gpu_shader_material_principled_library,
&gpu_shader_material_refraction_library,
&gpu_shader_material_rgb_curves_library,
diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h
index d3b12d3a2b7..7f9eeb8166a 100644
--- a/source/blender/gpu/intern/gpu_material_library.h
+++ b/source/blender/gpu/intern/gpu_material_library.h
@@ -63,4 +63,4 @@ char *gpu_material_library_generate_code(struct GSet *used_libraries, const char
/* Code Parsing */
const char *gpu_str_skip_token(const char *str, char *token, int max);
-const char *gpu_data_type_to_string(const eGPUType type);
+const char *gpu_data_type_to_string(eGPUType type);
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 50ff450ac79..e0d60aa5fda 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -439,7 +439,10 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
if (tex == NULL) {
tex = MEM_callocN(sizeof(*tex), __func__);
tex->ima = ima;
- tex->iuser = iuser;
+ if (iuser != NULL) {
+ tex->iuser = *iuser;
+ tex->iuser_available = true;
+ }
tex->colorband = colorband;
tex->sampler_state = sampler_state;
BLI_snprintf(tex->sampler_name, sizeof(tex->sampler_name), "samp%d", num_textures);
diff --git a/source/blender/gpu/intern/gpu_platform_private.hh b/source/blender/gpu/intern/gpu_platform_private.hh
index f823269ab54..faae7c48588 100644
--- a/source/blender/gpu/intern/gpu_platform_private.hh
+++ b/source/blender/gpu/intern/gpu_platform_private.hh
@@ -49,7 +49,7 @@ class GPUPlatformGlobal {
const char *renderer_str,
const char *version_str);
- void clear(void);
+ void clear();
};
extern GPUPlatformGlobal GPG;
diff --git a/source/blender/gpu/intern/gpu_query.hh b/source/blender/gpu/intern/gpu_query.hh
index 0356e145b00..a004c355c8f 100644
--- a/source/blender/gpu/intern/gpu_query.hh
+++ b/source/blender/gpu/intern/gpu_query.hh
@@ -45,8 +45,8 @@ class QueryPool {
* Will start and end the query at this index inside the pool.
* The pool will resize automatically.
*/
- virtual void begin_query(void) = 0;
- virtual void end_query(void) = 0;
+ virtual void begin_query() = 0;
+ virtual void end_query() = 0;
/**
* Must be fed with a buffer large enough to contain all the queries issued.
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index aadb52fb49c..958aab65b57 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -61,6 +61,15 @@ typedef struct GPUSelectState {
char algorithm;
/* allow GPU_select_begin/end without drawing */
bool use_cache;
+ /**
+ * Signifies that #GPU_select_cache_begin has been called,
+ * future calls to #GPU_select_begin should initialize the cache.
+ *
+ * \note #GPU_select_cache_begin could perform initialization but doesn't as it's inconvenient
+ * for callers making the cache begin/end calls outside lower level selection logic
+ * where the `mode` to pass to #GPU_select_begin yet isn't known.
+ */
+ bool use_cache_needs_init;
} GPUSelectState;
static GPUSelectState g_select_state = {0};
@@ -90,9 +99,26 @@ void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode,
g_select_state.algorithm = ALGO_GL_QUERY;
}
+ /* This function is called when cache has already been initialized,
+ * so only manipulate cache values when cache is pending. */
+ if (g_select_state.use_cache_needs_init) {
+ g_select_state.use_cache_needs_init = false;
+
+ switch (g_select_state.algorithm) {
+ case ALGO_GL_QUERY: {
+ g_select_state.use_cache = false;
+ break;
+ }
+ default: {
+ g_select_state.use_cache = true;
+ gpu_select_pick_cache_begin();
+ break;
+ }
+ }
+ }
+
switch (g_select_state.algorithm) {
case ALGO_GL_QUERY: {
- g_select_state.use_cache = false;
gpu_select_query_begin((uint(*)[4])buffer, bufsize / 4, input, mode, oldhits);
break;
}
@@ -154,12 +180,13 @@ uint GPU_select_end(void)
void GPU_select_cache_begin(void)
{
- /* validate on GPU_select_begin, clear if not supported */
- BLI_assert(g_select_state.use_cache == false);
- g_select_state.use_cache = true;
- if (g_select_state.algorithm == ALGO_GL_PICK) {
- gpu_select_pick_cache_begin();
- }
+ BLI_assert(g_select_state.select_is_active == false);
+ /* Ensure #GPU_select_cache_end is always called. */
+ BLI_assert(g_select_state.use_cache_needs_init == false);
+
+ /* Signal that cache should be used, instead of calling the algorithms cache-begin function.
+ * This is more convenient as the exact method of selection may not be known by the caller. */
+ g_select_state.use_cache_needs_init = true;
}
void GPU_select_cache_load_id(void)
@@ -173,9 +200,12 @@ void GPU_select_cache_load_id(void)
void GPU_select_cache_end(void)
{
if (g_select_state.algorithm == ALGO_GL_PICK) {
+ BLI_assert(g_select_state.use_cache == true);
gpu_select_pick_cache_end();
}
g_select_state.use_cache = false;
+ /* Paranoid assignment, should already be false. */
+ g_select_state.use_cache_needs_init = false;
}
bool GPU_select_is_cached(void)
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index 737e4c6e874..ddd3dfc6879 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -673,7 +673,7 @@ uint gpu_select_pick_end(void)
#endif
/* first 3 are dummy values */
g_pick_state.buffer[hits][0] = 1;
- g_pick_state.buffer[hits][1] = 0x0; /* depth_data[i].depth; */ /* unused */
+ g_pick_state.buffer[hits][1] = depth_data[i].depth;
g_pick_state.buffer[hits][2] = 0x0; /* z-far is currently never used. */
g_pick_state.buffer[hits][3] = depth_data[i].id;
hits++;
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index 1b6cb196534..ef800abc3c9 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -31,10 +31,32 @@
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
+#include "gpu_shader_create_info.hh"
+#include "gpu_shader_create_info_private.hh"
+#include "gpu_shader_dependency_private.h"
#include "gpu_shader_private.hh"
+#include <string>
+
extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[];
+namespace blender::gpu {
+
+std::string Shader::defines_declare(const shader::ShaderCreateInfo &info) const
+{
+ std::string defines;
+ for (const auto &def : info.defines_) {
+ defines += "#define ";
+ defines += def[0];
+ defines += " ";
+ defines += def[1];
+ defines += "\n";
+ }
+ return defines;
+}
+
+} // namespace blender::gpu
+
using namespace blender;
using namespace blender::gpu;
@@ -59,6 +81,8 @@ static void standard_defines(Vector<const char *> &sources)
BLI_assert(sources.size() == 0);
/* Version needs to be first. Exact values will be added by implementation. */
sources.append("version");
+ /* Define to identify code usage in shading language. */
+ sources.append("#define GPU_SHADER\n");
/* some useful defines to detect GPU type */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
sources.append("#define GPU_ATI\n");
@@ -225,6 +249,188 @@ GPUShader *GPU_shader_create_compute(const char *computecode,
shname);
}
+GPUShader *GPU_shader_create_from_info_name(const char *info_name)
+{
+ using namespace blender::gpu::shader;
+ const GPUShaderCreateInfo *_info = gpu_shader_create_info_get(info_name);
+ const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info);
+ if (!info.do_static_compilation_) {
+ printf("Warning: Trying to compile \"%s\" which was not marked for static compilation.\n",
+ info.name_.c_str());
+ }
+ return GPU_shader_create_from_info(_info);
+}
+
+GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
+{
+ using namespace blender::gpu::shader;
+ const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info);
+
+ const_cast<ShaderCreateInfo &>(info).finalize();
+
+ /* At least a vertex shader and a fragment shader are required, or only a compute shader. */
+ if (info.compute_source_.is_empty()) {
+ if (info.vertex_source_.is_empty()) {
+ printf("Missing vertex shader in %s.\n", info.name_.c_str());
+ }
+ if (info.fragment_source_.is_empty()) {
+ printf("Missing fragment shader in %s.\n", info.name_.c_str());
+ }
+ BLI_assert(!info.vertex_source_.is_empty() && !info.fragment_source_.is_empty());
+ }
+ else {
+ if (!info.vertex_source_.is_empty()) {
+ printf("Compute shader has vertex_source_ shader attached in %s.\n", info.name_.c_str());
+ }
+ if (!info.geometry_source_.is_empty()) {
+ printf("Compute shader has geometry_source_ shader attached in %s.\n", info.name_.c_str());
+ }
+ if (!info.fragment_source_.is_empty()) {
+ printf("Compute shader has fragment_source_ shader attached in %s.\n", info.name_.c_str());
+ }
+ BLI_assert(info.vertex_source_.is_empty() && info.geometry_source_.is_empty() &&
+ info.fragment_source_.is_empty());
+ }
+
+ Shader *shader = GPUBackend::get()->shader_alloc(info.name_.c_str());
+
+ std::string defines = shader->defines_declare(info);
+ std::string resources = shader->resources_declare(info);
+ char *shader_shared_utils = nullptr;
+
+ defines += "#define USE_GPU_SHADER_CREATE_INFO\n";
+
+ Vector<char *> typedefs;
+ for (auto filename : info.typedef_sources_) {
+ typedefs.append(gpu_shader_dependency_get_source(filename.c_str()));
+ }
+ if (!typedefs.is_empty()) {
+ shader_shared_utils = gpu_shader_dependency_get_source("gpu_shader_shared_utils.h");
+ }
+
+ if (!info.vertex_source_.is_empty()) {
+ uint32_t builtins = 0;
+ std::string interface = shader->vertex_interface_declare(info);
+ char *code = gpu_shader_dependency_get_resolved_source(info.vertex_source_.c_str(), &builtins);
+
+ Vector<const char *> sources;
+ standard_defines(sources);
+ sources.append("#define GPU_VERTEX_SHADER\n");
+ if (!info.geometry_source_.is_empty()) {
+ sources.append("#define USE_GEOMETRY_SHADER\n");
+ }
+ sources.append(defines.c_str());
+ if (!typedefs.is_empty()) {
+ sources.append(shader_shared_utils);
+ }
+ for (auto *types : typedefs) {
+ sources.append(types);
+ }
+ sources.append(resources.c_str());
+ sources.append(interface.c_str());
+ sources.append(code);
+
+ shader->vertex_shader_from_glsl(sources);
+
+ free(code);
+ }
+
+ if (!info.fragment_source_.is_empty()) {
+ uint32_t builtins = 0;
+ std::string interface = shader->fragment_interface_declare(info);
+ char *code = gpu_shader_dependency_get_resolved_source(info.fragment_source_.c_str(),
+ &builtins);
+
+ Vector<const char *> sources;
+ standard_defines(sources);
+ sources.append("#define GPU_FRAGMENT_SHADER\n");
+ if (!info.geometry_source_.is_empty()) {
+ sources.append("#define USE_GEOMETRY_SHADER\n");
+ }
+ sources.append(defines.c_str());
+ if (!typedefs.is_empty()) {
+ sources.append(shader_shared_utils);
+ }
+ for (auto *types : typedefs) {
+ sources.append(types);
+ }
+ sources.append(resources.c_str());
+ sources.append(interface.c_str());
+ sources.append(code);
+
+ shader->fragment_shader_from_glsl(sources);
+
+ free(code);
+ }
+
+ if (!info.geometry_source_.is_empty()) {
+ uint32_t builtins = 0;
+ std::string interface = shader->geometry_interface_declare(info);
+ std::string layout = shader->geometry_layout_declare(info);
+ char *code = gpu_shader_dependency_get_resolved_source(info.geometry_source_.c_str(),
+ &builtins);
+
+ Vector<const char *> sources;
+ standard_defines(sources);
+ sources.append("#define GPU_GEOMETRY_SHADER\n");
+ sources.append(defines.c_str());
+ if (!typedefs.is_empty()) {
+ sources.append(shader_shared_utils);
+ }
+ for (auto *types : typedefs) {
+ sources.append(types);
+ }
+ sources.append(resources.c_str());
+ sources.append(layout.c_str());
+ sources.append(interface.c_str());
+ sources.append(code);
+
+ shader->geometry_shader_from_glsl(sources);
+
+ free(code);
+ }
+
+ if (!info.compute_source_.is_empty()) {
+ uint32_t builtins = 0;
+ char *code = gpu_shader_dependency_get_resolved_source(info.compute_source_.c_str(),
+ &builtins);
+ std::string layout = shader->compute_layout_declare(info);
+
+ Vector<const char *> sources;
+ standard_defines(sources);
+ sources.append("#define GPU_COMPUTE_SHADER\n");
+ sources.append(defines.c_str());
+ if (!typedefs.is_empty()) {
+ sources.append(shader_shared_utils);
+ }
+ for (auto *types : typedefs) {
+ sources.append(types);
+ }
+ sources.append(resources.c_str());
+ sources.append(layout.c_str());
+ sources.append(code);
+
+ shader->compute_shader_from_glsl(sources);
+
+ free(code);
+ }
+
+ for (auto *types : typedefs) {
+ free(types);
+ }
+
+ if (shader_shared_utils) {
+ free(shader_shared_utils);
+ }
+
+ if (!shader->finalize(&info)) {
+ delete shader;
+ return nullptr;
+ }
+
+ return wrap(shader);
+}
+
GPUShader *GPU_shader_create_from_python(const char *vertcode,
const char *fragcode,
const char *geomcode,
@@ -339,7 +545,7 @@ void GPU_shader_bind(GPUShader *gpu_shader)
}
}
-void GPU_shader_unbind(void)
+void GPU_shader_unbind()
{
#ifndef NDEBUG
Context *ctx = Context::get();
diff --git a/source/blender/gpu/intern/gpu_shader_builder.cc b/source/blender/gpu/intern/gpu_shader_builder.cc
new file mode 100644
index 00000000000..334bdb2ec58
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_builder.cc
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Compile time automation of shader compilation and validation.
+ */
+
+#include <iostream>
+
+#include "GHOST_C-api.h"
+
+#include "GPU_context.h"
+#include "GPU_init_exit.h"
+#include "gpu_shader_create_info_private.hh"
+
+#include "CLG_log.h"
+
+namespace blender::gpu::shader_builder {
+
+class ShaderBuilder {
+ private:
+ GHOST_SystemHandle ghost_system_;
+ GHOST_ContextHandle ghost_context_;
+ GPUContext *gpu_context_ = nullptr;
+
+ public:
+ void init();
+ bool bake_create_infos();
+ void exit();
+};
+
+bool ShaderBuilder::bake_create_infos()
+{
+ return gpu_shader_create_info_compile_all();
+}
+
+void ShaderBuilder::init()
+{
+ CLG_init();
+
+ GHOST_GLSettings glSettings = {0};
+ ghost_system_ = GHOST_CreateSystem();
+ ghost_context_ = GHOST_CreateOpenGLContext(ghost_system_, glSettings);
+ GHOST_ActivateOpenGLContext(ghost_context_);
+
+ gpu_context_ = GPU_context_create(nullptr);
+ GPU_init();
+}
+
+void ShaderBuilder::exit()
+{
+ GPU_backend_exit();
+ GPU_exit();
+
+ GPU_context_discard(gpu_context_);
+
+ GHOST_DisposeOpenGLContext(ghost_system_, ghost_context_);
+ GHOST_DisposeSystem(ghost_system_);
+
+ CLG_exit();
+}
+
+} // namespace blender::gpu::shader_builder
+
+/** \brief Entry point for the shader_builder. */
+int main(int argc, const char *argv[])
+{
+ if (argc < 2) {
+ printf("Usage: %s <data_file_to>\n", argv[0]);
+ exit(1);
+ }
+
+ int exit_code = 0;
+
+ blender::gpu::shader_builder::ShaderBuilder builder;
+ builder.init();
+ if (!builder.bake_create_infos()) {
+ exit_code = 1;
+ }
+ builder.exit();
+ exit(exit_code);
+
+ return exit_code;
+}
diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
new file mode 100644
index 00000000000..40e54ab4394
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Stubs to reduce linking time for shader_builder.
+ */
+
+#include "BLI_utildefines.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_subdiv_ccg.h"
+
+#include "DNA_userdef_types.h"
+
+#include "DRW_engine.h"
+
+#include "bmesh.h"
+
+#include "UI_resources.h"
+
+extern "C" {
+
+Global G;
+UserDef U;
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BLI_imbuf_types.h
+ * \{ */
+
+void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
+{
+ BLI_assert_unreachable();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of UI_resources.h
+ * \{ */
+
+void UI_GetThemeColor4fv(int UNUSED(colorid), float UNUSED(col[4]))
+{
+ BLI_assert_unreachable();
+}
+
+void UI_GetThemeColor3fv(int UNUSED(colorid), float UNUSED(col[3]))
+{
+ BLI_assert_unreachable();
+}
+
+void UI_GetThemeColorShade4fv(int UNUSED(colorid), int UNUSED(offset), float UNUSED(col[4]))
+{
+ BLI_assert_unreachable();
+}
+
+void UI_GetThemeColorShadeAlpha4fv(int UNUSED(colorid),
+ int UNUSED(coloffset),
+ int UNUSED(alphaoffset),
+ float UNUSED(col[4]))
+{
+ BLI_assert_unreachable();
+}
+void UI_GetThemeColorBlendShade4fv(int UNUSED(colorid1),
+ int UNUSED(colorid2),
+ float UNUSED(fac),
+ int UNUSED(offset),
+ float UNUSED(col[4]))
+{
+ BLI_assert_unreachable();
+}
+
+void UI_GetThemeColorBlend3ubv(int UNUSED(colorid1),
+ int UNUSED(colorid2),
+ float UNUSED(fac),
+ unsigned char UNUSED(col[3]))
+{
+ BLI_assert_unreachable();
+}
+
+void UI_GetThemeColorShadeAlpha4ubv(int UNUSED(colorid),
+ int UNUSED(coloffset),
+ int UNUSED(alphaoffset),
+ unsigned char UNUSED(col[4]))
+{
+ BLI_assert_unreachable();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_paint.h
+ * \{ */
+bool paint_is_face_hidden(const struct MLoopTri *UNUSED(lt),
+ const struct MVert *UNUSED(mvert),
+ const struct MLoop *UNUSED(mloop))
+{
+ BLI_assert_unreachable();
+ return false;
+}
+
+void BKE_paint_face_set_overlay_color_get(const int UNUSED(face_set),
+ const int UNUSED(seed),
+ uchar UNUSED(r_color[4]))
+{
+ BLI_assert_unreachable();
+}
+
+bool paint_is_grid_face_hidden(const unsigned int *UNUSED(grid_hidden),
+ int UNUSED(gridsize),
+ int UNUSED(x),
+ int UNUSED(y))
+{
+ BLI_assert_unreachable();
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_mesh.h
+ * \{ */
+void BKE_mesh_calc_poly_normal(const struct MPoly *UNUSED(mpoly),
+ const struct MLoop *UNUSED(loopstart),
+ const struct MVert *UNUSED(mvarray),
+ float UNUSED(r_no[3]))
+{
+ BLI_assert_unreachable();
+}
+
+void BKE_mesh_looptri_get_real_edges(const struct Mesh *UNUSED(mesh),
+ const struct MLoopTri *UNUSED(looptri),
+ int UNUSED(r_edges[3]))
+{
+ BLI_assert_unreachable();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_material.h
+ * \{ */
+
+void BKE_material_defaults_free_gpu(void)
+{
+ /* This function is reachable via GPU_exit. */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_customdata.h
+ * \{ */
+
+int CustomData_get_offset(const struct CustomData *UNUSED(data), int UNUSED(type))
+{
+ BLI_assert_unreachable();
+ return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_pbvh.h
+ * \{ */
+
+int BKE_pbvh_count_grid_quads(BLI_bitmap **UNUSED(grid_hidden),
+ const int *UNUSED(grid_indices),
+ int UNUSED(totgrid),
+ int UNUSED(gridsize))
+{
+ BLI_assert_unreachable();
+ return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_subdiv_ccg.h
+ * \{ */
+int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *UNUSED(subdiv_ccg),
+ const int UNUSED(grid_index))
+{
+ BLI_assert_unreachable();
+ return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_node.h
+ * \{ */
+void ntreeGPUMaterialNodes(struct bNodeTree *UNUSED(localtree),
+ struct GPUMaterial *UNUSED(mat),
+ bool *UNUSED(has_surface_output),
+ bool *UNUSED(has_volume_output))
+{
+ BLI_assert_unreachable();
+}
+
+struct bNodeTree *ntreeLocalize(struct bNodeTree *UNUSED(ntree))
+{
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+void ntreeFreeLocalTree(struct bNodeTree *UNUSED(ntree))
+{
+ BLI_assert_unreachable();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of bmesh.h
+ * \{ */
+void BM_face_as_array_vert_tri(BMFace *UNUSED(f), BMVert *UNUSED(r_verts[3]))
+{
+ BLI_assert_unreachable();
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stubs of DRW_engine.h
+ * \{ */
+void DRW_deferred_shader_remove(struct GPUMaterial *UNUSED(mat))
+{
+ BLI_assert_unreachable();
+}
+
+/** \} */
+}
diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index bea43bacb23..6b1163fdc78 100644
--- a/source/blender/gpu/intern/gpu_shader_builtin.c
+++ b/source/blender/gpu/intern/gpu_shader_builtin.c
@@ -93,28 +93,15 @@ extern char datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl[];
extern char datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl[];
-extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[];
extern char datatoc_gpu_shader_point_uniform_color_aa_frag_glsl[];
extern char datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl[];
-extern char datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl[];
extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[];
extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
extern char datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl[];
-extern char datatoc_gpu_shader_3D_point_varying_size_vert_glsl[];
extern char datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl[];
extern char datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl[];
-extern char datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl[];
-extern char datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl[];
extern char datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl[];
extern char datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl[];
-extern char datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl[];
-
-extern char datatoc_gpu_shader_2D_edituvs_points_vert_glsl[];
-extern char datatoc_gpu_shader_2D_edituvs_facedots_vert_glsl[];
-extern char datatoc_gpu_shader_2D_edituvs_edges_vert_glsl[];
-extern char datatoc_gpu_shader_2D_edituvs_edges_frag_glsl[];
-extern char datatoc_gpu_shader_2D_edituvs_faces_vert_glsl[];
-extern char datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl[];
extern char datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl[];
extern char datatoc_gpu_shader_2D_line_dashed_frag_glsl[];
@@ -158,137 +145,97 @@ typedef struct {
const char *frag;
/** Optional. */
const char *defs;
+
+ const char *create_info;
+ const char *clipped_create_info;
} GPUShaderStages;
static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
[GPU_SHADER_TEXT] =
{
.name = "GPU_SHADER_TEXT",
- .vert = datatoc_gpu_shader_text_vert_glsl,
- .frag = datatoc_gpu_shader_text_frag_glsl,
+ .create_info = "gpu_shader_text",
},
[GPU_SHADER_KEYFRAME_SHAPE] =
{
.name = "GPU_SHADER_KEYFRAME_SHAPE",
- .vert = datatoc_gpu_shader_keyframe_shape_vert_glsl,
- .frag = datatoc_gpu_shader_keyframe_shape_frag_glsl,
+ .create_info = "gpu_shader_keyframe_shape",
},
[GPU_SHADER_SIMPLE_LIGHTING] =
{
.name = "GPU_SHADER_SIMPLE_LIGHTING",
- .vert = datatoc_gpu_shader_3D_normal_vert_glsl,
- .frag = datatoc_gpu_shader_simple_lighting_frag_glsl,
+ .create_info = "gpu_shader_simple_lighting",
},
[GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] =
{
- .vert = datatoc_gpu_shader_3D_image_vert_glsl,
- .frag = datatoc_gpu_shader_image_modulate_alpha_frag_glsl,
+ .name = "GPU_SHADER_3D_IMAGE_MODULATE_ALPHA",
+ .create_info = "gpu_shader_3D_image_modulate_alpha",
},
[GPU_SHADER_2D_CHECKER] =
{
.name = "GPU_SHADER_2D_CHECKER",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_checker_frag_glsl,
+ .create_info = "gpu_shader_2D_checker",
},
[GPU_SHADER_2D_DIAG_STRIPES] =
{
.name = "GPU_SHADER_2D_DIAG_STRIPES",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_diag_stripes_frag_glsl,
+ .create_info = "gpu_shader_2D_diag_stripes",
},
- [GPU_SHADER_2D_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_2D_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_uniform_color_frag_glsl,
- },
- [GPU_SHADER_2D_FLAT_COLOR] =
- {
- .name = "GPU_SHADER_2D_FLAT_COLOR",
- .vert = datatoc_gpu_shader_2D_flat_color_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
- [GPU_SHADER_2D_SMOOTH_COLOR] =
- {
- .name = "GPU_SHADER_2D_SMOOTH_COLOR",
- .vert = datatoc_gpu_shader_2D_smooth_color_vert_glsl,
- .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl,
- },
+ [GPU_SHADER_2D_UNIFORM_COLOR] = {.name = "GPU_SHADER_2D_UNIFORM_COLOR",
+ .create_info = "gpu_shader_2D_uniform_color"},
+ [GPU_SHADER_2D_FLAT_COLOR] = {.name = "GPU_SHADER_2D_FLAT_COLOR",
+ .create_info = "gpu_shader_2D_flat_color"},
+ [GPU_SHADER_2D_SMOOTH_COLOR] = {.name = "GPU_SHADER_2D_SMOOTH_COLOR",
+ .create_info = "gpu_shader_2D_smooth_color"},
[GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE] =
{
.name = "GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE",
+#ifdef __APPLE__
+ /* GPUShaderCreateInfo is disabled on MacOS due to mismatch with OCIO shader. See
+ * T95052 for more details. */
.vert = datatoc_gpu_shader_2D_image_vert_glsl,
.frag = datatoc_gpu_shader_image_overlays_merge_frag_glsl,
+#else
+ .create_info = "gpu_shader_2D_image_overlays_merge",
+#endif
},
[GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE] =
- {
- .name = "GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_image_overlays_stereo_merge_frag_glsl,
- },
- [GPU_SHADER_2D_IMAGE] =
- {
- .name = "GPU_SHADER_2D_IMAGE",
- .vert = datatoc_gpu_shader_2D_image_vert_glsl,
- .frag = datatoc_gpu_shader_image_frag_glsl,
- },
- [GPU_SHADER_2D_IMAGE_COLOR] =
- {
- .name = "GPU_SHADER_2D_IMAGE_COLOR",
- .vert = datatoc_gpu_shader_2D_image_vert_glsl,
- .frag = datatoc_gpu_shader_image_color_frag_glsl,
- },
- [GPU_SHADER_2D_IMAGE_DESATURATE_COLOR] =
- {
- .name = "GPU_SHADER_2D_IMAGE_DESATURATE_COLOR",
- .vert = datatoc_gpu_shader_2D_image_vert_glsl,
- .frag = datatoc_gpu_shader_image_desaturate_frag_glsl,
- },
+ {.name = "GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE",
+ .create_info = "gpu_shader_2D_image_overlays_stereo_merge"},
+ [GPU_SHADER_2D_IMAGE] = {.name = "GPU_SHADER_2D_IMAGE", .create_info = "gpu_shader_2D_image"},
+ [GPU_SHADER_2D_IMAGE_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_COLOR",
+ .create_info = "gpu_shader_2D_image_color"},
+ [GPU_SHADER_2D_IMAGE_DESATURATE_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_DESATURATE_COLOR",
+ .create_info =
+ "gpu_shader_2D_image_desaturate_color"},
[GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR] =
{
.name = "GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR",
- .vert = datatoc_gpu_shader_2D_image_vert_glsl,
- .frag = datatoc_gpu_shader_image_shuffle_color_frag_glsl,
- },
- [GPU_SHADER_2D_IMAGE_RECT_COLOR] =
- {
- .name = "GPU_SHADER_2D_IMAGE_RECT_COLOR",
- .vert = datatoc_gpu_shader_2D_image_rect_vert_glsl,
- .frag = datatoc_gpu_shader_image_color_frag_glsl,
- },
- [GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR] =
- {
- .name = "GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR",
- .vert = datatoc_gpu_shader_2D_image_multi_rect_vert_glsl,
- .frag = datatoc_gpu_shader_image_varying_color_frag_glsl,
+ .create_info = "gpu_shader_2D_image_shuffle_color",
},
+ [GPU_SHADER_2D_IMAGE_RECT_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_RECT_COLOR",
+ .create_info = "gpu_shader_2D_image_rect_color"},
+ [GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR",
+ .create_info =
+ "gpu_shader_2D_image_multi_rect_color"},
[GPU_SHADER_3D_UNIFORM_COLOR] =
{
.name = "GPU_SHADER_3D_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_3D_vert_glsl,
- .frag = datatoc_gpu_shader_uniform_color_frag_glsl,
- },
- [GPU_SHADER_3D_FLAT_COLOR] =
- {
- .name = "GPU_SHADER_3D_FLAT_COLOR",
- .vert = datatoc_gpu_shader_3D_flat_color_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
- [GPU_SHADER_3D_SMOOTH_COLOR] =
- {
- .name = "GPU_SHADER_3D_SMOOTH_COLOR",
- .vert = datatoc_gpu_shader_3D_smooth_color_vert_glsl,
- .frag = datatoc_gpu_shader_3D_smooth_color_frag_glsl,
- },
- [GPU_SHADER_3D_DEPTH_ONLY] =
- {
- .name = "GPU_SHADER_3D_DEPTH_ONLY",
- .vert = datatoc_gpu_shader_3D_vert_glsl,
- .frag = datatoc_gpu_shader_depth_only_frag_glsl,
- },
+ .create_info = "gpu_shader_3D_uniform_color",
+ .clipped_create_info = "gpu_shader_3D_uniform_color_clipped",
+ },
+ [GPU_SHADER_3D_FLAT_COLOR] = {.name = "GPU_SHADER_3D_FLAT_COLOR",
+ .create_info = "gpu_shader_3D_flat_color",
+ .clipped_create_info = "gpu_shader_3D_flat_color_clipped"},
+ [GPU_SHADER_3D_SMOOTH_COLOR] = {.name = "GPU_SHADER_3D_SMOOTH_COLOR",
+ .create_info = "gpu_shader_3D_smooth_color",
+ .clipped_create_info = "gpu_shader_3D_smooth_color_clipped"},
+ [GPU_SHADER_3D_DEPTH_ONLY] = {.name = "GPU_SHADER_3D_DEPTH_ONLY",
+ .create_info = "gpu_shader_3D_depth_only",
+ .clipped_create_info = "gpu_shader_3D_depth_only_clipped"},
[GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR] =
{
.name = "GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR",
@@ -343,72 +290,26 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.frag = datatoc_gpu_shader_2D_line_dashed_frag_glsl,
},
- [GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_frag_glsl,
- },
- [GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR] =
- {
- .name = "GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR",
- .vert = datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_frag_glsl,
- },
[GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] =
{
.name = "GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA",
- .vert = datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_aa_frag_glsl,
+ .create_info = "gpu_shader_2D_point_uniform_size_uniform_color_aa",
},
[GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] =
{
.name = "GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA",
- .vert = datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl,
- },
- [GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA] =
- {
- .name = "GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA",
- .vert = datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl,
- },
- [GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_3D_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_frag_glsl,
+ .create_info = "gpu_shader_2D_point_uniform_size_uniform_color_outline_aa",
},
[GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR] =
- {
- .name = "GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR",
- .vert = datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_frag_glsl,
- },
- [GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_3D_point_varying_size_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_frag_glsl,
- },
+ {.name = "GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR",
+ .create_info = "gpu_shader_3D_point_fixed_size_varying_color"},
[GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR] =
- {
- .name = "GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR",
- .vert = datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_frag_glsl,
- },
+ {.name = "GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR",
+ .create_info = "gpu_shader_3D_point_varying_size_varying_color"},
[GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] =
- {
- .name = "GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA",
- .vert = datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_aa_frag_glsl,
- },
- [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] =
- {
- .name = "GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA",
- .vert = datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl,
- .frag = datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl,
- },
+ {.name = "GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA",
+ .create_info = "gpu_shader_3D_point_uniform_size_uniform_color_aa",
+ .clipped_create_info = "gpu_shader_3D_point_uniform_size_uniform_color_aa_clipped"},
[GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE] =
{
@@ -418,12 +319,8 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.defs = "#define UNIFORM_SCALE\n",
},
- [GPU_SHADER_2D_AREA_EDGES] =
- {
- .name = "GPU_SHADER_2D_AREA_EDGES",
- .vert = datatoc_gpu_shader_2D_area_borders_vert_glsl,
- .frag = datatoc_gpu_shader_2D_area_borders_frag_glsl,
- },
+ [GPU_SHADER_2D_AREA_BORDERS] = {.name = "GPU_SHADER_2D_AREA_BORDERS",
+ .create_info = "gpu_shader_2D_area_borders"},
[GPU_SHADER_2D_WIDGET_BASE] =
{
.name = "GPU_SHADER_2D_WIDGET_BASE",
@@ -443,79 +340,14 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.vert = datatoc_gpu_shader_2D_widget_shadow_vert_glsl,
.frag = datatoc_gpu_shader_2D_widget_shadow_frag_glsl,
},
- [GPU_SHADER_2D_NODELINK] =
- {
- .name = "GPU_SHADER_2D_NODELINK",
- .vert = datatoc_gpu_shader_2D_nodelink_vert_glsl,
- .frag = datatoc_gpu_shader_2D_nodelink_frag_glsl,
- },
- [GPU_SHADER_2D_NODELINK_INST] =
- {
- .name = "GPU_SHADER_2D_NODELINK_INST",
- .vert = datatoc_gpu_shader_2D_nodelink_vert_glsl,
- .frag = datatoc_gpu_shader_2D_nodelink_frag_glsl,
- .defs = "#define USE_INSTANCE\n",
- },
+ [GPU_SHADER_2D_NODELINK] = {.name = "GPU_SHADER_2D_NODELINK",
+ .create_info = "gpu_shader_2D_nodelink"},
- [GPU_SHADER_2D_UV_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_2D_UV_UNIFORM_COLOR",
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_uniform_color_frag_glsl,
- .defs = "#define UV_POS\n",
- },
- [GPU_SHADER_2D_UV_VERTS] =
- {
- .name = "GPU_SHADER_2D_UV_VERTS",
- .vert = datatoc_gpu_shader_2D_edituvs_points_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl,
- },
- [GPU_SHADER_2D_UV_FACEDOTS] =
- {
- .name = "GPU_SHADER_2D_UV_FACEDOTS",
- .vert = datatoc_gpu_shader_2D_edituvs_facedots_vert_glsl,
- .frag = datatoc_gpu_shader_point_varying_color_frag_glsl,
- },
- [GPU_SHADER_2D_UV_EDGES] =
- {
- .name = "GPU_SHADER_2D_UV_EDGES",
- .vert = datatoc_gpu_shader_2D_edituvs_edges_vert_glsl,
- .frag = datatoc_gpu_shader_2D_edituvs_edges_frag_glsl,
- },
- [GPU_SHADER_2D_UV_EDGES_SMOOTH] =
- {
- .name = "GPU_SHADER_2D_UV_EDGES_SMOOTH",
- .vert = datatoc_gpu_shader_2D_edituvs_edges_vert_glsl,
- .frag = datatoc_gpu_shader_2D_edituvs_edges_frag_glsl,
- .defs = "#define SMOOTH_COLOR\n",
- },
- [GPU_SHADER_2D_UV_FACES] =
- {
- .name = "GPU_SHADER_2D_UV_FACES",
- .vert = datatoc_gpu_shader_2D_edituvs_faces_vert_glsl,
- .frag = datatoc_gpu_shader_flat_color_frag_glsl,
- },
- [GPU_SHADER_2D_UV_FACES_STRETCH_AREA] =
- {
- .name = "GPU_SHADER_2D_UV_FACES_STRETCH_AREA",
- .vert = datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl,
- .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl,
- },
- [GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE] =
- {
- .name = "GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE",
- .vert = datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl,
- .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl,
- .defs = "#define STRETCH_ANGLE\n",
- },
+ [GPU_SHADER_2D_NODELINK_INST] = {.name = "GPU_SHADER_2D_NODELINK_INST",
+ .create_info = "gpu_shader_2D_nodelink_inst"},
- [GPU_SHADER_GPENCIL_STROKE] =
- {
- .name = "GPU_SHADER_GPENCIL_STROKE",
- .vert = datatoc_gpu_shader_gpencil_stroke_vert_glsl,
- .geom = datatoc_gpu_shader_gpencil_stroke_geom_glsl,
- .frag = datatoc_gpu_shader_gpencil_stroke_frag_glsl,
- },
+ [GPU_SHADER_GPENCIL_STROKE] = {.name = "GPU_SHADER_GPENCIL_STROKE",
+ .create_info = "gpu_shader_gpencil_stroke"},
};
GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
@@ -530,14 +362,20 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
/* common case */
if (sh_cfg == GPU_SHADER_CFG_DEFAULT) {
- *sh_p = GPU_shader_create_from_arrays_named(
- stages->name,
- {
- .vert = (const char *[]){stages->vert, NULL},
- .geom = (const char *[]){stages->geom, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL},
- .defs = (const char *[]){stages->defs, NULL},
- });
+ if (stages->create_info != NULL) {
+ *sh_p = GPU_shader_create_from_info_name(stages->create_info);
+ }
+ else {
+ *sh_p = GPU_shader_create_from_arrays_named(
+ stages->name,
+ {
+ .vert = (const char *[]){stages->vert, NULL},
+ .geom = (const char *[]){stages->geom, NULL},
+ .frag =
+ (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL},
+ .defs = (const char *[]){stages->defs, NULL},
+ });
+ }
}
else if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
/* Remove eventually, for now ensure support for each shader has been added. */
@@ -546,21 +384,26 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
GPU_SHADER_3D_SMOOTH_COLOR,
GPU_SHADER_3D_DEPTH_ONLY,
GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE,
- GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
GPU_SHADER_3D_FLAT_COLOR,
GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR));
- const char *world_clip_lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl;
- const char *world_clip_def = "#define USE_WORLD_CLIP_PLANES\n";
/* In rare cases geometry shaders calculate clipping themselves. */
- *sh_p = GPU_shader_create_from_arrays_named(
- stages->name,
- {
- .vert = (const char *[]){world_clip_lib, stages->vert, NULL},
- .geom = (const char *[]){stages->geom ? world_clip_lib : NULL, stages->geom, NULL},
- .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL},
- .defs = (const char *[]){world_clip_def, stages->defs, NULL},
- });
+ if (stages->clipped_create_info != NULL) {
+ *sh_p = GPU_shader_create_from_info_name(stages->clipped_create_info);
+ }
+ else {
+ const char *world_clip_lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl;
+ const char *world_clip_def = "#define USE_WORLD_CLIP_PLANES\n";
+ *sh_p = GPU_shader_create_from_arrays_named(
+ stages->name,
+ {
+ .vert = (const char *[]){world_clip_lib, stages->vert, NULL},
+ .geom = (const char *[]){stages->geom ? world_clip_lib : NULL, stages->geom, NULL},
+ .frag =
+ (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL},
+ .defs = (const char *[]){world_clip_def, stages->defs, NULL},
+ });
+ }
}
else {
BLI_assert(0);
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc
new file mode 100644
index 00000000000..492b247e192
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_create_info.cc
@@ -0,0 +1,308 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Descriptor type used to define shader structure, resources and interfaces.
+ */
+
+#include "BLI_map.hh"
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+
+#include "GPU_capabilities.h"
+#include "GPU_platform.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+#include "gpu_shader_create_info.hh"
+#include "gpu_shader_create_info_private.hh"
+#include "gpu_shader_private.hh"
+
+#undef GPU_SHADER_INTERFACE_INFO
+#undef GPU_SHADER_CREATE_INFO
+
+namespace blender::gpu::shader {
+
+using CreateInfoDictionnary = Map<StringRef, ShaderCreateInfo *>;
+using InterfaceDictionnary = Map<StringRef, StageInterfaceInfo *>;
+
+static CreateInfoDictionnary *g_create_infos = nullptr;
+static InterfaceDictionnary *g_interfaces = nullptr;
+
+void ShaderCreateInfo::finalize()
+{
+ if (finalized_) {
+ return;
+ }
+ finalized_ = true;
+
+ for (auto &info_name : additional_infos_) {
+ const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(
+ gpu_shader_create_info_get(info_name.c_str()));
+
+ /* Recursive. */
+ const_cast<ShaderCreateInfo &>(info).finalize();
+
+#if 0 /* Enabled for debugging merging. TODO(fclem) exception handling and error reporting in \
+ console. */
+ std::cout << "Merging : " << info_name << " > " << name_ << std::endl;
+#endif
+
+ interface_names_size_ += info.interface_names_size_;
+
+ vertex_inputs_.extend(info.vertex_inputs_);
+ fragment_outputs_.extend(info.fragment_outputs_);
+ vertex_out_interfaces_.extend(info.vertex_out_interfaces_);
+ geometry_out_interfaces_.extend(info.geometry_out_interfaces_);
+
+ push_constants_.extend(info.push_constants_);
+ defines_.extend(info.defines_);
+
+ batch_resources_.extend(info.batch_resources_);
+ pass_resources_.extend(info.pass_resources_);
+ typedef_sources_.extend_non_duplicates(info.typedef_sources_);
+
+ validate(info);
+
+ if (info.compute_layout_.local_size_x != -1) {
+ compute_layout_.local_size_x = info.compute_layout_.local_size_x;
+ compute_layout_.local_size_y = info.compute_layout_.local_size_y;
+ compute_layout_.local_size_z = info.compute_layout_.local_size_z;
+ }
+
+ if (!info.vertex_source_.is_empty()) {
+ BLI_assert(vertex_source_.is_empty());
+ vertex_source_ = info.vertex_source_;
+ }
+ if (!info.geometry_source_.is_empty()) {
+ BLI_assert(geometry_source_.is_empty());
+ geometry_source_ = info.geometry_source_;
+ geometry_layout_ = info.geometry_layout_;
+ }
+ if (!info.fragment_source_.is_empty()) {
+ BLI_assert(fragment_source_.is_empty());
+ fragment_source_ = info.fragment_source_;
+ }
+ if (!info.compute_source_.is_empty()) {
+ BLI_assert(compute_source_.is_empty());
+ compute_source_ = info.compute_source_;
+ }
+
+ do_static_compilation_ = do_static_compilation_ || info.do_static_compilation_;
+ }
+}
+
+void ShaderCreateInfo::validate(const ShaderCreateInfo &other_info)
+{
+ {
+ /* Check same bind-points usage in OGL. */
+ Set<int> images, samplers, ubos, ssbos;
+
+ auto register_resource = [&](const Resource &res) -> bool {
+ switch (res.bind_type) {
+ case Resource::BindType::UNIFORM_BUFFER:
+ return images.add(res.slot);
+ case Resource::BindType::STORAGE_BUFFER:
+ return samplers.add(res.slot);
+ case Resource::BindType::SAMPLER:
+ return ubos.add(res.slot);
+ case Resource::BindType::IMAGE:
+ return ssbos.add(res.slot);
+ default:
+ return false;
+ }
+ };
+
+ auto print_error_msg = [&](const Resource &res) {
+ std::cerr << name_ << ": Validation failed : Overlapping ";
+
+ switch (res.bind_type) {
+ case Resource::BindType::UNIFORM_BUFFER:
+ std::cerr << "Uniform Buffer " << res.uniformbuf.name;
+ break;
+ case Resource::BindType::STORAGE_BUFFER:
+ std::cerr << "Storage Buffer " << res.storagebuf.name;
+ break;
+ case Resource::BindType::SAMPLER:
+ std::cerr << "Sampler " << res.sampler.name;
+ break;
+ case Resource::BindType::IMAGE:
+ std::cerr << "Image " << res.image.name;
+ break;
+ default:
+ std::cerr << "Unknown Type";
+ break;
+ }
+ std::cerr << " (" << res.slot << ") while merging " << other_info.name_ << std::endl;
+ };
+
+ for (auto &res : batch_resources_) {
+ if (register_resource(res) == false) {
+ print_error_msg(res);
+ }
+ }
+
+ for (auto &res : pass_resources_) {
+ if (register_resource(res) == false) {
+ print_error_msg(res);
+ }
+ }
+ }
+ {
+ /* TODO(fclem) Push constant validation. */
+ }
+}
+
+} // namespace blender::gpu::shader
+
+using namespace blender::gpu::shader;
+
+void gpu_shader_create_info_init()
+{
+ g_create_infos = new CreateInfoDictionnary();
+ g_interfaces = new InterfaceDictionnary();
+
+#define GPU_SHADER_INTERFACE_INFO(_interface, _inst_name) \
+ auto *ptr_##_interface = new StageInterfaceInfo(#_interface, _inst_name); \
+ auto &_interface = *ptr_##_interface; \
+ g_interfaces->add_new(#_interface, ptr_##_interface); \
+ _interface
+
+#define GPU_SHADER_CREATE_INFO(_info) \
+ auto *ptr_##_info = new ShaderCreateInfo(#_info); \
+ auto &_info = *ptr_##_info; \
+ g_create_infos->add_new(#_info, ptr_##_info); \
+ _info
+
+/* Declare, register and construct the infos. */
+#include "gpu_shader_create_info_list.hh"
+
+/* Baked shader data appended to create infos. */
+/* TODO(jbakker): should call a function with a callback. so we could switch implementations.
+ * We cannot compile bf_gpu twice. */
+#ifdef GPU_RUNTIME
+# include "gpu_shader_baked.hh"
+#endif
+
+ /* WORKAROUND: Replace draw_mesh info with the legacy one for systems that have problems with UBO
+ * indexing. */
+ if (GPU_type_matches(GPU_DEVICE_INTEL | GPU_DEVICE_INTEL_UHD, GPU_OS_ANY, GPU_DRIVER_ANY) ||
+ GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY) || GPU_crappy_amd_driver()) {
+ draw_modelmat = draw_modelmat_legacy;
+ }
+
+ /* TEST */
+ // gpu_shader_create_info_compile_all();
+}
+
+void gpu_shader_create_info_exit()
+{
+ for (auto *value : g_create_infos->values()) {
+ delete value;
+ }
+ delete g_create_infos;
+
+ for (auto *value : g_interfaces->values()) {
+ delete value;
+ }
+ delete g_interfaces;
+}
+
+bool gpu_shader_create_info_compile_all()
+{
+ using namespace blender::gpu;
+ int success = 0;
+ int total = 0;
+ for (ShaderCreateInfo *info : g_create_infos->values()) {
+ if (info->do_static_compilation_) {
+ total++;
+ GPUShader *shader = GPU_shader_create_from_info(
+ reinterpret_cast<const GPUShaderCreateInfo *>(info));
+ if (shader == nullptr) {
+ printf("Compilation %s Failed\n", info->name_.c_str());
+ }
+ else {
+ success++;
+
+#if 0 /* TODO(fclem): This is too verbose for now. Make it a cmake option. */
+ /* Test if any resource is optimized out and print a warning if that's the case. */
+ /* TODO(fclem): Limit this to OpenGL backend. */
+ const ShaderInterface *interface = unwrap(shader)->interface;
+
+ blender::Vector<ShaderCreateInfo::Resource> all_resources;
+ all_resources.extend(info->pass_resources_);
+ all_resources.extend(info->batch_resources_);
+
+ for (ShaderCreateInfo::Resource &res : all_resources) {
+ blender::StringRefNull name = "";
+ const ShaderInput *input = nullptr;
+
+ switch (res.bind_type) {
+ case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER:
+ input = interface->ubo_get(res.slot);
+ name = res.uniformbuf.name;
+ break;
+ case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER:
+ input = interface->ssbo_get(res.slot);
+ name = res.storagebuf.name;
+ break;
+ case ShaderCreateInfo::Resource::BindType::SAMPLER:
+ input = interface->texture_get(res.slot);
+ name = res.sampler.name;
+ break;
+ case ShaderCreateInfo::Resource::BindType::IMAGE:
+ input = interface->texture_get(res.slot);
+ name = res.image.name;
+ break;
+ }
+
+ if (input == nullptr) {
+ std::cout << "Error: " << info->name_;
+ std::cout << ": Resource « " << name << " » not found in the shader interface\n";
+ }
+ else if (input->location == -1) {
+ std::cout << "Warning: " << info->name_;
+ std::cout << ": Resource « " << name << " » is optimized out\n";
+ }
+ }
+#endif
+ }
+ GPU_shader_free(shader);
+ }
+ }
+ printf("===============================\n");
+ printf("Shader Test compilation result: \n");
+ printf("%d Total\n", total);
+ printf("%d Passed\n", success);
+ printf("%d Failed\n", total - success);
+ printf("===============================\n");
+ return success == total;
+}
+
+/* Runtime create infos are not registered in the dictionary and cannot be searched. */
+const GPUShaderCreateInfo *gpu_shader_create_info_get(const char *info_name)
+{
+ if (g_create_infos->contains(info_name) == false) {
+ printf("Error: Cannot find shader create info named \"%s\"\n", info_name);
+ }
+ ShaderCreateInfo *info = g_create_infos->lookup(info_name);
+ return reinterpret_cast<const GPUShaderCreateInfo *>(info);
+}
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh
new file mode 100644
index 00000000000..63c6e94f4c8
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_create_info.hh
@@ -0,0 +1,613 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Descriptor type used to define shader structure, resources and interfaces.
+ *
+ * Some rule of thumb:
+ * - Do not include anything else than this file in each info file.
+ */
+
+#pragma once
+
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+#include "GPU_texture.h"
+
+namespace blender::gpu::shader {
+
+#ifndef GPU_SHADER_CREATE_INFO
+/* Helps intelisense / auto-completion. */
+# define GPU_SHADER_INTERFACE_INFO(_interface, _inst_name) \
+ StageInterfaceInfo _interface(#_interface, _inst_name); \
+ _interface
+# define GPU_SHADER_CREATE_INFO(_info) \
+ ShaderCreateInfo _info(#_info); \
+ _info
+#endif
+
+enum class Type {
+ FLOAT = 0,
+ VEC2,
+ VEC3,
+ VEC4,
+ MAT3,
+ MAT4,
+ UINT,
+ UVEC2,
+ UVEC3,
+ UVEC4,
+ INT,
+ IVEC2,
+ IVEC3,
+ IVEC4,
+ BOOL,
+};
+
+enum class BuiltinBits {
+ /**
+ * Allow getting barycentric coordinates inside the fragment shader.
+ * \note Emulated on OpenGL.
+ */
+ BARYCENTRIC_COORD = (1 << 0),
+ FRAG_COORD = (1 << 2),
+ FRONT_FACING = (1 << 4),
+ GLOBAL_INVOCATION_ID = (1 << 5),
+ INSTANCE_ID = (1 << 6),
+ LAYER = (1 << 7),
+ LOCAL_INVOCATION_ID = (1 << 8),
+ LOCAL_INVOCATION_INDEX = (1 << 9),
+ NUM_WORK_GROUP = (1 << 10),
+ POINT_COORD = (1 << 11),
+ POINT_SIZE = (1 << 12),
+ PRIMITIVE_ID = (1 << 13),
+ VERTEX_ID = (1 << 14),
+ WORK_GROUP_ID = (1 << 15),
+ WORK_GROUP_SIZE = (1 << 16),
+};
+ENUM_OPERATORS(BuiltinBits, BuiltinBits::WORK_GROUP_SIZE);
+
+/* Samplers & images. */
+enum class ImageType {
+ /** Color samplers/image. */
+ FLOAT_BUFFER = 0,
+ FLOAT_1D,
+ FLOAT_1D_ARRAY,
+ FLOAT_2D,
+ FLOAT_2D_ARRAY,
+ FLOAT_3D,
+ FLOAT_CUBE,
+ FLOAT_CUBE_ARRAY,
+ INT_BUFFER,
+ INT_1D,
+ INT_1D_ARRAY,
+ INT_2D,
+ INT_2D_ARRAY,
+ INT_3D,
+ INT_CUBE,
+ INT_CUBE_ARRAY,
+ UINT_BUFFER,
+ UINT_1D,
+ UINT_1D_ARRAY,
+ UINT_2D,
+ UINT_2D_ARRAY,
+ UINT_3D,
+ UINT_CUBE,
+ UINT_CUBE_ARRAY,
+ /** Depth samplers (not supported as image). */
+ SHADOW_2D,
+ SHADOW_2D_ARRAY,
+ SHADOW_CUBE,
+ SHADOW_CUBE_ARRAY,
+ DEPTH_2D,
+ DEPTH_2D_ARRAY,
+ DEPTH_CUBE,
+ DEPTH_CUBE_ARRAY,
+};
+
+/* Storage qualifiers. */
+enum class Qualifier {
+ RESTRICT = (1 << 0),
+ READ_ONLY = (1 << 1),
+ WRITE_ONLY = (1 << 2),
+ QUALIFIER_MAX = (WRITE_ONLY << 1) - 1,
+};
+ENUM_OPERATORS(Qualifier, Qualifier::QUALIFIER_MAX);
+
+enum class Frequency {
+ BATCH = 0,
+ PASS,
+};
+
+/* Dual Source Blending Index. */
+enum class DualBlend {
+ NONE = 0,
+ SRC_0,
+ SRC_1,
+};
+
+/* Interpolation qualifiers. */
+enum class Interpolation {
+ SMOOTH = 0,
+ FLAT,
+ NO_PERSPECTIVE,
+};
+
+/** Input layout for geometry shader. */
+enum class PrimitiveIn {
+ POINTS = 0,
+ LINES,
+ LINES_ADJACENCY,
+ TRIANGLES,
+ TRIANGLES_ADJACENCY,
+};
+
+/** Output layout for geometry shader. */
+enum class PrimitiveOut {
+ POINTS = 0,
+ LINE_STRIP,
+ TRIANGLE_STRIP,
+};
+
+struct StageInterfaceInfo {
+ struct InOut {
+ Interpolation interp;
+ Type type;
+ StringRefNull name;
+ };
+
+ StringRefNull name;
+ /** Name of the instance of the block (used to access).
+ * Can be empty string (i.e: "") only if not using geometry shader. */
+ StringRefNull instance_name;
+ /** List of all members of the interface. */
+ Vector<InOut> inouts;
+
+ StageInterfaceInfo(const char *name_, const char *instance_name_)
+ : name(name_), instance_name(instance_name_){};
+ ~StageInterfaceInfo(){};
+
+ using Self = StageInterfaceInfo;
+
+ Self &smooth(Type type, StringRefNull _name)
+ {
+ inouts.append({Interpolation::SMOOTH, type, _name});
+ return *(Self *)this;
+ }
+
+ Self &flat(Type type, StringRefNull _name)
+ {
+ inouts.append({Interpolation::FLAT, type, _name});
+ return *(Self *)this;
+ }
+
+ Self &no_perspective(Type type, StringRefNull _name)
+ {
+ inouts.append({Interpolation::NO_PERSPECTIVE, type, _name});
+ return *(Self *)this;
+ }
+};
+
+/**
+ * @brief Describe inputs & outputs, stage interfaces, resources and sources of a shader.
+ * If all data is correctly provided, this is all that is needed to create and compile
+ * a GPUShader.
+ *
+ * IMPORTANT: All strings are references only. Make sure all the strings used by a
+ * ShaderCreateInfo are not freed until it is consumed or deleted.
+ */
+struct ShaderCreateInfo {
+ /** Shader name for debugging. */
+ StringRefNull name_;
+ /** True if the shader is static and can be pre-compiled at compile time. */
+ bool do_static_compilation_ = false;
+ /** If true, all additionally linked create info will be merged into this one. */
+ bool finalized_ = false;
+ /**
+ * Maximum length of all the resource names including each null terminator.
+ * Only for names used by gpu::ShaderInterface.
+ */
+ size_t interface_names_size_ = 0;
+
+ struct VertIn {
+ int index;
+ Type type;
+ StringRefNull name;
+ };
+ Vector<VertIn> vertex_inputs_;
+
+ struct GeometryStageLayout {
+ PrimitiveIn primitive_in;
+ int invocations;
+ PrimitiveOut primitive_out;
+ /** Set to -1 by default to check if used. */
+ int max_vertices = -1;
+ };
+ GeometryStageLayout geometry_layout_;
+
+ struct ComputeStageLayout {
+ int local_size_x = -1;
+ int local_size_y = -1;
+ int local_size_z = -1;
+ };
+
+ ComputeStageLayout compute_layout_;
+
+ struct FragOut {
+ int index;
+ Type type;
+ DualBlend blend;
+ StringRefNull name;
+ };
+ Vector<FragOut> fragment_outputs_;
+
+ struct Sampler {
+ ImageType type;
+ eGPUSamplerState sampler;
+ StringRefNull name;
+ };
+
+ struct Image {
+ eGPUTextureFormat format;
+ ImageType type;
+ Qualifier qualifiers;
+ StringRefNull name;
+ };
+
+ struct UniformBuf {
+ StringRefNull type_name;
+ StringRefNull name;
+ };
+
+ struct StorageBuf {
+ Qualifier qualifiers;
+ StringRefNull type_name;
+ StringRefNull name;
+ };
+
+ struct Resource {
+ enum BindType {
+ UNIFORM_BUFFER = 0,
+ STORAGE_BUFFER,
+ SAMPLER,
+ IMAGE,
+ };
+
+ BindType bind_type;
+ int slot;
+ union {
+ Sampler sampler;
+ Image image;
+ UniformBuf uniformbuf;
+ StorageBuf storagebuf;
+ };
+
+ Resource(BindType type, int _slot) : bind_type(type), slot(_slot){};
+ };
+ /**
+ * Resources are grouped by frequency of change.
+ * Pass resources are meant to be valid for the whole pass.
+ * Batch resources can be changed in a more granular manner (per object/material).
+ * Mis-usage will only produce suboptimal performance.
+ */
+ Vector<Resource> pass_resources_, batch_resources_;
+
+ Vector<StageInterfaceInfo *> vertex_out_interfaces_;
+ Vector<StageInterfaceInfo *> geometry_out_interfaces_;
+
+ struct PushConst {
+ Type type;
+ StringRefNull name;
+ int array_size;
+ };
+
+ Vector<PushConst> push_constants_;
+
+ /* Sources for resources type definitions. */
+ Vector<StringRefNull> typedef_sources_;
+
+ StringRefNull vertex_source_, geometry_source_, fragment_source_, compute_source_;
+
+ Vector<std::array<StringRefNull, 2>> defines_;
+ /**
+ * Name of other infos to recursively merge with this one.
+ * No data slot must overlap otherwise we throw an error.
+ */
+ Vector<StringRefNull> additional_infos_;
+
+ public:
+ ShaderCreateInfo(const char *name) : name_(name){};
+ ~ShaderCreateInfo(){};
+
+ using Self = ShaderCreateInfo;
+
+ /* -------------------------------------------------------------------- */
+ /** \name Shaders in/outs (fixed function pipeline config)
+ * \{ */
+
+ Self &vertex_in(int slot, Type type, StringRefNull name)
+ {
+ vertex_inputs_.append({slot, type, name});
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &vertex_out(StageInterfaceInfo &interface)
+ {
+ vertex_out_interfaces_.append(&interface);
+ return *(Self *)this;
+ }
+
+ /**
+ * IMPORTANT: invocations count is only used if GL_ARB_gpu_shader5 is supported. On
+ * implementations that do not supports it, the max_vertices will be be multiplied by
+ * invocations. Your shader needs to account for this fact. Use `#ifdef GPU_ARB_gpu_shader5`
+ * and make a code path that does not rely on gl_InvocationID.
+ */
+ Self &geometry_layout(PrimitiveIn prim_in,
+ PrimitiveOut prim_out,
+ int max_vertices,
+ int invocations = -1)
+ {
+ geometry_layout_.primitive_in = prim_in;
+ geometry_layout_.primitive_out = prim_out;
+ geometry_layout_.max_vertices = max_vertices;
+ geometry_layout_.invocations = invocations;
+ return *(Self *)this;
+ }
+
+ Self &local_group_size(int local_size_x = -1, int local_size_y = -1, int local_size_z = -1)
+ {
+ compute_layout_.local_size_x = local_size_x;
+ compute_layout_.local_size_y = local_size_y;
+ compute_layout_.local_size_z = local_size_z;
+ return *(Self *)this;
+ }
+
+ /**
+ * Only needed if geometry shader is enabled.
+ * IMPORTANT: Input and output instance name will have respectively "_in" and "_out" suffix
+ * appended in the geometry shader IF AND ONLY IF the vertex_out interface instance name matches
+ * the geometry_out interface instance name.
+ */
+ Self &geometry_out(StageInterfaceInfo &interface)
+ {
+ geometry_out_interfaces_.append(&interface);
+ return *(Self *)this;
+ }
+
+ Self &fragment_out(int slot, Type type, StringRefNull name, DualBlend blend = DualBlend::NONE)
+ {
+ fragment_outputs_.append({slot, type, blend, name});
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Resources bindings points
+ * \{ */
+
+ Self &uniform_buf(int slot,
+ StringRefNull type_name,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS)
+ {
+ Resource res(Resource::BindType::UNIFORM_BUFFER, slot);
+ res.uniformbuf.name = name;
+ res.uniformbuf.type_name = type_name;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &storage_buf(int slot,
+ Qualifier qualifiers,
+ StringRefNull type_name,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS)
+ {
+ Resource res(Resource::BindType::STORAGE_BUFFER, slot);
+ res.storagebuf.qualifiers = qualifiers;
+ res.storagebuf.type_name = type_name;
+ res.storagebuf.name = name;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &image(int slot,
+ eGPUTextureFormat format,
+ Qualifier qualifiers,
+ ImageType type,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS)
+ {
+ Resource res(Resource::BindType::IMAGE, slot);
+ res.image.format = format;
+ res.image.qualifiers = qualifiers;
+ res.image.type = type;
+ res.image.name = name;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ Self &sampler(int slot,
+ ImageType type,
+ StringRefNull name,
+ Frequency freq = Frequency::PASS,
+ eGPUSamplerState sampler = (eGPUSamplerState)-1)
+ {
+ Resource res(Resource::BindType::SAMPLER, slot);
+ res.sampler.type = type;
+ res.sampler.name = name;
+ res.sampler.sampler = sampler;
+ ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res);
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Shader Source
+ * \{ */
+
+ Self &vertex_source(StringRefNull filename)
+ {
+ vertex_source_ = filename;
+ return *(Self *)this;
+ }
+
+ Self &geometry_source(StringRefNull filename)
+ {
+ geometry_source_ = filename;
+ return *(Self *)this;
+ }
+
+ Self &fragment_source(StringRefNull filename)
+ {
+ fragment_source_ = filename;
+ return *(Self *)this;
+ }
+
+ Self &compute_source(StringRefNull filename)
+ {
+ compute_source_ = filename;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Push constants
+ *
+ * Data managed by GPUShader. Can be set through uniform functions. Must be less than 128bytes.
+ * \{ */
+
+ Self &push_constant(Type type, StringRefNull name, int array_size = 0)
+ {
+ BLI_assert_msg(name.find("[") == -1,
+ "Array syntax is forbidden for push constants."
+ "Use the array_size parameter instead.");
+ push_constants_.append({type, name, array_size});
+ interface_names_size_ += name.size() + 1;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Defines
+ * \{ */
+
+ Self &define(StringRefNull name, StringRefNull value = "")
+ {
+ defines_.append({name, value});
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Defines
+ * \{ */
+
+ Self &do_static_compilation(bool value)
+ {
+ do_static_compilation_ = value;
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Additional Create Info
+ *
+ * Used to share parts of the infos that are common to many shaders.
+ * \{ */
+
+ Self &additional_info(StringRefNull info_name0,
+ StringRefNull info_name1 = "",
+ StringRefNull info_name2 = "",
+ StringRefNull info_name3 = "",
+ StringRefNull info_name4 = "",
+ StringRefNull info_name5 = "",
+ StringRefNull info_name6 = "")
+ {
+ additional_infos_.append(info_name0);
+ if (!info_name1.is_empty()) {
+ additional_infos_.append(info_name1);
+ }
+ if (!info_name2.is_empty()) {
+ additional_infos_.append(info_name2);
+ }
+ if (!info_name3.is_empty()) {
+ additional_infos_.append(info_name3);
+ }
+ if (!info_name4.is_empty()) {
+ additional_infos_.append(info_name4);
+ }
+ if (!info_name5.is_empty()) {
+ additional_infos_.append(info_name5);
+ }
+ if (!info_name6.is_empty()) {
+ additional_infos_.append(info_name6);
+ }
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Typedef Sources
+ *
+ * Some resource declarations might need some special structure defined.
+ * Adding a file using typedef_source will include it before the resource
+ * and interface definitions.
+ * \{ */
+
+ Self &typedef_source(StringRefNull filename)
+ {
+ typedef_sources_.append(filename);
+ return *(Self *)this;
+ }
+
+ /** \} */
+
+ /* -------------------------------------------------------------------- */
+ /** \name Recursive evaluation.
+ *
+ * Flatten all dependency so that this descriptor contains all the data from the additional
+ * descriptors. This avoids tedious traversal in shader source creation.
+ * \{ */
+
+ /* WARNING: Recursive. */
+ void finalize();
+
+ /** Error detection that some backend compilers do not complain about. */
+ void validate(const ShaderCreateInfo &other_info);
+
+ /** \} */
+};
+
+} // namespace blender::gpu::shader
diff --git a/source/blender/gpu/intern/gpu_shader_create_info_private.hh b/source/blender/gpu/intern/gpu_shader_create_info_private.hh
new file mode 100644
index 00000000000..6d2878377ad
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_create_info_private.hh
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Descriptor type used to define shader structure, resources and interfaces.
+ *
+ * Some rule of thumb:
+ * - Do not include anything else than this file in each descriptor file.
+ */
+
+#pragma once
+
+#include "GPU_shader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gpu_shader_create_info_init(void);
+void gpu_shader_create_info_exit(void);
+
+bool gpu_shader_create_info_compile_all(void);
+
+const GPUShaderCreateInfo *gpu_shader_create_info_get(const char *info_name);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
new file mode 100644
index 00000000000..2333590810f
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -0,0 +1,388 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Shader source dependency builder that make possible to support #include directive inside the
+ * shader files.
+ */
+
+#include <iostream>
+
+#include "BLI_map.hh"
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+
+#include "gpu_shader_create_info.hh"
+#include "gpu_shader_dependency_private.h"
+
+extern "C" {
+#define SHADER_SOURCE(datatoc, filename, filepath) extern char datatoc[];
+#include "glsl_draw_source_list.h"
+#include "glsl_gpu_source_list.h"
+#undef SHADER_SOURCE
+}
+
+namespace blender::gpu {
+
+using GPUSourceDictionnary = Map<StringRef, struct GPUSource *>;
+
+struct GPUSource {
+ StringRefNull fullpath;
+ StringRefNull filename;
+ StringRefNull source;
+ Vector<GPUSource *> dependencies;
+ bool dependencies_init = false;
+ shader::BuiltinBits builtins = (shader::BuiltinBits)0;
+ std::string processed_source;
+
+ GPUSource(const char *path, const char *file, const char *datatoc)
+ : fullpath(path), filename(file), source(datatoc)
+ {
+ /* Scan for builtins. */
+ /* FIXME: This can trigger false positive caused by disabled #if blocks. */
+ /* TODO(fclem): Could be made faster by scanning once. */
+ /* TODO(fclem): BARYCENTRIC_COORD. */
+ if (source.find("gl_FragCoord", 0)) {
+ builtins |= shader::BuiltinBits::FRAG_COORD;
+ }
+ if (source.find("gl_FrontFacing", 0)) {
+ builtins |= shader::BuiltinBits::FRONT_FACING;
+ }
+ if (source.find("gl_GlobalInvocationID", 0)) {
+ builtins |= shader::BuiltinBits::GLOBAL_INVOCATION_ID;
+ }
+ if (source.find("gl_InstanceID", 0)) {
+ builtins |= shader::BuiltinBits::INSTANCE_ID;
+ }
+ if (source.find("gl_Layer", 0)) {
+ builtins |= shader::BuiltinBits::LAYER;
+ }
+ if (source.find("gl_LocalInvocationID", 0)) {
+ builtins |= shader::BuiltinBits::LOCAL_INVOCATION_ID;
+ }
+ if (source.find("gl_LocalInvocationIndex", 0)) {
+ builtins |= shader::BuiltinBits::LOCAL_INVOCATION_INDEX;
+ }
+ if (source.find("gl_NumWorkGroup", 0)) {
+ builtins |= shader::BuiltinBits::NUM_WORK_GROUP;
+ }
+ if (source.find("gl_PointCoord", 0)) {
+ builtins |= shader::BuiltinBits::POINT_COORD;
+ }
+ if (source.find("gl_PointSize", 0)) {
+ builtins |= shader::BuiltinBits::POINT_SIZE;
+ }
+ if (source.find("gl_PrimitiveID", 0)) {
+ builtins |= shader::BuiltinBits::PRIMITIVE_ID;
+ }
+ if (source.find("gl_VertexID", 0)) {
+ builtins |= shader::BuiltinBits::VERTEX_ID;
+ }
+ if (source.find("gl_WorkGroupID", 0)) {
+ builtins |= shader::BuiltinBits::WORK_GROUP_ID;
+ }
+ if (source.find("gl_WorkGroupSize", 0)) {
+ builtins |= shader::BuiltinBits::WORK_GROUP_SIZE;
+ }
+
+ /* TODO(fclem): We could do that at compile time. */
+ /* Limit to shared header files to avoid the temptation to use C++ syntax in .glsl files. */
+ if (filename.endswith(".h") || filename.endswith(".hh")) {
+ enum_preprocess();
+ }
+ };
+
+ bool is_in_comment(const StringRef &input, int64_t offset)
+ {
+ return (input.rfind("/*", offset) > input.rfind("*/", offset)) ||
+ (input.rfind("//", offset) > input.rfind("\n", offset));
+ }
+
+ template<bool check_whole_word = true, bool reversed = false, typename T>
+ int64_t find_str(const StringRef &input, const T keyword, int64_t offset = 0)
+ {
+ while (1) {
+ if constexpr (reversed) {
+ offset = input.rfind(keyword, offset);
+ }
+ else {
+ offset = input.find(keyword, offset);
+ }
+ if (offset > 0) {
+ if constexpr (check_whole_word) {
+ /* Fix false positive if something has "enum" as suffix. */
+ char previous_char = input[offset - 1];
+ if (!(ELEM(previous_char, '\n', '\t', ' ', ':'))) {
+ offset += (reversed) ? -1 : 1;
+ continue;
+ }
+ }
+ /* Fix case where the keyword is in a comment. */
+ if (is_in_comment(input, offset)) {
+ offset += (reversed) ? -1 : 1;
+ continue;
+ }
+ }
+ return offset;
+ }
+ }
+
+ void print_error(const StringRef &input, int64_t offset, const StringRef message)
+ {
+ std::cout << " error: " << message << "\n";
+ StringRef sub = input.substr(0, offset);
+ int64_t line_number = std::count(sub.begin(), sub.end(), '\n') + 1;
+ int64_t line_end = input.find("\n", offset);
+ int64_t line_start = input.rfind("\n", offset) + 1;
+ int64_t char_number = offset - line_start + 1;
+ char line_prefix[16] = "";
+ SNPRINTF(line_prefix, "%5ld | ", line_number);
+
+ /* TODO Use clog. */
+
+ std::cout << fullpath << ":" << line_number << ":" << char_number;
+
+ std::cout << " error: " << message << "\n";
+ std::cout << line_prefix << input.substr(line_start, line_end - line_start) << "\n";
+ std::cout << " | ";
+ for (int64_t i = 0; i < char_number - 1; i++) {
+ std::cout << " ";
+ }
+ std::cout << "^\n";
+ }
+
+ /**
+ * Transform C,C++ enum declaration into GLSL compatible defines and constants:
+ *
+ * \code{.cpp}
+ * enum eMyEnum : uint32_t {
+ * ENUM_1 = 0u,
+ * ENUM_2 = 1u,
+ * ENUM_3 = 2u,
+ * };
+ * \endcode
+ *
+ * or
+ *
+ * \code{.c}
+ * enum eMyEnum {
+ * ENUM_1 = 0u,
+ * ENUM_2 = 1u,
+ * ENUM_3 = 2u,
+ * };
+ * \endcode
+ *
+ * becomes
+ *
+ * \code{.glsl}
+ * #define eMyEnum uint
+ * const uint ENUM_1 = 0u, ENUM_2 = 1u, ENUM_3 = 2u;
+ * \endcode
+ *
+ * IMPORTANT: This has some requirements:
+ * - Enums needs to have underlying types specified to uint32_t to make them usable in UBO/SSBO.
+ * - All values needs to be specified using constant literals to avoid compiler differencies.
+ * - All values needs to have the 'u' suffix to avoid GLSL compiler errors.
+ */
+ void enum_preprocess(void)
+ {
+ const StringRefNull input = source;
+ std::string output = "";
+ int64_t cursor = 0;
+ int64_t last_pos = 0;
+ const bool is_cpp = filename.endswith(".hh");
+
+#define find_keyword find_str<true, false>
+#define find_token find_str<false, false>
+#define rfind_token find_str<false, true>
+#define CHECK(test_value, str, ofs, msg) \
+ if ((test_value) == -1) { \
+ print_error(str, ofs, msg); \
+ cursor++; \
+ continue; \
+ }
+
+ while (1) {
+ cursor = find_keyword(input, "enum ", cursor);
+ if (cursor == -1) {
+ break;
+ }
+ /* Output anything between 2 enums blocks. */
+ output += input.substr(last_pos, cursor - last_pos);
+
+ /* Extract enum type name. */
+ int64_t name_start = input.find(" ", cursor);
+
+ int64_t values_start = find_token(input, '{', cursor);
+ CHECK(values_start, input, cursor, "Malformed enum class. Expected \'{\' after typename.");
+
+ StringRef enum_name = input.substr(name_start, values_start - name_start);
+ if (is_cpp) {
+ int64_t name_end = find_token(enum_name, ":");
+ CHECK(name_end, input, name_start, "Expected \':\' after C++ enum name.");
+
+ int64_t underlying_type = find_keyword(enum_name, "uint32_t", name_end);
+ CHECK(underlying_type, input, name_start, "C++ enums needs uint32_t underlying type.");
+
+ enum_name = input.substr(name_start, name_end);
+ }
+
+ output += "#define " + enum_name + " uint\n";
+
+ /* Extract enum values. */
+ int64_t values_end = find_token(input, '}', values_start);
+ CHECK(values_end, input, cursor, "Malformed enum class. Expected \'}\' after values.");
+
+ /* Skip opening brackets. */
+ values_start += 1;
+
+ StringRef enum_values = input.substr(values_start, values_end - values_start);
+
+ /* Really poor check. Could be done better. */
+ int64_t token = find_token(enum_values, '{');
+ int64_t not_found = (token == -1) ? 0 : -1;
+ CHECK(not_found, input, values_start + token, "Unexpected \'{\' token inside enum values.");
+
+ /* Do not capture the comma after the last value (if present). */
+ int64_t last_equal = rfind_token(enum_values, '=', values_end);
+ int64_t last_comma = rfind_token(enum_values, ',', values_end);
+ if (last_comma > last_equal) {
+ enum_values = input.substr(values_start, last_comma);
+ }
+
+ output += "const uint " + enum_values;
+
+ int64_t semicolon_found = (input[values_end + 1] == ';') ? 0 : -1;
+ CHECK(semicolon_found, input, values_end + 1, "Expected \';\' after enum type declaration.");
+
+ /* Skip the curly bracket but not the semicolon. */
+ cursor = last_pos = values_end + 1;
+ }
+ /* If nothing has been changed, do not allocate processed_source. */
+ if (last_pos == 0) {
+ return;
+ }
+
+#undef find_keyword
+#undef find_token
+#undef rfind_token
+
+ if (last_pos != 0) {
+ output += input.substr(last_pos);
+ }
+ processed_source = output;
+ source = processed_source.c_str();
+ };
+
+ void init_dependencies(const GPUSourceDictionnary &dict)
+ {
+ if (dependencies_init) {
+ return;
+ }
+ dependencies_init = true;
+ int64_t pos = 0;
+ while (true) {
+ pos = source.find("pragma BLENDER_REQUIRE(", pos);
+ if (pos == -1) {
+ return;
+ }
+ int64_t start = source.find('(', pos) + 1;
+ int64_t end = source.find(')', pos);
+ if (end == -1) {
+ /* TODO Use clog. */
+ std::cout << "Error: " << filename << " : Malformed BLENDER_REQUIRE: Missing \")\"."
+ << std::endl;
+ return;
+ }
+ StringRef dependency_name = source.substr(start, end - start);
+ GPUSource *dependency_source = dict.lookup_default(dependency_name, nullptr);
+ if (dependency_source == nullptr) {
+ /* TODO Use clog. */
+ std::cout << "Error: " << filename << " : Dependency not found \"" << dependency_name
+ << "\"." << std::endl;
+ return;
+ }
+ /* Recursive. */
+ dependency_source->init_dependencies(dict);
+
+ for (auto *dep : dependency_source->dependencies) {
+ dependencies.append_non_duplicates(dep);
+ }
+ dependencies.append_non_duplicates(dependency_source);
+ pos++;
+ };
+ }
+
+ /* Returns the final string with all includes done. */
+ void build(std::string &str, shader::BuiltinBits &out_builtins)
+ {
+ for (auto *dep : dependencies) {
+ out_builtins |= builtins;
+ str += dep->source;
+ }
+ str += source;
+ }
+};
+
+} // namespace blender::gpu
+
+using namespace blender::gpu;
+
+static GPUSourceDictionnary *g_sources = nullptr;
+
+void gpu_shader_dependency_init()
+{
+ g_sources = new GPUSourceDictionnary();
+
+#define SHADER_SOURCE(datatoc, filename, filepath) \
+ g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc));
+#include "glsl_draw_source_list.h"
+#include "glsl_gpu_source_list.h"
+#undef SHADER_SOURCE
+
+ for (auto *value : g_sources->values()) {
+ value->init_dependencies(*g_sources);
+ }
+}
+
+void gpu_shader_dependency_exit()
+{
+ for (auto *value : g_sources->values()) {
+ delete value;
+ }
+ delete g_sources;
+}
+
+char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name, uint32_t *builtins)
+{
+ GPUSource *source = g_sources->lookup(shader_source_name);
+ std::string str;
+ shader::BuiltinBits out_builtins;
+ source->build(str, out_builtins);
+ *builtins |= (uint32_t)out_builtins;
+ return strdup(str.c_str());
+}
+
+char *gpu_shader_dependency_get_source(const char *shader_source_name)
+{
+ GPUSource *src = g_sources->lookup(shader_source_name);
+ return strdup(src->source.c_str());
+}
diff --git a/source/blender/gpu/intern/gpu_shader_dependency_private.h b/source/blender/gpu/intern/gpu_shader_dependency_private.h
new file mode 100644
index 00000000000..b129ca74a48
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_dependency_private.h
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Shader source dependency builder that make possible to support #include directive inside the
+ * shader files.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gpu_shader_dependency_init(void);
+
+void gpu_shader_dependency_exit(void);
+
+/* User must free the resulting string using free. */
+char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name,
+ uint32_t *builtins);
+char *gpu_shader_dependency_get_source(const char *shader_source_name);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/intern/gpu_shader_info_baked.cc b/source/blender/gpu/intern/gpu_shader_info_baked.cc
new file mode 100644
index 00000000000..55115a6d459
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_info_baked.cc
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Intentionally empty for compiling shader builder.
+ */
diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc
index 1648446d21b..937f49ccaec 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.cc
+++ b/source/blender/gpu/intern/gpu_shader_interface.cc
@@ -74,6 +74,8 @@ void ShaderInterface::sort_inputs()
sort_input_list(MutableSpan<ShaderInput>(inputs_, attr_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_, ubo_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_));
+ sort_input_list(
+ MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_));
}
void ShaderInterface::debug_print()
diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh
index 12a7ffabcc6..7f99619c98c 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.hh
+++ b/source/blender/gpu/intern/gpu_shader_interface.hh
@@ -34,6 +34,7 @@
#include "BLI_utildefines.h"
#include "GPU_shader.h"
+#include "gpu_shader_create_info.hh"
namespace blender::gpu {
@@ -50,6 +51,7 @@ typedef struct ShaderInput {
* Base class which is then specialized for each implementation (GL, VK, ...).
*/
class ShaderInterface {
+ friend shader::ShaderCreateInfo;
/* TODO(fclem): should be protected. */
public:
/** Flat array. In this order: Attributes, Ubos, Uniforms. */
@@ -72,9 +74,10 @@ class ShaderInterface {
public:
ShaderInterface();
+ ShaderInterface(const shader::ShaderCreateInfo &info);
virtual ~ShaderInterface();
- void debug_print(void);
+ void debug_print();
inline const ShaderInput *attr_get(const char *name) const
{
@@ -104,6 +107,10 @@ class ShaderInterface {
{
return input_lookup(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_, name);
}
+ inline const ShaderInput *ssbo_get(const int binding) const
+ {
+ return input_lookup(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_, binding);
+ }
inline const char *input_name_get(const ShaderInput *input) const
{
@@ -129,20 +136,24 @@ class ShaderInterface {
static inline const char *builtin_uniform_block_name(GPUUniformBlockBuiltin u);
inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const;
+ inline void copy_input_name(ShaderInput *input,
+ const StringRefNull &name,
+ char *name_buffer,
+ uint32_t &name_buffer_offset) const;
/**
* Finalize interface construction by sorting the #ShaderInputs for faster lookups.
*/
- void sort_inputs(void);
+ void sort_inputs();
private:
inline const ShaderInput *input_lookup(const ShaderInput *const inputs,
- const uint inputs_len,
+ uint inputs_len,
const char *name) const;
inline const ShaderInput *input_lookup(const ShaderInput *const inputs,
- const uint inputs_len,
- const int binding) const;
+ uint inputs_len,
+ int binding) const;
};
inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u)
@@ -182,11 +193,11 @@ inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u)
case GPU_UNIFORM_COLOR:
return "color";
case GPU_UNIFORM_BASE_INSTANCE:
- return "baseInstance";
+ return "gpu_BaseInstance";
case GPU_UNIFORM_RESOURCE_CHUNK:
- return "resourceChunk";
+ return "drw_resourceChunk";
case GPU_UNIFORM_RESOURCE_ID:
- return "resourceId";
+ return "drw_ResourceID";
case GPU_UNIFORM_SRGB_TRANSFORM:
return "srgbTarget";
@@ -204,6 +215,13 @@ inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBu
return "modelBlock";
case GPU_UNIFORM_BLOCK_INFO:
return "infoBlock";
+
+ case GPU_UNIFORM_BLOCK_DRW_VIEW:
+ return "drw_view";
+ case GPU_UNIFORM_BLOCK_DRW_MODEL:
+ return "drw_matrices";
+ case GPU_UNIFORM_BLOCK_DRW_INFOS:
+ return "drw_infos";
default:
return NULL;
}
@@ -216,8 +234,12 @@ inline uint32_t ShaderInterface::set_input_name(ShaderInput *input,
{
/* remove "[0]" from array name */
if (name[name_len - 1] == ']') {
- name[name_len - 3] = '\0';
- name_len -= 3;
+ for (; name_len > 1; name_len--) {
+ if (name[name_len] == '[') {
+ name[name_len] = '\0';
+ break;
+ }
+ }
}
input->name_offset = (uint32_t)(name - name_buffer_);
@@ -225,6 +247,17 @@ inline uint32_t ShaderInterface::set_input_name(ShaderInput *input,
return name_len + 1; /* include NULL terminator */
}
+inline void ShaderInterface::copy_input_name(ShaderInput *input,
+ const StringRefNull &name,
+ char *name_buffer,
+ uint32_t &name_buffer_offset) const
+{
+ uint32_t name_len = name.size();
+ /* Copy include NULL terminator. */
+ memcpy(name_buffer + name_buffer_offset, name.c_str(), name_len + 1);
+ name_buffer_offset += set_input_name(input, name_buffer + name_buffer_offset, name_len);
+}
+
inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const inputs,
const uint inputs_len,
const char *name) const
diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh
index 65720e457d8..3bfecdefba7 100644
--- a/source/blender/gpu/intern/gpu_shader_private.hh
+++ b/source/blender/gpu/intern/gpu_shader_private.hh
@@ -24,9 +24,12 @@
#include "BLI_string_ref.hh"
#include "GPU_shader.h"
+#include "gpu_shader_create_info.hh"
#include "gpu_shader_interface.hh"
#include "gpu_vertex_buffer_private.hh"
+#include <string>
+
namespace blender {
namespace gpu {
@@ -53,35 +56,40 @@ class Shader {
virtual void geometry_shader_from_glsl(MutableSpan<const char *> sources) = 0;
virtual void fragment_shader_from_glsl(MutableSpan<const char *> sources) = 0;
virtual void compute_shader_from_glsl(MutableSpan<const char *> sources) = 0;
- virtual bool finalize(void) = 0;
+ virtual bool finalize(const shader::ShaderCreateInfo *info = nullptr) = 0;
virtual void transform_feedback_names_set(Span<const char *> name_list,
- const eGPUShaderTFBType geom_type) = 0;
+ eGPUShaderTFBType geom_type) = 0;
virtual bool transform_feedback_enable(GPUVertBuf *) = 0;
- virtual void transform_feedback_disable(void) = 0;
+ virtual void transform_feedback_disable() = 0;
- virtual void bind(void) = 0;
- virtual void unbind(void) = 0;
+ virtual void bind() = 0;
+ virtual void unbind() = 0;
virtual void uniform_float(int location, int comp_len, int array_size, const float *data) = 0;
virtual void uniform_int(int location, int comp_len, int array_size, const int *data) = 0;
virtual void vertformat_from_shader(GPUVertFormat *) const = 0;
+ std::string defines_declare(const shader::ShaderCreateInfo &info) const;
+ virtual std::string resources_declare(const shader::ShaderCreateInfo &info) const = 0;
+ virtual std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const = 0;
+ virtual std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const = 0;
+ virtual std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const = 0;
+ virtual std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const = 0;
+ virtual std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const = 0;
+
/* DEPRECATED: Kept only because of BGL API. */
- virtual int program_handle_get(void) const = 0;
+ virtual int program_handle_get() const = 0;
- inline const char *const name_get(void) const
+ inline const char *const name_get() const
{
return name;
};
protected:
- void print_log(Span<const char *> sources,
- char *log,
- const char *stage,
- const bool error,
- GPULogParser *parser);
+ void print_log(
+ Span<const char *> sources, char *log, const char *stage, bool error, GPULogParser *parser);
};
/* Syntactic sugar. */
@@ -137,4 +145,4 @@ class GPULogParser {
} // namespace blender
/* XXX do not use it. Special hack to use OCIO with batch API. */
-GPUShader *immGetShader(void);
+GPUShader *immGetShader();
diff --git a/source/blender/gpu/intern/gpu_shader_shared_utils.h b/source/blender/gpu/intern/gpu_shader_shared_utils.h
new file mode 100644
index 00000000000..0d283fb1e66
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_shared_utils.h
@@ -0,0 +1,116 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Glue definition to make shared declaration of struct & functions work in both C / C++ and GLSL.
+ * We use the same vector and matrix types as Blender C++. Some math functions are defined to use
+ * the float version to match the GLSL syntax.
+ * This file can be used for C & C++ code and the syntax used should follow the same rules.
+ * Some preprocessing is done by the GPU back-end to make it GLSL compatible.
+ *
+ * IMPORTANT:
+ * - Always use `u` suffix for enum values. GLSL do not support implicit cast.
+ * - Define all values. This is in order to simplify custom pre-processor code.
+ * - (C++ only) Always use `uint32_t` as underlying type (`enum eMyEnum : uint32_t`).
+ * - (C only) do NOT use the enum type inside UBO/SSBO structs and use `uint` instead.
+ * - Use float suffix by default for float literals to avoid double promotion in C++.
+ * - Pack one float or int after a vec3/ivec3 to fulfill alignment rules.
+ *
+ * NOTE: Due to alignment restriction and buggy drivers, do not try to use mat3 inside structs.
+ * NOTE: (UBO only) Do not use arrays of float. They are padded to arrays of vec4 and are not worth
+ * it. This does not apply to SSBO.
+ *
+ * IMPORTANT: Do not forget to align mat4, vec3 and vec4 to 16 bytes, and vec2 to 8 bytes.
+ *
+ * NOTE: You can use bool type using bool1 a int boolean type matching the GLSL type.
+ */
+
+#ifdef GPU_SHADER
+# define BLI_STATIC_ASSERT_ALIGN(type_, align_)
+# define BLI_STATIC_ASSERT_SIZE(type_, size_)
+# define static
+# define inline
+# define cosf cos
+# define sinf sin
+# define tanf tan
+# define acosf acos
+# define asinf asin
+# define atanf atan
+# define floorf floor
+# define ceilf ceil
+# define sqrtf sqrt
+
+# define float2 vec2
+# define float3 vec3
+# define float4 vec4
+# define float4x4 mat4
+# define int2 ivec2
+# define int3 ivec3
+# define int4 ivec4
+# define uint2 uvec2
+# define uint3 uvec3
+# define uint4 uvec4
+# define bool1 bool
+# define bool2 bvec2
+# define bool3 bvec3
+# define bool4 bvec4
+
+#else /* C / C++ */
+# pragma once
+
+# include "BLI_assert.h"
+
+# ifdef __cplusplus
+# include "BLI_float4x4.hh"
+# include "BLI_math_vec_types.hh"
+using blender::float2;
+using blender::float3;
+using blender::float4;
+using blender::float4x4;
+using blender::int2;
+using blender::int3;
+using blender::int4;
+using blender::uint2;
+using blender::uint3;
+using blender::uint4;
+using bool1 = int;
+using bool2 = blender::int2;
+using bool3 = blender::int3;
+using bool4 = blender::int4;
+
+# else /* C */
+typedef float float2[2];
+typedef float float3[3];
+typedef float float4[4];
+typedef float float4x4[4][4];
+typedef int int2[2];
+typedef int int3[2];
+typedef int int4[4];
+typedef uint uint2[2];
+typedef uint uint3[3];
+typedef uint uint4[4];
+typedef int bool1;
+typedef int bool2[2];
+typedef int bool3[2];
+typedef int bool4[4];
+# endif
+
+#endif
diff --git a/source/blender/gpu/intern/gpu_state_private.hh b/source/blender/gpu/intern/gpu_state_private.hh
index b96b71a7ac4..864b7d0446a 100644
--- a/source/blender/gpu/intern/gpu_state_private.hh
+++ b/source/blender/gpu/intern/gpu_state_private.hh
@@ -62,7 +62,7 @@ union GPUState {
uint32_t polygon_smooth : 1;
uint32_t line_smooth : 1;
};
- /* Here to allow fast bitwise ops. */
+ /* Here to allow fast bit-wise ops. */
uint64_t data;
};
@@ -159,18 +159,18 @@ class StateManager {
StateManager();
virtual ~StateManager(){};
- virtual void apply_state(void) = 0;
- virtual void force_state(void) = 0;
+ virtual void apply_state() = 0;
+ virtual void force_state() = 0;
virtual void issue_barrier(eGPUBarrier barrier_bits) = 0;
virtual void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) = 0;
virtual void texture_unbind(Texture *tex) = 0;
- virtual void texture_unbind_all(void) = 0;
+ virtual void texture_unbind_all() = 0;
virtual void image_bind(Texture *tex, int unit) = 0;
virtual void image_unbind(Texture *tex) = 0;
- virtual void image_unbind_all(void) = 0;
+ virtual void image_unbind_all() = 0;
virtual void texture_unpack_row_length_set(uint len) = 0;
};
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index c7e2043b790..1b8b28bf04c 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -190,7 +190,7 @@ using namespace blender::gpu;
/* ------ Memory Management ------ */
-uint GPU_texture_memory_usage_get(void)
+uint GPU_texture_memory_usage_get()
{
/* TODO(fclem): Do that inside the new Texture class. */
return 0;
@@ -424,7 +424,7 @@ void GPU_texture_unbind(GPUTexture *tex_)
Context::get()->state_manager->texture_unbind(tex);
}
-void GPU_texture_unbind_all(void)
+void GPU_texture_unbind_all()
{
Context::get()->state_manager->texture_unbind_all();
}
@@ -439,7 +439,7 @@ void GPU_texture_image_unbind(GPUTexture *tex)
Context::get()->state_manager->image_unbind(unwrap(tex));
}
-void GPU_texture_image_unbind_all(void)
+void GPU_texture_image_unbind_all()
{
Context::get()->state_manager->image_unbind_all();
}
@@ -613,7 +613,7 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *r_size)
* Override texture sampler state for one sampler unit only.
* \{ */
-void GPU_samplers_update(void)
+void GPU_samplers_update()
{
GPUBackend::get()->samplers_update();
}
diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh
index 19d83366e6f..73b59b9f06f 100644
--- a/source/blender/gpu/intern/gpu_texture_private.hh
+++ b/source/blender/gpu/intern/gpu_texture_private.hh
@@ -123,7 +123,7 @@ class Texture {
bool init_cubemap(int w, int layers, eGPUTextureFormat format);
bool init_buffer(GPUVertBuf *vbo, eGPUTextureFormat format);
- virtual void generate_mipmap(void) = 0;
+ virtual void generate_mipmap() = 0;
virtual void copy_to(Texture *tex) = 0;
virtual void clear(eGPUDataFormat format, const void *data) = 0;
virtual void swizzle_set(const char swizzle_mask[4]) = 0;
@@ -138,17 +138,17 @@ class Texture {
int mip, int offset[3], int extent[3], eGPUDataFormat format, const void *data) = 0;
/* TODO(fclem): Legacy. Should be removed at some point. */
- virtual uint gl_bindcode_get(void) const = 0;
+ virtual uint gl_bindcode_get() const = 0;
- int width_get(void) const
+ int width_get() const
{
return w_;
}
- int height_get(void) const
+ int height_get() const
{
return h_;
}
- int depth_get(void) const
+ int depth_get() const
{
return d_;
}
@@ -188,7 +188,7 @@ class Texture {
}
/* Return number of dimension taking the array type into account. */
- int dimensions_count(void) const
+ int dimensions_count() const
{
const int array = (type_ & GPU_TEXTURE_ARRAY) ? 1 : 0;
switch (type_ & ~GPU_TEXTURE_ARRAY) {
@@ -205,7 +205,7 @@ class Texture {
}
}
/* Return number of array layer (or face layer) for texture array or 1 for the others. */
- int layer_count(void) const
+ int layer_count() const
{
switch (type_) {
case GPU_TEXTURE_1D_ARRAY:
@@ -218,15 +218,15 @@ class Texture {
}
}
- eGPUTextureFormat format_get(void) const
+ eGPUTextureFormat format_get() const
{
return format_;
}
- eGPUTextureFormatFlag format_flag_get(void) const
+ eGPUTextureFormatFlag format_flag_get() const
{
return format_flag_;
}
- eGPUTextureType type_get(void) const
+ eGPUTextureType type_get() const
{
return type_;
}
@@ -248,7 +248,7 @@ class Texture {
}
protected:
- virtual bool init_internal(void) = 0;
+ virtual bool init_internal() = 0;
virtual bool init_internal(GPUVertBuf *vbo) = 0;
};
diff --git a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
index e8fc1343eaf..018b85c865e 100644
--- a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
@@ -54,7 +54,7 @@ class UniformBuf {
virtual void update(const void *data) = 0;
virtual void bind(int slot) = 0;
- virtual void unbind(void) = 0;
+ virtual void unbind() = 0;
/** Used to defer data upload at drawing time.
* This is useful if the thread has no context bound.
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index 5ed9648387f..dba31f501f2 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.cc
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc
@@ -144,6 +144,12 @@ void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts_,
unwrap(verts_)->init(format, usage);
}
+void GPU_vertbuf_init_build_on_device(GPUVertBuf *verts, GPUVertFormat *format, uint v_len)
+{
+ GPU_vertbuf_init_with_format_ex(verts, format, GPU_USAGE_DEVICE_ONLY);
+ GPU_vertbuf_data_alloc(verts, v_len);
+}
+
GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts_)
{
return wrap(unwrap(verts_)->duplicate());
@@ -313,6 +319,11 @@ GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts)
return unwrap(verts)->flag;
}
+void GPU_vertbuf_tag_dirty(GPUVertBuf *verts)
+{
+ unwrap(verts)->flag |= GPU_VERTBUF_DATA_DIRTY;
+}
+
uint GPU_vertbuf_get_memory_usage()
{
return VertBuf::memory_usage;
@@ -323,12 +334,17 @@ void GPU_vertbuf_use(GPUVertBuf *verts)
unwrap(verts)->upload();
}
+void GPU_vertbuf_wrap_handle(GPUVertBuf *verts, uint64_t handle)
+{
+ unwrap(verts)->wrap_handle(handle);
+}
+
void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding)
{
unwrap(verts)->bind_as_ssbo(binding);
}
-void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data)
+void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data)
{
unwrap(verts)->update_sub(start, len, data);
}
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
index 9531c2c1a5f..97514b382b1 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
@@ -60,34 +60,36 @@ class VertBuf {
virtual ~VertBuf();
void init(const GPUVertFormat *format, GPUUsageType usage);
- void clear(void);
+ void clear();
/* Data management. */
void allocate(uint vert_len);
void resize(uint vert_len);
- void upload(void);
+ void upload();
virtual void bind_as_ssbo(uint binding) = 0;
- VertBuf *duplicate(void);
+ virtual void wrap_handle(uint64_t handle) = 0;
+
+ VertBuf *duplicate();
/* Size of the data allocated. */
- size_t size_alloc_get(void) const
+ size_t size_alloc_get() const
{
BLI_assert(format.packed);
return vertex_alloc * format.stride;
}
/* Size of the data uploaded to the GPU. */
- size_t size_used_get(void) const
+ size_t size_used_get() const
{
BLI_assert(format.packed);
return vertex_len * format.stride;
}
- void reference_add(void)
+ void reference_add()
{
handle_refcount_++;
}
- void reference_remove(void)
+ void reference_remove()
{
BLI_assert(handle_refcount_ > 0);
handle_refcount_--;
@@ -96,15 +98,15 @@ class VertBuf {
}
}
- virtual void update_sub(uint start, uint len, void *data) = 0;
+ virtual void update_sub(uint start, uint len, const void *data) = 0;
virtual const void *read() const = 0;
virtual void *unmap(const void *mapped_data) const = 0;
protected:
- virtual void acquire_data(void) = 0;
- virtual void resize_data(void) = 0;
- virtual void release_data(void) = 0;
- virtual void upload_data(void) = 0;
+ virtual void acquire_data() = 0;
+ virtual void resize_data() = 0;
+ virtual void release_data() = 0;
+ virtual void upload_data() = 0;
virtual void duplicate_data(VertBuf *dst) = 0;
};
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index c604859fa94..6d8ff8e7088 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -137,19 +137,25 @@ struct DRWData **GPU_viewport_data_get(GPUViewport *viewport)
static void gpu_viewport_textures_create(GPUViewport *viewport)
{
int *size = viewport->size;
+ float empty_pixel_fl[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ uchar empty_pixel_u[4] = {0, 0, 0, 0};
if (viewport->color_render_tx[0] == NULL) {
viewport->color_render_tx[0] = GPU_texture_create_2d(
"dtxl_color", UNPACK2(size), 1, GPU_RGBA16F, NULL);
+ GPU_texture_clear(viewport->color_render_tx[0], GPU_DATA_FLOAT, empty_pixel_fl);
viewport->color_overlay_tx[0] = GPU_texture_create_2d(
"dtxl_color_overlay", UNPACK2(size), 1, GPU_SRGB8_A8, NULL);
+ GPU_texture_clear(viewport->color_overlay_tx[0], GPU_DATA_UBYTE, empty_pixel_u);
}
if ((viewport->flag & GPU_VIEWPORT_STEREO) != 0 && viewport->color_render_tx[1] == NULL) {
viewport->color_render_tx[1] = GPU_texture_create_2d(
"dtxl_color_stereo", UNPACK2(size), 1, GPU_RGBA16F, NULL);
+ GPU_texture_clear(viewport->color_render_tx[1], GPU_DATA_FLOAT, empty_pixel_fl);
viewport->color_overlay_tx[1] = GPU_texture_create_2d(
"dtxl_color_overlay_stereo", UNPACK2(size), 1, GPU_SRGB8_A8, NULL);
+ GPU_texture_clear(viewport->color_overlay_tx[1], GPU_DATA_UBYTE, empty_pixel_u);
}
/* Can be shared with GPUOffscreen. */
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 7bb88894b81..92d180f1140 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -240,12 +240,14 @@ static void detect_workarounds()
GLContext::unused_fb_slot_workaround = true;
/* Turn off extensions. */
GCaps.shader_image_load_store_support = false;
+ GCaps.shader_storage_buffer_objects_support = false;
GLContext::base_instance_support = false;
GLContext::clear_texture_support = false;
GLContext::copy_image_support = false;
GLContext::debug_layer_support = false;
GLContext::direct_state_access_support = false;
GLContext::fixed_restart_index_support = false;
+ GLContext::geometry_shader_invocations = false;
GLContext::multi_bind_support = false;
GLContext::multi_draw_indirect_support = false;
GLContext::shader_draw_parameters_support = false;
@@ -418,6 +420,12 @@ static void detect_workarounds()
strstr(renderer, "HD Graphics 4000")) {
GLContext::generate_mipmap_workaround = true;
}
+
+ /* Buggy interface query functions cause crashes when handling SSBOs (T93680) */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY) &&
+ (strstr(renderer, "HD Graphics 4400") || strstr(renderer, "HD Graphics 4600"))) {
+ GCaps.shader_storage_buffer_objects_support = false;
+ }
} // namespace blender::gpu
/** Internal capabilities. */
@@ -434,6 +442,8 @@ bool GLContext::clear_texture_support = false;
bool GLContext::copy_image_support = false;
bool GLContext::debug_layer_support = false;
bool GLContext::direct_state_access_support = false;
+bool GLContext::explicit_location_support = false;
+bool GLContext::geometry_shader_invocations = false;
bool GLContext::fixed_restart_index_support = false;
bool GLContext::multi_bind_support = false;
bool GLContext::multi_draw_indirect_support = false;
@@ -492,6 +502,8 @@ void GLBackend::capabilities_init()
GLContext::copy_image_support = GLEW_ARB_copy_image;
GLContext::debug_layer_support = GLEW_VERSION_4_3 || GLEW_KHR_debug || GLEW_ARB_debug_output;
GLContext::direct_state_access_support = GLEW_ARB_direct_state_access;
+ GLContext::explicit_location_support = GLEW_VERSION_4_3;
+ GLContext::geometry_shader_invocations = GLEW_ARB_gpu_shader5;
GLContext::fixed_restart_index_support = GLEW_ARB_ES3_compatibility;
GLContext::multi_bind_support = GLEW_ARB_multi_bind;
GLContext::multi_draw_indirect_support = GLEW_ARB_multi_draw_indirect;
diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh
index e9dcdffced0..abac9174d4a 100644
--- a/source/blender/gpu/opengl/gl_backend.hh
+++ b/source/blender/gpu/opengl/gl_backend.hh
@@ -62,12 +62,12 @@ class GLBackend : public GPUBackend {
GLBackend::platform_exit();
}
- static GLBackend *get(void)
+ static GLBackend *get()
{
return static_cast<GLBackend *>(GPUBackend::get());
}
- void samplers_update(void) override
+ void samplers_update() override
{
GLTexture::samplers_update();
};
@@ -77,7 +77,7 @@ class GLBackend : public GPUBackend {
return new GLContext(ghost_window, shared_orphan_list_);
};
- Batch *batch_alloc(void) override
+ Batch *batch_alloc() override
{
return new GLBatch();
};
@@ -92,12 +92,12 @@ class GLBackend : public GPUBackend {
return new GLFrameBuffer(name);
};
- IndexBuf *indexbuf_alloc(void) override
+ IndexBuf *indexbuf_alloc() override
{
return new GLIndexBuf();
};
- QueryPool *querypool_alloc(void) override
+ QueryPool *querypool_alloc() override
{
return new GLQueryPool();
};
@@ -117,12 +117,12 @@ class GLBackend : public GPUBackend {
return new GLUniformBuf(size, name);
};
- VertBuf *vertbuf_alloc(void) override
+ VertBuf *vertbuf_alloc() override
{
return new GLVertBuf();
};
- GLSharedOrphanLists &shared_orphan_list_get(void)
+ GLSharedOrphanLists &shared_orphan_list_get()
{
return shared_orphan_list_;
};
@@ -134,10 +134,10 @@ class GLBackend : public GPUBackend {
}
private:
- static void platform_init(void);
- static void platform_exit(void);
+ static void platform_init();
+ static void platform_exit();
- static void capabilities_init(void);
+ static void capabilities_init();
};
} // namespace gpu
diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh
index a2b5f8fc15e..4e6e25cdb0f 100644
--- a/source/blender/gpu/opengl/gl_batch.hh
+++ b/source/blender/gpu/opengl/gl_batch.hh
@@ -91,15 +91,15 @@ class GLVaoCache {
*/
void insert(const GLShaderInterface *interface, GLuint vao_id);
void remove(const GLShaderInterface *interface);
- void clear(void);
+ void clear();
private:
- void init(void);
+ void init();
/**
* The #GLVaoCache object is only valid for one #GLContext.
* Reset the cache if trying to draw in another context;.
*/
- void context_check(void);
+ void context_check();
};
class GLBatch : public Batch {
@@ -113,7 +113,7 @@ class GLBatch : public Batch {
/* Convenience getters. */
- GLIndexBuf *elem_(void) const
+ GLIndexBuf *elem_() 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 40107ca9ef7..dd22418972b 100644
--- a/source/blender/gpu/opengl/gl_context.hh
+++ b/source/blender/gpu/opengl/gl_context.hh
@@ -50,7 +50,7 @@ class GLSharedOrphanLists {
Vector<GLuint> buffers;
public:
- void orphans_clear(void);
+ void orphans_clear();
};
class GLContext : public Context {
@@ -69,6 +69,8 @@ class GLContext : public Context {
static bool copy_image_support;
static bool debug_layer_support;
static bool direct_state_access_support;
+ static bool explicit_location_support;
+ static bool geometry_shader_invocations;
static bool fixed_restart_index_support;
static bool multi_bind_support;
static bool multi_draw_indirect_support;
@@ -112,11 +114,11 @@ class GLContext : public Context {
static void check_error(const char *info);
- void activate(void) override;
- void deactivate(void) override;
+ void activate() override;
+ void deactivate() override;
- void flush(void) override;
- void finish(void) override;
+ void flush() override;
+ void finish() override;
void memory_statistics_get(int *total_mem, int *free_mem) override;
@@ -142,11 +144,11 @@ class GLContext : public Context {
void vao_cache_unregister(GLVaoCache *cache);
void debug_group_begin(const char *name, int index) override;
- void debug_group_end(void) override;
+ void debug_group_end() override;
private:
static void orphans_add(Vector<GLuint> &orphan_list, std::mutex &list_mutex, GLuint id);
- void orphans_clear(void);
+ void orphans_clear();
MEM_CXX_CLASS_ALLOC_FUNCS("GLContext")
};
diff --git a/source/blender/gpu/opengl/gl_debug.hh b/source/blender/gpu/opengl/gl_debug.hh
index 3964e5da550..7917c05f94b 100644
--- a/source/blender/gpu/opengl/gl_debug.hh
+++ b/source/blender/gpu/opengl/gl_debug.hh
@@ -91,14 +91,14 @@ void check_gl_resources(const char *info);
/**
* This function needs to be called once per context.
*/
-void init_gl_callbacks(void);
+void init_gl_callbacks();
/**
* 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 init_debug_layer();
void object_label(GLenum type, GLuint object, const char *name);
diff --git a/source/blender/gpu/opengl/gl_drawlist.hh b/source/blender/gpu/opengl/gl_drawlist.hh
index 6f80fdd5a8a..bb7b89ca707 100644
--- a/source/blender/gpu/opengl/gl_drawlist.hh
+++ b/source/blender/gpu/opengl/gl_drawlist.hh
@@ -48,10 +48,10 @@ class GLDrawList : public DrawList {
~GLDrawList();
void append(GPUBatch *batch, int i_first, int i_count) override;
- void submit(void) override;
+ void submit() override;
private:
- void init(void);
+ void init();
/** Batch for which we are recording commands for. */
GLBatch *batch_;
diff --git a/source/blender/gpu/opengl/gl_framebuffer.hh b/source/blender/gpu/opengl/gl_framebuffer.hh
index 21b5931440d..9ebe549efe7 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.hh
+++ b/source/blender/gpu/opengl/gl_framebuffer.hh
@@ -110,12 +110,12 @@ class GLFrameBuffer : public FrameBuffer {
int dst_offset_x,
int dst_offset_y) override;
- void apply_state(void);
+ void apply_state();
private:
- void init(void);
- void update_attachments(void);
- void update_drawbuffers(void);
+ void init();
+ void update_attachments();
+ void update_drawbuffers();
MEM_CXX_CLASS_ALLOC_FUNCS("GLFrameBuffer");
};
diff --git a/source/blender/gpu/opengl/gl_immediate.hh b/source/blender/gpu/opengl/gl_immediate.hh
index b42f439f9ec..235bc1254f2 100644
--- a/source/blender/gpu/opengl/gl_immediate.hh
+++ b/source/blender/gpu/opengl/gl_immediate.hh
@@ -58,21 +58,21 @@ class GLImmediate : public Immediate {
GLImmediate();
~GLImmediate();
- uchar *begin(void) override;
- void end(void) override;
+ uchar *begin() override;
+ void end() override;
private:
- GLuint &vbo_id(void)
+ GLuint &vbo_id()
{
return strict_vertex_len ? buffer_strict.vbo_id : buffer.vbo_id;
};
- size_t &buffer_offset(void)
+ size_t &buffer_offset()
{
return strict_vertex_len ? buffer_strict.buffer_offset : buffer.buffer_offset;
};
- size_t &buffer_size(void)
+ size_t &buffer_size()
{
return strict_vertex_len ? buffer_strict.buffer_size : buffer.buffer_size;
};
diff --git a/source/blender/gpu/opengl/gl_index_buffer.cc b/source/blender/gpu/opengl/gl_index_buffer.cc
index e305f765ad9..82bab460ae3 100644
--- a/source/blender/gpu/opengl/gl_index_buffer.cc
+++ b/source/blender/gpu/opengl/gl_index_buffer.cc
@@ -81,4 +81,14 @@ bool GLIndexBuf::is_active() const
return ibo_id_ == active_ibo_id;
}
+void GLIndexBuf::upload_data()
+{
+ bind();
+}
+
+void GLIndexBuf::update_sub(uint start, uint len, const void *data)
+{
+ glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, start, len, data);
+}
+
} // namespace blender::gpu
diff --git a/source/blender/gpu/opengl/gl_index_buffer.hh b/source/blender/gpu/opengl/gl_index_buffer.hh
index 0dbdaa6d398..aaec10d43b3 100644
--- a/source/blender/gpu/opengl/gl_index_buffer.hh
+++ b/source/blender/gpu/opengl/gl_index_buffer.hh
@@ -42,7 +42,7 @@ class GLIndexBuf : public IndexBuf {
public:
~GLIndexBuf();
- void bind(void);
+ void bind();
void bind_as_ssbo(uint binding) override;
const uint32_t *read() const override;
@@ -56,11 +56,15 @@ class GLIndexBuf : public IndexBuf {
return (GLushort *)0 + additional_vertex_offset;
}
- GLuint restart_index(void) const
+ GLuint restart_index() const
{
return (index_type_ == GPU_INDEX_U16) ? 0xFFFFu : 0xFFFFFFFFu;
}
+ void upload_data() override;
+
+ void update_sub(uint start, uint len, const void *data) override;
+
private:
bool is_active() const;
diff --git a/source/blender/gpu/opengl/gl_query.hh b/source/blender/gpu/opengl/gl_query.hh
index b4f971f45ee..2848a7abb8b 100644
--- a/source/blender/gpu/opengl/gl_query.hh
+++ b/source/blender/gpu/opengl/gl_query.hh
@@ -50,8 +50,8 @@ class GLQueryPool : public QueryPool {
void init(GPUQueryType type) override;
- void begin_query(void) override;
- void end_query(void) override;
+ void begin_query() override;
+ void end_query() override;
void get_occlusion_result(MutableSpan<uint32_t> r_values) override;
};
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index cd2c3caad46..d1ef6448791 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -38,6 +38,7 @@
using namespace blender;
using namespace blender::gpu;
+using namespace blender::gpu::shader;
/* -------------------------------------------------------------------- */
/** \name Creation / Destruction
@@ -47,7 +48,7 @@ GLShader::GLShader(const char *name) : Shader(name)
{
#if 0 /* Would be nice to have, but for now the Deferred compilation \
* does not have a GPUContext. */
- BLI_assert(GLContext::get() != NULL);
+ BLI_assert(GLContext::get() != nullptr);
#endif
shader_program_ = glCreateProgram();
@@ -58,7 +59,7 @@ GLShader::~GLShader()
{
#if 0 /* Would be nice to have, but for now the Deferred compilation \
* does not have a GPUContext. */
- BLI_assert(GLContext::get() != NULL);
+ BLI_assert(GLContext::get() != nullptr);
#endif
/* Invalid handles are silently ignored. */
glDeleteShader(vert_shader_);
@@ -71,20 +72,500 @@ GLShader::~GLShader()
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Create Info
+ * \{ */
+
+static const char *to_string(const Interpolation &interp)
+{
+ switch (interp) {
+ case Interpolation::SMOOTH:
+ return "smooth";
+ case Interpolation::FLAT:
+ return "flat";
+ case Interpolation::NO_PERSPECTIVE:
+ return "noperspective";
+ default:
+ return "unkown";
+ }
+}
+
+static const char *to_string(const Type &type)
+{
+ switch (type) {
+ case Type::FLOAT:
+ return "float";
+ case Type::VEC2:
+ return "vec2";
+ case Type::VEC3:
+ return "vec3";
+ case Type::VEC4:
+ return "vec4";
+ case Type::MAT3:
+ return "mat3";
+ case Type::MAT4:
+ return "mat4";
+ case Type::UINT:
+ return "uint";
+ case Type::UVEC2:
+ return "uvec2";
+ case Type::UVEC3:
+ return "uvec3";
+ case Type::UVEC4:
+ return "uvec4";
+ case Type::INT:
+ return "int";
+ case Type::IVEC2:
+ return "ivec2";
+ case Type::IVEC3:
+ return "ivec3";
+ case Type::IVEC4:
+ return "ivec4";
+ case Type::BOOL:
+ return "bool";
+ default:
+ return "unkown";
+ }
+}
+
+static const char *to_string(const PrimitiveIn &layout)
+{
+ switch (layout) {
+ case PrimitiveIn::POINTS:
+ return "points";
+ case PrimitiveIn::LINES:
+ return "lines";
+ case PrimitiveIn::LINES_ADJACENCY:
+ return "lines_adjacency";
+ case PrimitiveIn::TRIANGLES:
+ return "triangles";
+ case PrimitiveIn::TRIANGLES_ADJACENCY:
+ return "triangles_adjacency";
+ default:
+ return "unknown";
+ }
+}
+
+static const char *to_string(const PrimitiveOut &layout)
+{
+ switch (layout) {
+ case PrimitiveOut::POINTS:
+ return "points";
+ case PrimitiveOut::LINE_STRIP:
+ return "line_strip";
+ case PrimitiveOut::TRIANGLE_STRIP:
+ return "triangle_strip";
+ default:
+ return "unknown";
+ }
+}
+
+static void print_image_type(std::ostream &os,
+ const ImageType &type,
+ const ShaderCreateInfo::Resource::BindType bind_type)
+{
+ switch (type) {
+ case ImageType::INT_BUFFER:
+ case ImageType::INT_1D:
+ case ImageType::INT_1D_ARRAY:
+ case ImageType::INT_2D:
+ case ImageType::INT_2D_ARRAY:
+ case ImageType::INT_3D:
+ case ImageType::INT_CUBE:
+ case ImageType::INT_CUBE_ARRAY:
+ os << "i";
+ break;
+ case ImageType::UINT_BUFFER:
+ case ImageType::UINT_1D:
+ case ImageType::UINT_1D_ARRAY:
+ case ImageType::UINT_2D:
+ case ImageType::UINT_2D_ARRAY:
+ case ImageType::UINT_3D:
+ case ImageType::UINT_CUBE:
+ case ImageType::UINT_CUBE_ARRAY:
+ os << "u";
+ break;
+ default:
+ break;
+ }
+
+ if (bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
+ os << "image";
+ }
+ else {
+ os << "sampler";
+ }
+
+ switch (type) {
+ case ImageType::FLOAT_BUFFER:
+ case ImageType::INT_BUFFER:
+ case ImageType::UINT_BUFFER:
+ os << "Buffer";
+ break;
+ case ImageType::FLOAT_1D:
+ case ImageType::FLOAT_1D_ARRAY:
+ case ImageType::INT_1D:
+ case ImageType::INT_1D_ARRAY:
+ case ImageType::UINT_1D:
+ case ImageType::UINT_1D_ARRAY:
+ os << "1D";
+ break;
+ case ImageType::FLOAT_2D:
+ case ImageType::FLOAT_2D_ARRAY:
+ case ImageType::INT_2D:
+ case ImageType::INT_2D_ARRAY:
+ case ImageType::UINT_2D:
+ case ImageType::UINT_2D_ARRAY:
+ case ImageType::SHADOW_2D:
+ case ImageType::SHADOW_2D_ARRAY:
+ case ImageType::DEPTH_2D:
+ case ImageType::DEPTH_2D_ARRAY:
+ os << "2D";
+ break;
+ case ImageType::FLOAT_3D:
+ case ImageType::INT_3D:
+ case ImageType::UINT_3D:
+ os << "3D";
+ break;
+ case ImageType::FLOAT_CUBE:
+ case ImageType::FLOAT_CUBE_ARRAY:
+ case ImageType::INT_CUBE:
+ case ImageType::INT_CUBE_ARRAY:
+ case ImageType::UINT_CUBE:
+ case ImageType::UINT_CUBE_ARRAY:
+ case ImageType::SHADOW_CUBE:
+ case ImageType::SHADOW_CUBE_ARRAY:
+ case ImageType::DEPTH_CUBE:
+ case ImageType::DEPTH_CUBE_ARRAY:
+ os << "Cube";
+ break;
+ default:
+ break;
+ }
+
+ switch (type) {
+ case ImageType::FLOAT_1D_ARRAY:
+ case ImageType::FLOAT_2D_ARRAY:
+ case ImageType::FLOAT_CUBE_ARRAY:
+ case ImageType::INT_1D_ARRAY:
+ case ImageType::INT_2D_ARRAY:
+ case ImageType::INT_CUBE_ARRAY:
+ case ImageType::UINT_1D_ARRAY:
+ case ImageType::UINT_2D_ARRAY:
+ case ImageType::UINT_CUBE_ARRAY:
+ case ImageType::SHADOW_2D_ARRAY:
+ case ImageType::SHADOW_CUBE_ARRAY:
+ case ImageType::DEPTH_2D_ARRAY:
+ case ImageType::DEPTH_CUBE_ARRAY:
+ os << "Array";
+ break;
+ default:
+ break;
+ }
+
+ switch (type) {
+ case ImageType::SHADOW_2D:
+ case ImageType::SHADOW_2D_ARRAY:
+ case ImageType::SHADOW_CUBE:
+ case ImageType::SHADOW_CUBE_ARRAY:
+ os << "Shadow";
+ break;
+ default:
+ break;
+ }
+ os << " ";
+}
+
+static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifiers)
+{
+ if ((qualifiers & Qualifier::RESTRICT) == Qualifier::RESTRICT) {
+ os << "restrict ";
+ }
+ if ((qualifiers & Qualifier::READ_ONLY) == Qualifier::READ_ONLY) {
+ os << "readonly ";
+ }
+ if ((qualifiers & Qualifier::WRITE_ONLY) == Qualifier::WRITE_ONLY) {
+ os << "writeonly ";
+ }
+ return os;
+}
+
+static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &res)
+{
+ if (GLContext::explicit_location_support) {
+ os << "layout(binding = " << res.slot;
+ if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
+ os << ", " << res.image.format;
+ }
+ else if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) {
+ os << ", std140";
+ }
+ else if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) {
+ os << ", std430";
+ }
+ os << ") ";
+ }
+ else if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) {
+ os << "layout(std140) ";
+ }
+
+ int64_t array_offset;
+ StringRef name_no_array;
+
+ switch (res.bind_type) {
+ case ShaderCreateInfo::Resource::BindType::SAMPLER:
+ os << "uniform ";
+ print_image_type(os, res.sampler.type, res.bind_type);
+ os << res.sampler.name << ";\n";
+ break;
+ case ShaderCreateInfo::Resource::BindType::IMAGE:
+ os << "uniform ";
+ print_qualifier(os, res.image.qualifiers);
+ print_image_type(os, res.image.type, res.bind_type);
+ os << res.image.name << ";\n";
+ break;
+ case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER:
+ array_offset = res.uniformbuf.name.find_first_of("[");
+ name_no_array = (array_offset == -1) ? res.uniformbuf.name :
+ StringRef(res.uniformbuf.name.c_str(), array_offset);
+ os << "uniform " << name_no_array << " { " << res.uniformbuf.type_name << " _"
+ << res.uniformbuf.name << "; };\n";
+ break;
+ case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER:
+ array_offset = res.storagebuf.name.find_first_of("[");
+ name_no_array = (array_offset == -1) ? res.storagebuf.name :
+ StringRef(res.storagebuf.name.c_str(), array_offset);
+ print_qualifier(os, res.storagebuf.qualifiers);
+ os << "buffer ";
+ os << name_no_array << " { " << res.storagebuf.type_name << " _" << res.storagebuf.name
+ << "; };\n";
+ break;
+ }
+}
+
+static void print_resource_alias(std::ostream &os, const ShaderCreateInfo::Resource &res)
+{
+ int64_t array_offset;
+ StringRef name_no_array;
+
+ switch (res.bind_type) {
+ case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER:
+ array_offset = res.uniformbuf.name.find_first_of("[");
+ name_no_array = (array_offset == -1) ? res.uniformbuf.name :
+ StringRef(res.uniformbuf.name.c_str(), array_offset);
+ os << "#define " << name_no_array << " (_" << name_no_array << ")\n";
+ break;
+ case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER:
+ array_offset = res.storagebuf.name.find_first_of("[");
+ name_no_array = (array_offset == -1) ? res.storagebuf.name :
+ StringRef(res.storagebuf.name.c_str(), array_offset);
+ os << "#define " << name_no_array << " (_" << name_no_array << ")\n";
+ break;
+ default:
+ break;
+ }
+}
+
+static void print_interface(std::ostream &os,
+ const StringRefNull &prefix,
+ const StageInterfaceInfo &iface,
+ const StringRefNull &suffix = "")
+{
+ /* TODO(fclem) Move that to interface check. */
+ // if (iface.instance_name.is_empty()) {
+ // BLI_assert_msg(0, "Interfaces require an instance name for geometry shader.");
+ // std::cout << iface.name << ": Interfaces require an instance name for geometry shader.\n";
+ // continue;
+ // }
+ os << prefix << " " << iface.name << "{" << std::endl;
+ for (const StageInterfaceInfo::InOut &inout : iface.inouts) {
+ os << " " << to_string(inout.interp) << " " << to_string(inout.type) << " " << inout.name
+ << ";\n";
+ }
+ os << "}";
+ os << (iface.instance_name.is_empty() ? "" : "\n") << iface.instance_name << suffix << ";\n";
+}
+
+std::string GLShader::resources_declare(const ShaderCreateInfo &info) const
+{
+ std::stringstream ss;
+
+ /* NOTE: We define macros in GLSL to trigger compilation error if the resource names
+ * are reused for local variables. This is to match other backend behavior which needs accessors
+ * macros. */
+
+ ss << "\n/* Pass Resources. */\n";
+ for (const ShaderCreateInfo::Resource &res : info.pass_resources_) {
+ print_resource(ss, res);
+ }
+ for (const ShaderCreateInfo::Resource &res : info.pass_resources_) {
+ print_resource_alias(ss, res);
+ }
+ ss << "\n/* Batch Resources. */\n";
+ for (const ShaderCreateInfo::Resource &res : info.batch_resources_) {
+ print_resource(ss, res);
+ }
+ for (const ShaderCreateInfo::Resource &res : info.batch_resources_) {
+ print_resource_alias(ss, res);
+ }
+ ss << "\n/* Push Constants. */\n";
+ for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) {
+ ss << "uniform " << to_string(uniform.type) << " " << uniform.name;
+ if (uniform.array_size > 0) {
+ ss << "[" << uniform.array_size << "]";
+ }
+ ss << ";\n";
+ }
+ for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) {
+ ss << "#define " << uniform.name << " (" << uniform.name << ")\n";
+ }
+ ss << "\n";
+ return ss.str();
+}
+
+std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) const
+{
+ std::stringstream ss;
+
+ ss << "\n/* Inputs. */\n";
+ for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) {
+ if (GLContext::explicit_location_support) {
+ ss << "layout(location = " << attr.index << ") ";
+ }
+ ss << "in " << to_string(attr.type) << " " << attr.name << ";\n";
+ }
+ ss << "\n/* Interfaces. */\n";
+ for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {
+ print_interface(ss, "out", *iface);
+ }
+ ss << "\n";
+ return ss.str();
+}
+
+std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) const
+{
+ std::stringstream ss;
+ ss << "\n/* Interfaces. */\n";
+ const Vector<StageInterfaceInfo *> &in_interfaces = (info.geometry_source_.is_empty()) ?
+ info.vertex_out_interfaces_ :
+ info.geometry_out_interfaces_;
+ for (const StageInterfaceInfo *iface : in_interfaces) {
+ print_interface(ss, "in", *iface);
+ }
+ ss << "\n/* Outputs. */\n";
+ for (const ShaderCreateInfo::FragOut &output : info.fragment_outputs_) {
+ ss << "layout(location = " << output.index;
+ switch (output.blend) {
+ case DualBlend::SRC_0:
+ ss << ", index = 0";
+ break;
+ case DualBlend::SRC_1:
+ ss << ", index = 1";
+ break;
+ default:
+ break;
+ }
+ ss << ") ";
+ ss << "out " << to_string(output.type) << " " << output.name << ";\n";
+ }
+ ss << "\n";
+ return ss.str();
+}
+
+std::string GLShader::geometry_layout_declare(const ShaderCreateInfo &info) const
+{
+ int max_verts = info.geometry_layout_.max_vertices;
+ int invocations = info.geometry_layout_.invocations;
+
+ if (GLContext::geometry_shader_invocations == false && invocations != -1) {
+ max_verts *= invocations;
+ invocations = -1;
+ }
+
+ std::stringstream ss;
+ ss << "\n/* Geometry Layout. */\n";
+ ss << "layout(" << to_string(info.geometry_layout_.primitive_in);
+ if (invocations != -1) {
+ ss << ", invocations = " << invocations;
+ }
+ ss << ") in;\n";
+
+ ss << "layout(" << to_string(info.geometry_layout_.primitive_out)
+ << ", max_vertices = " << max_verts << ") out;\n";
+ ss << "\n";
+ return ss.str();
+}
+
+static StageInterfaceInfo *find_interface_by_name(const Vector<StageInterfaceInfo *> &ifaces,
+ const StringRefNull &name)
+{
+ for (auto iface : ifaces) {
+ if (iface->name == name) {
+ return iface;
+ }
+ }
+ return nullptr;
+}
+
+std::string GLShader::geometry_interface_declare(const ShaderCreateInfo &info) const
+{
+
+ std::stringstream ss;
+ ss << "\n/* Interfaces. */\n";
+ for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {
+ bool has_matching_output_iface = find_interface_by_name(info.geometry_out_interfaces_,
+ iface->instance_name) != nullptr;
+ const char *suffix = (has_matching_output_iface) ? "_in[]" : "[]";
+ print_interface(ss, "in", *iface, suffix);
+ }
+ ss << "\n";
+ for (const StageInterfaceInfo *iface : info.geometry_out_interfaces_) {
+ bool has_matching_input_iface = find_interface_by_name(info.vertex_out_interfaces_,
+ iface->instance_name) != nullptr;
+ const char *suffix = (has_matching_input_iface) ? "_out" : "";
+ print_interface(ss, "out", *iface, suffix);
+ }
+ ss << "\n";
+ return ss.str();
+}
+
+std::string GLShader::compute_layout_declare(const ShaderCreateInfo &info) const
+{
+ std::stringstream ss;
+ ss << "\n/* Compute Layout. */\n";
+ ss << "layout(local_size_x = " << info.compute_layout_.local_size_x;
+ if (info.compute_layout_.local_size_y != -1) {
+ ss << ", local_size_y = " << info.compute_layout_.local_size_y;
+ }
+ if (info.compute_layout_.local_size_z != -1) {
+ ss << ", local_size_y = " << info.compute_layout_.local_size_z;
+ }
+ ss << ") in;\n";
+ ss << "\n";
+ return ss.str();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Shader stage creation
* \{ */
static char *glsl_patch_default_get()
{
/** Used for shader patching. Init once. */
- static char patch[512] = "\0";
+ static char patch[700] = "\0";
if (patch[0] != '\0') {
return patch;
}
size_t slen = 0;
/* Version need to go first. */
- STR_CONCAT(patch, slen, "#version 330\n");
+ if (GLEW_VERSION_4_3) {
+ STR_CONCAT(patch, slen, "#version 430\n");
+ }
+ else {
+ STR_CONCAT(patch, slen, "#version 330\n");
+ }
/* Enable extensions for features that are not part of our base GLSL version
* don't use an extension for something already available! */
@@ -99,11 +580,31 @@ static char *glsl_patch_default_get()
if (GLContext::shader_draw_parameters_support) {
STR_CONCAT(patch, slen, "#extension GL_ARB_shader_draw_parameters : enable\n");
STR_CONCAT(patch, slen, "#define GPU_ARB_shader_draw_parameters\n");
+ STR_CONCAT(patch, slen, "#define gpu_BaseInstance gl_BaseInstanceARB\n");
+ }
+ if (GLContext::geometry_shader_invocations) {
+ STR_CONCAT(patch, slen, "#extension GL_ARB_gpu_shader5 : enable\n");
+ STR_CONCAT(patch, slen, "#define GPU_ARB_gpu_shader5\n");
}
if (GLContext::texture_cube_map_array_support) {
STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n");
STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n");
}
+ if (GLEW_ARB_conservative_depth) {
+ STR_CONCAT(patch, slen, "#extension GL_ARB_conservative_depth : enable\n");
+ }
+ if (GPU_shader_image_load_store_support()) {
+ STR_CONCAT(patch, slen, "#extension GL_ARB_shader_image_load_store: enable\n");
+ STR_CONCAT(patch, slen, "#extension GL_ARB_shading_language_420pack: enable\n");
+ }
+
+ /* Fallbacks. */
+ if (!GLContext::shader_draw_parameters_support) {
+ STR_CONCAT(patch, slen, "uniform int gpu_BaseInstance;\n");
+ }
+
+ /* Vulkan GLSL compat. */
+ STR_CONCAT(patch, slen, "#define gpu_InstanceIndex (gl_InstanceID + gpu_BaseInstance)\n");
/* Derivative sign can change depending on implementation. */
STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", GLContext::derivative_signs[0]);
@@ -206,7 +707,7 @@ void GLShader::compute_shader_from_glsl(MutableSpan<const char *> sources)
compute_shader_ = this->create_shader_stage(GL_COMPUTE_SHADER, sources);
}
-bool GLShader::finalize()
+bool GLShader::finalize(const shader::ShaderCreateInfo *info)
{
if (compilation_failed_) {
return false;
@@ -225,7 +726,12 @@ bool GLShader::finalize()
return false;
}
- interface = new GLShaderInterface(shader_program_);
+ if (info != nullptr) {
+ interface = new GLShaderInterface(shader_program_, *info);
+ }
+ else {
+ interface = new GLShaderInterface(shader_program_);
+ }
return true;
}
diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh
index 57e33392d9f..a82ab026c16 100644
--- a/source/blender/gpu/opengl/gl_shader.hh
+++ b/source/blender/gpu/opengl/gl_shader.hh
@@ -27,6 +27,7 @@
#include "glew-mx.h"
+#include "gpu_shader_create_info.hh"
#include "gpu_shader_private.hh"
namespace blender {
@@ -36,6 +37,9 @@ namespace gpu {
* Implementation of shader compilation and uniforms handling using OpenGL.
*/
class GLShader : public Shader {
+ friend shader::ShaderCreateInfo;
+ friend shader::StageInterfaceInfo;
+
private:
/** Handle for full program (links shader stages below). */
GLuint shader_program_ = 0;
@@ -58,16 +62,23 @@ class GLShader : public Shader {
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;
+ bool finalize(const shader::ShaderCreateInfo *info = nullptr) override;
+
+ std::string resources_declare(const shader::ShaderCreateInfo &info) const override;
+ std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const override;
+ std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const override;
+ std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const override;
+ std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override;
+ std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const override;
/** Should be called before linking. */
void transform_feedback_names_set(Span<const char *> name_list,
- const eGPUShaderTFBType geom_type) override;
+ eGPUShaderTFBType geom_type) override;
bool transform_feedback_enable(GPUVertBuf *buf) override;
- void transform_feedback_disable(void) override;
+ void transform_feedback_disable() override;
- void bind(void) override;
- void unbind(void) override;
+ void bind() override;
+ void unbind() override;
void uniform_float(int location, int comp_len, int array_size, const float *data) override;
void uniform_int(int location, int comp_len, int array_size, const int *data) override;
@@ -75,7 +86,7 @@ class GLShader : public Shader {
void vertformat_from_shader(GPUVertFormat *format) const override;
/** DEPRECATED: Kept only because of BGL API. */
- int program_handle_get(void) const override;
+ int program_handle_get() const override;
private:
char *glsl_patch_get(GLenum gl_stage);
diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc
index 9900a4e0766..71b908665d3 100644
--- a/source/blender/gpu/opengl/gl_shader_interface.cc
+++ b/source/blender/gpu/opengl/gl_shader_interface.cc
@@ -25,7 +25,9 @@
#include "BLI_bitmap.h"
+#include "gl_backend.hh"
#include "gl_batch.hh"
+#include "gl_context.hh"
#include "gl_shader_interface.hh"
@@ -323,6 +325,160 @@ GLShaderInterface::GLShaderInterface(GLuint program)
this->sort_inputs();
}
+GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info)
+{
+ using namespace blender::gpu::shader;
+
+ attr_len_ = info.vertex_inputs_.size();
+ uniform_len_ = info.push_constants_.size();
+ ubo_len_ = 0;
+ ssbo_len_ = 0;
+
+ Vector<ShaderCreateInfo::Resource> all_resources;
+ all_resources.extend(info.pass_resources_);
+ all_resources.extend(info.batch_resources_);
+
+ for (ShaderCreateInfo::Resource &res : all_resources) {
+ switch (res.bind_type) {
+ case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER:
+ ubo_len_++;
+ break;
+ case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER:
+ ssbo_len_++;
+ break;
+ case ShaderCreateInfo::Resource::BindType::SAMPLER:
+ uniform_len_++;
+ break;
+ case ShaderCreateInfo::Resource::BindType::IMAGE:
+ uniform_len_++;
+ break;
+ }
+ }
+
+ size_t workaround_names_size = 0;
+ Vector<StringRefNull> workaround_uniform_names;
+ auto check_enabled_uniform = [&](const char *uniform_name) {
+ if (glGetUniformLocation(program, uniform_name) != -1) {
+ workaround_uniform_names.append(uniform_name);
+ workaround_names_size += StringRefNull(uniform_name).size() + 1;
+ uniform_len_++;
+ }
+ };
+
+ if (!GLContext::shader_draw_parameters_support) {
+ check_enabled_uniform("gpu_BaseInstance");
+ }
+
+ BLI_assert_msg(ubo_len_ <= 16, "enabled_ubo_mask_ is uint16_t");
+
+ int input_tot_len = attr_len_ + ubo_len_ + uniform_len_ + ssbo_len_;
+ inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__);
+ ShaderInput *input = inputs_;
+
+ name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_ + workaround_names_size,
+ "name_buffer");
+ uint32_t name_buffer_offset = 0;
+
+ /* Necessary to make #glUniform works. TODO(fclem) Remove. */
+ glUseProgram(program);
+
+ /* Attributes */
+ for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) {
+ copy_input_name(input, attr.name, name_buffer_, name_buffer_offset);
+ if (true || !GLContext::explicit_location_support) {
+ input->location = input->binding = glGetAttribLocation(program, attr.name.c_str());
+ }
+ else {
+ input->location = input->binding = attr.index;
+ }
+ enabled_attr_mask_ |= (1 << input->location);
+ input++;
+ }
+
+ /* Uniform Blocks */
+ for (const ShaderCreateInfo::Resource &res : all_resources) {
+ if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) {
+ copy_input_name(input, res.uniformbuf.name, name_buffer_, name_buffer_offset);
+ if (true || !GLContext::explicit_location_support) {
+ input->location = glGetUniformBlockIndex(program, name_buffer_ + input->name_offset);
+ glUniformBlockBinding(program, input->location, res.slot);
+ }
+ input->binding = res.slot;
+ enabled_ubo_mask_ |= (1 << input->binding);
+ input++;
+ }
+ }
+
+ /* Uniforms & samplers & images */
+ for (const ShaderCreateInfo::Resource &res : all_resources) {
+ if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) {
+ copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset);
+ /* Until we make use of explicit uniform location or eliminate all
+ * sampler manually changing. */
+ if (true || !GLContext::explicit_location_support) {
+ input->location = glGetUniformLocation(program, res.sampler.name.c_str());
+ glUniform1i(input->location, res.slot);
+ }
+ input->binding = res.slot;
+ enabled_tex_mask_ |= (1ull << input->binding);
+ input++;
+ }
+ else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
+ copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset);
+ /* Until we make use of explicit uniform location. */
+ if (true || !GLContext::explicit_location_support) {
+ input->location = glGetUniformLocation(program, res.image.name.c_str());
+ glUniform1i(input->location, res.slot);
+ }
+ input->binding = res.slot;
+ enabled_ima_mask_ |= (1 << input->binding);
+ input++;
+ }
+ }
+ for (const ShaderCreateInfo::PushConst &uni : info.push_constants_) {
+ copy_input_name(input, uni.name, name_buffer_, name_buffer_offset);
+ input->location = glGetUniformLocation(program, name_buffer_ + input->name_offset);
+ input->binding = -1;
+ input++;
+ }
+
+ /* Compatibility uniforms. */
+ for (auto &name : workaround_uniform_names) {
+ copy_input_name(input, name, name_buffer_, name_buffer_offset);
+ input->location = glGetUniformLocation(program, name_buffer_ + input->name_offset);
+ input->binding = -1;
+ input++;
+ }
+
+ /* SSBOs */
+ for (const ShaderCreateInfo::Resource &res : all_resources) {
+ if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) {
+ copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset);
+ input->location = input->binding = res.slot;
+ enabled_ubo_mask_ |= (1 << input->binding);
+ input++;
+ }
+ }
+
+ /* Builtin Uniforms */
+ for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
+ GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
+ const ShaderInput *uni = this->uniform_get(builtin_uniform_name(u));
+ builtins_[u] = (uni != nullptr) ? uni->location : -1;
+ }
+
+ /* Builtin Uniforms Blocks */
+ for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) {
+ GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int);
+ const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u));
+ builtin_blocks_[u] = (block != nullptr) ? block->binding : -1;
+ }
+
+ this->sort_inputs();
+
+ // this->debug_print();
+}
+
GLShaderInterface::~GLShaderInterface()
{
for (auto *ref : refs_) {
diff --git a/source/blender/gpu/opengl/gl_shader_interface.hh b/source/blender/gpu/opengl/gl_shader_interface.hh
index 89a5b631047..94b6dd58316 100644
--- a/source/blender/gpu/opengl/gl_shader_interface.hh
+++ b/source/blender/gpu/opengl/gl_shader_interface.hh
@@ -34,6 +34,7 @@
#include "glew-mx.h"
+#include "gpu_shader_create_info.hh"
#include "gpu_shader_interface.hh"
namespace blender::gpu {
@@ -49,6 +50,7 @@ class GLShaderInterface : public ShaderInterface {
Vector<GLVaoCache *> refs_;
public:
+ GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info);
GLShaderInterface(GLuint program);
~GLShaderInterface();
diff --git a/source/blender/gpu/opengl/gl_state.cc b/source/blender/gpu/opengl/gl_state.cc
index bfc691df4b3..c6c013fcf3a 100644
--- a/source/blender/gpu/opengl/gl_state.cc
+++ b/source/blender/gpu/opengl/gl_state.cc
@@ -377,7 +377,7 @@ void GLStateManager::set_blend(const eGPUBlend value)
break;
}
case GPU_BLEND_ADDITIVE: {
- /* Do not let alpha accumulate but premult the source RGB by it. */
+ /* Do not let alpha accumulate but pre-multiply the source RGB by it. */
src_rgb = GL_SRC_ALPHA;
dst_rgb = GL_ONE;
src_alpha = GL_ZERO;
diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh
index 979644b41c9..83ff3ffc9e9 100644
--- a/source/blender/gpu/opengl/gl_state.hh
+++ b/source/blender/gpu/opengl/gl_state.hh
@@ -71,11 +71,11 @@ class GLStateManager : public StateManager {
public:
GLStateManager();
- void apply_state(void) override;
+ void apply_state() override;
/**
* Will set all the states regardless of the current ones.
*/
- void force_state(void) override;
+ void force_state() override;
void issue_barrier(eGPUBarrier barrier_bits) override;
@@ -85,35 +85,35 @@ class GLStateManager : public StateManager {
*/
void texture_bind_temp(GLTexture *tex);
void texture_unbind(Texture *tex) override;
- void texture_unbind_all(void) override;
+ void texture_unbind_all() override;
void image_bind(Texture *tex, int unit) override;
void image_unbind(Texture *tex) override;
- void image_unbind_all(void) override;
+ void image_unbind_all() override;
void texture_unpack_row_length_set(uint len) override;
- uint64_t bound_texture_slots(void);
- uint8_t bound_image_slots(void);
+ uint64_t bound_texture_slots();
+ uint8_t bound_image_slots();
private:
- static void set_write_mask(const eGPUWriteMask value);
- static void set_depth_test(const eGPUDepthTest value);
- static void set_stencil_test(const eGPUStencilTest test, const eGPUStencilOp operation);
- static void set_stencil_mask(const eGPUStencilTest test, const GPUStateMutable state);
- static void set_clip_distances(const int new_dist_len, const int old_dist_len);
- static void set_logic_op(const bool enable);
- static void set_facing(const bool invert);
- static void set_backface_culling(const eGPUFaceCullTest test);
- static void set_provoking_vert(const eGPUProvokingVertex vert);
- static void set_shadow_bias(const bool enable);
- static void set_blend(const eGPUBlend value);
+ static void set_write_mask(eGPUWriteMask value);
+ static void set_depth_test(eGPUDepthTest value);
+ static void set_stencil_test(eGPUStencilTest test, eGPUStencilOp operation);
+ static void set_stencil_mask(eGPUStencilTest test, const GPUStateMutable state);
+ static void set_clip_distances(int new_dist_len, int old_dist_len);
+ static void set_logic_op(bool enable);
+ static void set_facing(bool invert);
+ static void set_backface_culling(eGPUFaceCullTest test);
+ static void set_provoking_vert(eGPUProvokingVertex vert);
+ static void set_shadow_bias(bool enable);
+ static void set_blend(eGPUBlend value);
void set_state(const GPUState &state);
void set_mutable_state(const GPUStateMutable &state);
- void texture_bind_apply(void);
- void image_bind_apply(void);
+ void texture_bind_apply();
+ void image_bind_apply();
MEM_CXX_CLASS_ALLOC_FUNCS("GLStateManager")
};
@@ -130,6 +130,12 @@ static inline GLbitfield to_gl(eGPUBarrier barrier_bits)
if (barrier_bits & GPU_BARRIER_SHADER_STORAGE) {
barrier |= GL_SHADER_STORAGE_BARRIER_BIT;
}
+ if (barrier_bits & GPU_BARRIER_VERTEX_ATTRIB_ARRAY) {
+ barrier |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
+ }
+ if (barrier_bits & GPU_BARRIER_ELEMENT_ARRAY) {
+ barrier |= GL_ELEMENT_ARRAY_BARRIER_BIT;
+ }
return barrier;
}
diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh
index eb979444f5a..e786eaed38a 100644
--- a/source/blender/gpu/opengl/gl_texture.hh
+++ b/source/blender/gpu/opengl/gl_texture.hh
@@ -69,25 +69,25 @@ class GLTexture : public Texture {
* \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 generate_mipmap() override;
void copy_to(Texture *dst) override;
void clear(eGPUDataFormat format, const void *data) override;
void swizzle_set(const char swizzle_mask[4]) override;
void mip_range_set(int min, int max) override;
void *read(int mip, eGPUDataFormat type) override;
- void check_feedback_loop(void);
+ void check_feedback_loop();
/* TODO(fclem): Legacy. Should be removed at some point. */
- uint gl_bindcode_get(void) const override;
+ uint gl_bindcode_get() const override;
- static void samplers_init(void);
- static void samplers_free(void);
- static void samplers_update(void);
+ static void samplers_init();
+ static void samplers_free();
+ static void samplers_update();
protected:
/** Return true on success. */
- bool init_internal(void) override;
+ bool init_internal() override;
/** Return true on success. */
bool init_internal(GPUVertBuf *vbo) override;
@@ -97,7 +97,7 @@ class GLTexture : public Texture {
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);
- GPUFrameBuffer *framebuffer_get(void);
+ GPUFrameBuffer *framebuffer_get();
MEM_CXX_CLASS_ALLOC_FUNCS("GLTexture")
};
diff --git a/source/blender/gpu/opengl/gl_uniform_buffer.hh b/source/blender/gpu/opengl/gl_uniform_buffer.hh
index 6cc525a2b7a..d7b9982dfb8 100644
--- a/source/blender/gpu/opengl/gl_uniform_buffer.hh
+++ b/source/blender/gpu/opengl/gl_uniform_buffer.hh
@@ -48,10 +48,10 @@ class GLUniformBuf : public UniformBuf {
void update(const void *data) override;
void bind(int slot) override;
- void unbind(void) override;
+ void unbind() override;
private:
- void init(void);
+ void init();
MEM_CXX_CLASS_ALLOC_FUNCS("GLUniformBuf");
};
diff --git a/source/blender/gpu/opengl/gl_vertex_array.hh b/source/blender/gpu/opengl/gl_vertex_array.hh
index 0f9b61f9648..b8edbf3a691 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.hh
+++ b/source/blender/gpu/opengl/gl_vertex_array.hh
@@ -39,13 +39,13 @@ namespace GLVertArray {
void update_bindings(const GLuint vao,
const GPUBatch *batch,
const ShaderInterface *interface,
- const int base_instance);
+ int base_instance);
/**
* Another version of update_bindings for Immediate mode.
*/
void update_bindings(const GLuint vao,
- const uint v_first,
+ uint v_first,
const GPUVertFormat *format,
const ShaderInterface *interface);
diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.cc b/source/blender/gpu/opengl/gl_vertex_buffer.cc
index ce16a491528..469ac2cf8d6 100644
--- a/source/blender/gpu/opengl/gl_vertex_buffer.cc
+++ b/source/blender/gpu/opengl/gl_vertex_buffer.cc
@@ -49,6 +49,10 @@ void GLVertBuf::resize_data()
void GLVertBuf::release_data()
{
+ if (is_wrapper_) {
+ return;
+ }
+
if (vbo_id_ != 0) {
GLContext::buf_free(vbo_id_);
vbo_id_ = 0;
@@ -137,6 +141,16 @@ void *GLVertBuf::unmap(const void *mapped_data) const
return result;
}
+void GLVertBuf::wrap_handle(uint64_t handle)
+{
+ BLI_assert(vbo_id_ == 0);
+ BLI_assert(glIsBuffer(static_cast<uint>(handle)));
+ is_wrapper_ = true;
+ vbo_id_ = static_cast<uint>(handle);
+ /* We assume the data is already on the device, so no need to allocate or send it. */
+ flag = GPU_VERTBUF_DATA_UPLOADED;
+}
+
bool GLVertBuf::is_active() const
{
if (!vbo_id_) {
@@ -147,7 +161,7 @@ bool GLVertBuf::is_active() const
return vbo_id_ == active_vbo_id;
}
-void GLVertBuf::update_sub(uint start, uint len, void *data)
+void GLVertBuf::update_sub(uint start, uint len, const void *data)
{
glBufferSubData(GL_ARRAY_BUFFER, start, len, data);
}
diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.hh b/source/blender/gpu/opengl/gl_vertex_buffer.hh
index 6c38a2225b3..d347b6d56ca 100644
--- a/source/blender/gpu/opengl/gl_vertex_buffer.hh
+++ b/source/blender/gpu/opengl/gl_vertex_buffer.hh
@@ -39,22 +39,27 @@ class GLVertBuf : public VertBuf {
private:
/** OpenGL buffer handle. Init on first upload. Immutable after that. */
GLuint vbo_id_ = 0;
+ /** Defines whether the buffer handle is wrapped by this GLVertBuf, i.e. we do not own it and
+ * should not free it. */
+ bool is_wrapper_ = false;
/** Size on the GPU. */
size_t vbo_size_ = 0;
public:
- void bind(void);
+ void bind();
- void update_sub(uint start, uint len, void *data) override;
+ void update_sub(uint start, uint len, const void *data) override;
const void *read() const override;
void *unmap(const void *mapped_data) const override;
+ void wrap_handle(uint64_t handle) override;
+
protected:
- void acquire_data(void) override;
- void resize_data(void) override;
- void release_data(void) override;
- void upload_data(void) override;
+ void acquire_data() override;
+ void resize_data() override;
+ void release_data() override;
+ void upload_data() override;
void duplicate_data(VertBuf *dst) override;
void bind_as_ssbo(uint binding) override;
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl
index 5a36b414229..4ebcb9c397f 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_frag.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color;
uniform float scale;
in vec2 uv;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl
index d20ddcd27c0..c6f01d68eee 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_area_borders_vert.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform vec4 rect;
@@ -8,6 +8,7 @@ uniform float scale;
in vec2 pos;
out vec2 uv;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_frag.glsl
deleted file mode 100644
index 108fc85c4a5..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_frag.glsl
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-uniform float dashWidth;
-
-#ifdef SMOOTH_COLOR
-noperspective in vec4 finalColor;
-#else
-flat in vec4 finalColor;
-#endif
-
-noperspective in vec2 stipple_pos;
-flat in vec2 stipple_start;
-
-out vec4 fragColor;
-
-void main()
-{
- fragColor = finalColor;
-
- /* Avoid passing viewport size */
- vec2 dd = fwidth(stipple_pos);
-
- float dist = distance(stipple_start, stipple_pos) / max(dd.x, dd.y);
-
- if (fract(dist / dashWidth) > 0.5) {
- fragColor.rgb = vec3(0.0);
- }
-
- fragColor = blender_srgb_to_framebuffer_space(fragColor);
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl
deleted file mode 100644
index 69fe5c93a61..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl
+++ /dev/null
@@ -1,38 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec4 edgeColor;
-uniform vec4 selectColor;
-
-in vec2 pos;
-in int flag;
-
-#ifdef SMOOTH_COLOR
-noperspective out vec4 finalColor;
-#else
-flat out vec4 finalColor;
-#endif
-
-noperspective out vec2 stipple_pos;
-flat out vec2 stipple_start;
-
-/* TODO: Port drawing to draw manager and
- * remove constants duplications. */
-#define VERT_UV_SELECT (1 << 3)
-#define EDGE_UV_SELECT (1 << 5)
-
-void main()
-{
-#ifdef SMOOTH_COLOR
- bool is_select = (flag & VERT_UV_SELECT) != 0;
-#else
- bool is_select = (flag & EDGE_UV_SELECT) != 0;
-#endif
-
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
- gl_Position.z = float(!is_select);
-
- /* Avoid precision loss. */
- stipple_start = stipple_pos = 500.0 + 500.0 * (gl_Position.xy / gl_Position.w);
-
- finalColor = (is_select) ? selectColor : edgeColor;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl
deleted file mode 100644
index 7a94fc088c4..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl
+++ /dev/null
@@ -1,19 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec4 vertColor;
-uniform vec4 selectColor;
-
-in vec2 pos;
-in int flag;
-
-out vec4 finalColor;
-
-/* TODO: Port drawing to draw manager and
- * remove constants duplications. */
-#define FACE_UV_SELECT (1 << 7)
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
- finalColor = ((flag & FACE_UV_SELECT) != 0) ? selectColor : vertColor;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl
deleted file mode 100644
index 6fc41271cf5..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl
+++ /dev/null
@@ -1,26 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec4 faceColor;
-uniform vec4 selectColor;
-uniform vec4 activeColor;
-
-in vec2 pos;
-in int flag;
-
-flat out vec4 finalColor;
-
-/* TODO: Port drawing to draw manager and
- * remove constants duplications. */
-#define FACE_UV_ACTIVE (1 << 6)
-#define FACE_UV_SELECT (1 << 7)
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
-
- bool is_selected = (flag & FACE_UV_SELECT) != 0;
- bool is_active = (flag & FACE_UV_ACTIVE) != 0;
-
- finalColor = (is_selected) ? selectColor : faceColor;
- finalColor = (is_active) ? activeColor : finalColor;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl
deleted file mode 100644
index bec565be1df..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl
+++ /dev/null
@@ -1,44 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec4 vertColor;
-uniform vec4 selectColor;
-uniform vec4 pinnedColor;
-uniform float pointSize;
-uniform float outlineWidth;
-
-in vec2 pos;
-in int flag;
-
-out vec4 fillColor;
-out vec4 outlineColor;
-out vec4 radii;
-
-/* TODO: Port drawing to draw manager and
- * remove constants duplications. */
-#define VERT_UV_SELECT (1 << 3)
-#define VERT_UV_PINNED (1 << 4)
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
- gl_PointSize = pointSize;
-
- bool is_selected = (flag & VERT_UV_SELECT) != 0;
- bool is_pinned = (flag & VERT_UV_PINNED) != 0;
-
- vec4 deselect_col = (is_pinned) ? pinnedColor : vertColor;
- fillColor = (is_selected) ? selectColor : deselect_col;
- outlineColor = (is_pinned) ? pinnedColor : vec4(fillColor.rgb, 0.0);
-
- /* Calculate concentric radii in pixels. */
- float radius = 0.5 * pointSize;
-
- /* Start at the outside and progress toward the center. */
- radii[0] = radius;
- radii[1] = radius - 1.0;
- radii[2] = radius - outlineWidth;
- radii[3] = radius - outlineWidth - 1.0;
-
- /* Convert to PointCoord units. */
- radii /= pointSize;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
deleted file mode 100644
index 3254a7e1508..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl
+++ /dev/null
@@ -1,98 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec2 aspect;
-
-in vec2 pos;
-
-#ifdef STRETCH_ANGLE
-in vec2 uv_angles;
-in float angle;
-
-#else
-in float ratio;
-uniform float totalAreaRatio;
-uniform float totalAreaRatioInv;
-
-#endif
-
-noperspective out vec4 finalColor;
-
-vec3 weight_to_rgb(float weight)
-{
- vec3 r_rgb;
- float blend = ((weight / 2.0) + 0.5);
-
- if (weight <= 0.25) { /* blue->cyan */
- r_rgb[0] = 0.0;
- r_rgb[1] = blend * weight * 4.0;
- r_rgb[2] = blend;
- }
- else if (weight <= 0.50) { /* cyan->green */
- r_rgb[0] = 0.0;
- r_rgb[1] = blend;
- r_rgb[2] = blend * (1.0 - ((weight - 0.25) * 4.0));
- }
- else if (weight <= 0.75) { /* green->yellow */
- r_rgb[0] = blend * ((weight - 0.50) * 4.0);
- r_rgb[1] = blend;
- r_rgb[2] = 0.0;
- }
- else if (weight <= 1.0) { /* yellow->red */
- r_rgb[0] = blend;
- r_rgb[1] = blend * (1.0 - ((weight - 0.75) * 4.0));
- r_rgb[2] = 0.0;
- }
- else {
- /* exceptional value, unclamped or nan,
- * avoid uninitialized memory use */
- r_rgb[0] = 1.0;
- r_rgb[1] = 0.0;
- r_rgb[2] = 1.0;
- }
-
- return r_rgb;
-}
-
-#define M_PI 3.1415926535897932
-
-vec2 angle_to_v2(float angle)
-{
- return vec2(cos(angle), sin(angle));
-}
-
-/* Adapted from BLI_math_vector.h */
-float angle_normalized_v2v2(vec2 v1, vec2 v2)
-{
- v1 = normalize(v1 * aspect);
- v2 = normalize(v2 * aspect);
- /* this is the same as acos(dot_v3v3(v1, v2)), but more accurate */
- bool q = (dot(v1, v2) >= 0.0);
- vec2 v = (q) ? (v1 - v2) : (v1 + v2);
- float a = 2.0 * asin(length(v) / 2.0);
- return (q) ? a : M_PI - a;
-}
-
-float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio)
-{
- ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio;
- return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
-}
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
-
-#ifdef STRETCH_ANGLE
- vec2 v1 = angle_to_v2(uv_angles.x * M_PI);
- vec2 v2 = angle_to_v2(uv_angles.y * M_PI);
- float uv_angle = angle_normalized_v2v2(v1, v2) / M_PI;
- float stretch = 1.0 - abs(uv_angle - angle);
- stretch = stretch;
- stretch = 1.0 - stretch * stretch;
-#else
- float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio, totalAreaRatioInv);
-
-#endif
-
- finalColor = vec4(weight_to_rgb(stretch), 1.0);
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl
index df2507c0dc9..494ef8d888e 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec2 pos;
in vec4 color;
flat out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
index bdc0d37a7ae..9851e08fe2e 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
@@ -4,7 +4,8 @@
*/
/* Same as ICON_DRAW_CACHE_SIZE */
-#define MAX_CALLS 16
+#ifndef USE_GPU_SHADER_CREATE_INFO
+# define MAX_CALLS 16
uniform vec4 calls_data[MAX_CALLS * 3];
@@ -12,12 +13,13 @@ out vec2 texCoord_interp;
flat out vec4 finalColor;
in vec2 pos;
+#endif
void main()
{
- vec4 rect = calls_data[gl_InstanceID * 3];
- vec4 tex = calls_data[gl_InstanceID * 3 + 1];
- finalColor = calls_data[gl_InstanceID * 3 + 2];
+ vec4 rect = multi_rect_data.calls_data[gl_InstanceID * 3];
+ vec4 tex = multi_rect_data.calls_data[gl_InstanceID * 3 + 1];
+ finalColor = multi_rect_data.calls_data[gl_InstanceID * 3 + 2];
/* Use pos to select the right swizzle (instead of gl_VertexID)
* in order to workaround an OSX driver bug. */
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
index ab9c30505c2..d9a5aeeef46 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
@@ -3,11 +3,13 @@
* does not need any vertex input (producing less call to immBegin/End)
*/
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform vec4 rect_icon;
uniform vec4 rect_geom;
out vec2 texCoord_interp;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl
index cdb066c9c52..0b5e3759dfb 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
/* Keep in sync with intern/opencolorio/gpu_shader_display_transform_vertex.glsl */
in vec2 texCoord;
in vec2 pos;
out vec2 texCoord_interp;
+#endif
void main()
{
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 43f259671fa..af9a24d1280 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
@@ -6,6 +6,8 @@
* Dashed is performed in screen space.
*/
+#ifndef USE_GPU_SHADER_CREATE_INFO
+
uniform float dash_width;
/* Simple mode, discarding non-dash parts (so no need for blending at all). */
@@ -23,6 +25,7 @@ noperspective in vec2 stipple_pos;
flat in vec2 stipple_start;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
index 15362d020e4..9d52820188b 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl
@@ -5,7 +5,7 @@
*
* Dashed is performed in screen space.
*/
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform vec4 color;
@@ -18,6 +18,7 @@ flat out vec4 color_vert;
/* We leverage hardware interpolation to compute distance along the line. */
noperspective out vec2 stipple_pos; /* In screen space */
flat out vec2 stipple_start; /* In screen space */
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl
index 134a7d00127..c4d56579b18 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in float colorGradient;
in vec4 finalColor;
in float lineU;
@@ -8,6 +8,7 @@ flat in float dashAlpha;
flat in int isMainLine;
out vec4 fragColor;
+#endif
#define DASH_WIDTH 10.0
#define ANTIALIAS 1.0
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
index 8325568988c..b83ea59a692 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl
@@ -4,13 +4,15 @@
#define MID_VERTEX 65
+#ifndef USE_GPU_SHADER_CREATE_INFO
+
/* u is position along the curve, defining the tangent space.
* v is "signed" distance (compressed to [0..1] range) from the pos in expand direction */
in vec2 uv;
in vec2 pos; /* verts position in the curve tangent space */
in vec2 expand;
-#ifdef USE_INSTANCE
+# ifdef USE_INSTANCE
/* Instance attrs. */
in vec2 P0;
in vec2 P1;
@@ -27,21 +29,10 @@ in float dash_alpha;
uniform vec4 colors[6];
-# define colStart (colid_doarrow[0] < 3 ? start_color : colors[colid_doarrow[0]])
-# define colEnd (colid_doarrow[1] < 3 ? end_color : colors[colid_doarrow[1]])
-# define colShadow colors[colid_doarrow[2]]
-# define doArrow (colid_doarrow[3] != 0)
-# define doMuted (domuted[0] != 0)
-
-#else
+# else
/* Single curve drawcall, use uniform. */
uniform vec2 bezierPts[4];
-# define P0 bezierPts[0]
-# define P1 bezierPts[1]
-# define P2 bezierPts[2]
-# define P3 bezierPts[3]
-
uniform vec4 colors[3];
uniform bool doArrow;
uniform bool doMuted;
@@ -50,11 +41,7 @@ uniform float thickness;
uniform float dash_factor;
uniform float dash_alpha;
-# define colShadow colors[0]
-# define colStart colors[1]
-# define colEnd colors[2]
-
-#endif
+# endif
uniform float expandSize;
uniform float arrowSize;
@@ -67,6 +54,33 @@ flat out float lineLength;
flat out float dashFactor;
flat out float dashAlpha;
flat out int isMainLine;
+#endif
+
+#ifdef USE_INSTANCE
+# define colStart (colid_doarrow[0] < 3 ? start_color : node_link_data.colors[colid_doarrow[0]])
+# define colEnd (colid_doarrow[1] < 3 ? end_color : node_link_data.colors[colid_doarrow[1]])
+# define colShadow node_link_data.colors[colid_doarrow[2]]
+# define doArrow (colid_doarrow[3] != 0)
+# define doMuted (domuted[0] != 0)
+
+#else
+# define P0 node_link_data.bezierPts[0].xy
+# define P1 node_link_data.bezierPts[1].xy
+# define P2 node_link_data.bezierPts[2].xy
+# define P3 node_link_data.bezierPts[3].xy
+# define cols node_link_data.colors
+# define doArrow node_link_data.doArrow
+# define doMuted node_link_data.doMuted
+# define dim_factor node_link_data.dim_factor
+# define thickness node_link_data.thickness
+# define dash_factor node_link_data.dash_factor
+# define dash_alpha node_link_data.dash_alpha
+
+# define colShadow node_link_data.colors[0]
+# define colStart node_link_data.colors[1]
+# define colEnd node_link_data.colors[2]
+
+#endif
/* Define where along the noodle the gradient will starts and ends.
* Use 0.25 instead of 0.35-0.65, because of a visual shift issue. */
@@ -101,7 +115,7 @@ void main(void)
vec2 normal = tangent.yx * vec2(-1.0, 1.0);
/* Position vertex on the curve tangent space */
- point += (pos.x * tangent + pos.y * normal) * arrowSize;
+ point += (pos.x * tangent + pos.y * normal) * node_link_data.arrowSize;
gl_Position = ModelViewProjectionMatrix * vec4(point, 0.0, 1.0);
@@ -139,7 +153,7 @@ void main(void)
finalColor[3] *= dim_factor;
/* Expand into a line */
- gl_Position.xy += exp_axis * expandSize * expand_dist * thickness;
+ gl_Position.xy += exp_axis * node_link_data.expandSize * expand_dist * thickness;
/* If the link is not muted or is not a reroute arrow the points are squashed to the center of
* the line. Magic numbers are defined in drawnode.c */
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl
index 1453393aa9f..f2b6aa1f12c 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl
@@ -1,9 +1,11 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform float size;
in vec2 pos;
out vec2 radii;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl
index 5c555b2d3e7..5d97fca1116 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform float size;
uniform float outlineWidth;
in vec2 pos;
out vec4 radii;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl
deleted file mode 100644
index 3eec271913a..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl
+++ /dev/null
@@ -1,28 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform float size;
-uniform float outlineWidth;
-
-in vec2 pos;
-in vec4 color;
-out vec4 radii;
-out vec4 fillColor;
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
- gl_PointSize = size;
- fillColor = color;
-
- /* Calculate concentric radii in pixels. */
- float radius = 0.5 * size;
-
- /* Start at the outside and progress toward the center. */
- radii[0] = radius;
- radii[1] = radius - 1.0;
- radii[2] = radius - outlineWidth;
- radii[3] = radius - outlineWidth - 1.0;
-
- /* Convert to PointCoord units. */
- radii /= size;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl
index 469370b9173..6ba6f980406 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec2 pos;
in float size;
in vec4 color;
out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl
index 1333c00682c..4d887a37807 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl
@@ -1,6 +1,7 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
noperspective in vec4 finalColor;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl
index fcf436d50af..5d19aea9168 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec2 pos;
in vec4 color;
noperspective out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl
index de6547715f3..698f20ae1f9 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl
@@ -1,11 +1,13 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#ifdef UV_POS
+# ifdef UV_POS
in vec2 u;
-# define pos u
-#else
+# define pos u
+# else
in vec2 pos;
+# endif
#endif
void main()
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
index 6dd0201535d..a03b88db342 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
@@ -1,3 +1,4 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec3 checkerColorAndSize;
noperspective in vec2 uvInterp;
@@ -12,6 +13,7 @@ flat in vec4 embossColor;
flat in float lineWidth;
out vec4 fragColor;
+#endif
vec3 compute_masks(vec2 uv)
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
index b5036b51d9d..80b93baf20a 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
@@ -1,12 +1,13 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#define MAX_PARAM 12
-#ifdef USE_INSTANCE
-# define MAX_INSTANCE 6
+# define MAX_PARAM 12
+# ifdef USE_INSTANCE
+# define MAX_INSTANCE 6
uniform vec4 parameters[MAX_PARAM * MAX_INSTANCE];
-#else
+# else
uniform vec4 parameters[MAX_PARAM];
+# endif
#endif
/* gl_InstanceID is supposed to be 0 if not drawing instances, but this seems
@@ -41,6 +42,7 @@ uniform vec4 parameters[MAX_PARAM];
#define doAlphaCheck (alphaDiscard < 0.0)
#define discardFactor abs(alphaDiscard)
+#ifndef USE_GPU_SHADER_CREATE_INFO
noperspective out vec2 uvInterp;
flat out vec2 outRectSize;
flat out vec4 outRoundCorners;
@@ -51,8 +53,9 @@ flat out float lineWidth;
noperspective out float butCo;
flat out float discardFac;
-#ifdef OS_MAC
+# ifdef OS_MAC
in float dummy;
+# endif
#endif
vec2 do_widget(void)
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl
index e8a6a43191e..a624d3f2f8b 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl
@@ -1,9 +1,11 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
in float shadowFalloff;
out vec4 fragColor;
uniform float alpha;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl
index dc2849c8aa9..d3eed997292 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl
@@ -51,9 +51,12 @@ const vec2 cornervec[36] = vec2[36](vec2(0.0, 1.0),
#define INNER_FLAG uint(1 << 10) /* is inner vert */
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform vec4 parameters[4];
+#endif
+
/* radi and rad per corner */
#define recti parameters[0]
#define rect parameters[1]
@@ -61,9 +64,11 @@ uniform vec4 parameters[4];
#define rads parameters[2].y
#define roundCorners parameters[3]
+#ifndef USE_GPU_SHADER_CREATE_INFO
in uint vflag;
out float shadowFalloff;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl
index 16424ece2b6..1a87796f7c4 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ModelMatrix;
uniform vec4 ClipPlane;
in vec3 pos;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl
index 5b6a890ccc8..b6132113bc9 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl
@@ -1,33 +1,24 @@
+#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl)
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
in vec3 pos;
-#if defined(USE_COLOR_U32)
-in uint color;
-#else
in vec4 color;
-#endif
flat out vec4 finalColor;
+#endif
void main()
{
vec4 pos_4d = vec4(pos, 1.0);
gl_Position = ModelViewProjectionMatrix * pos_4d;
-
-#if defined(USE_COLOR_U32)
- finalColor = vec4(((color)&uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 24)) * (1.0f / 255.0f));
-#else
finalColor = color;
-#endif
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * pos_4d).xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl
index 0fb8d06e317..908d442739a 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl
@@ -1,9 +1,11 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec2 texCoord;
in vec3 pos;
out vec2 texCoord_interp;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
index aefa47275f5..9328e0a13e9 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl
@@ -6,11 +6,13 @@
* Dashed is performed in screen space.
*/
+#ifndef USE_GPU_SHADER_CREATE_INFO
+
uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
uniform vec4 color;
uniform vec2 viewport_size;
@@ -22,6 +24,7 @@ flat out vec4 color_vert;
/* We leverage hardware interpolation to compute distance along the line. */
noperspective out vec2 stipple_pos; /* In screen space */
flat out vec2 stipple_start; /* In screen space */
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl
index 252fee87015..18fed69eff6 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform mat3 NormalMatrix;
in vec3 pos;
in vec3 nor;
out vec3 normal;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl
index 12594b04da9..52e9e71fdd8 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl
@@ -1,9 +1,11 @@
-#ifdef USE_WORLD_CLIP_PLANES
+#ifndef USE_GPU_SHADER_CREATE_INFO
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
/* Does Nothing */
in vec3 pos;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl
index 776656fc2df..504b3f75373 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec3 pos;
in vec4 color;
out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl
index 5d67658c639..7f143ccc28d 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl
@@ -1,12 +1,15 @@
+#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl)
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
uniform float size;
in vec3 pos;
out vec2 radii;
+#endif
void main()
{
@@ -25,6 +28,6 @@ void main()
radii /= size;
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz);
+ world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * pos_4d).xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl
deleted file mode 100644
index fb5506a778d..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl
+++ /dev/null
@@ -1,33 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
-uniform mat4 ModelMatrix;
-#endif
-uniform float size;
-uniform float outlineWidth;
-
-in vec3 pos;
-out vec4 radii;
-
-void main()
-{
- vec4 pos_4d = vec4(pos, 1.0);
- gl_Position = ModelViewProjectionMatrix * pos_4d;
- gl_PointSize = size;
-
- /* calculate concentric radii in pixels */
- float radius = 0.5 * size;
-
- /* start at the outside and progress toward the center */
- radii[0] = radius;
- radii[1] = radius - 1.0;
- radii[2] = radius - outlineWidth;
- radii[3] = radius - outlineWidth - 1.0;
-
- /* convert to PointCoord units */
- radii /= size;
-
-#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz);
-#endif
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl
index 3bc72535266..f048e143da7 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec3 pos;
in float size;
in vec4 color;
out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl
deleted file mode 100644
index fc61be936fe..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl
+++ /dev/null
@@ -1,11 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-
-in vec3 pos;
-in float size;
-
-void main()
-{
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
- gl_PointSize = size;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl
index 3ea8f7dbfbe..8687763f4c1 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl
@@ -1,14 +1,15 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform float lineWidth;
uniform bool lineSmooth = true;
in vec4 finalColor;
noperspective in float smoothline;
-#ifdef CLIP
+# ifdef CLIP
in float clip;
-#endif
+# endif
out vec4 fragColor;
+#endif
#define SMOOTH_WIDTH 1.0
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl
index 70026398937..627e91af4d6 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
layout(lines) in;
layout(triangle_strip, max_vertices = 4) out;
@@ -7,17 +7,18 @@ uniform vec2 viewportSize;
uniform float lineWidth;
uniform bool lineSmooth = true;
-#if !defined(UNIFORM)
+# if !defined(UNIFORM)
in vec4 finalColor_g[];
-#endif
+# endif
-#ifdef CLIP
+# ifdef CLIP
in float clip_g[];
out float clip;
-#endif
+# endif
out vec4 finalColor;
noperspective out float smoothline;
+#endif
#define SMOOTH_WIDTH 1.0
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl
index 28aa2a4ccc6..5c673494870 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl
@@ -1,18 +1,19 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ModelMatrix;
uniform vec4 ClipPlane;
in vec3 pos;
-#if !defined(UNIFORM)
+# if !defined(UNIFORM)
in vec4 color;
out vec4 finalColor_g;
-#endif
+# endif
-#ifdef CLIP
+# ifdef CLIP
out float clip_g;
+# endif
#endif
void main()
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl
index 3a2d96c9929..de555cc5706 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl
@@ -1,6 +1,7 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec4 finalColor;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl
index 4eafb7b7be3..56a1210c957 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl
@@ -1,14 +1,17 @@
+#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl)
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
in vec3 pos;
in vec4 color;
out vec4 finalColor;
+#endif
void main()
{
@@ -16,6 +19,6 @@ void main()
finalColor = color;
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz);
+ world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * vec4(pos, 1.0)).xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl
index 70bb881ffea..1d7b7df49a8 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl
@@ -1,17 +1,20 @@
+#pragma BLENDER_REQUIRE(gpu_shader_cfg_world_clip_lib.glsl)
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
-#ifdef USE_WORLD_CLIP_PLANES
+# ifdef USE_WORLD_CLIP_PLANES
uniform mat4 ModelMatrix;
-#endif
+# endif
in vec3 pos;
+#endif
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
#ifdef USE_WORLD_CLIP_PLANES
- world_clip_planes_calc_clip_distance((ModelMatrix * vec4(pos, 1.0)).xyz);
+ world_clip_planes_calc_clip_distance((clipPlanes.ModelMatrix * vec4(pos, 1.0)).xyz);
#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl b/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl
index 46cf2fe09a2..cdc716db7a4 100644
--- a/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl
@@ -1,7 +1,9 @@
#ifdef USE_WORLD_CLIP_PLANES
# if defined(GPU_VERTEX_SHADER) || defined(GPU_GEOMETRY_SHADER)
+# ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 WorldClipPlanes[6];
+# endif
# define _world_clip_planes_calc_clip_distance(wpos, _clipplanes) \
{ \
@@ -14,6 +16,10 @@ uniform vec4 WorldClipPlanes[6];
gl_ClipDistance[5] = dot(_clipplanes[5], pos); \
}
+/* When all shaders are builtin shaders are migrated this could be applied directly. */
+# ifdef USE_GPU_SHADER_CREATE_INFO
+# define WorldClipPlanes clipPlanes.world
+# endif
/* HACK Dirty hack to be able to override the definition in common_view_lib.glsl.
* Not doing this would require changing the include order in every shaders. */
# define world_clip_planes_calc_clip_distance(wpos) \
diff --git a/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl
index 156b6cb75ab..9065da0275a 100644
--- a/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color1;
uniform vec4 color2;
uniform int size;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl
index aae659516bb..74341701fb0 100644
--- a/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl
@@ -2,7 +2,9 @@
/* Undefine the macro that avoids compilation errors. */
#undef blender_srgb_to_framebuffer_space
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform bool srgbTarget = false;
+#endif
vec4 blender_srgb_to_framebuffer_space(vec4 color)
{
diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
index 9e1527a9e7f..f5b6de4899f 100644
--- a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
@@ -9,11 +9,14 @@ struct ObjectInfos {
vec4 drw_Infos;
};
+# ifndef USE_GPU_SHADER_CREATE_INFO
layout(std140) uniform infoBlock
{
/* DRW_RESOURCE_CHUNK_LEN = 512 */
ObjectInfos drw_infos[512];
};
+# endif
+
# define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors)
# define ObjectInfo (drw_infos[resource_id].drw_Infos)
# define ObjectColor (drw_infos[resource_id].drw_ObjectColor)
diff --git a/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl
index 48979af4ad0..a4a24ed8e46 100644
--- a/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color1;
uniform vec4 color2;
uniform int size1;
uniform int size2;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl
index 6f7d68856d5..d3d4b66589b 100644
--- a/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl
@@ -1,6 +1,7 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
flat in vec4 finalColor;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl
index 99d8b6ab685..1675de3d567 100644
--- a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl
@@ -1,6 +1,7 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
flat in vec4 finalColor;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl
index 8e1287c483a..2aabdb84f16 100644
--- a/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl
@@ -1,6 +1,7 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
flat in uint finalId;
out uint fragId;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index 3b4e2e17ccc..4fdc14289e1 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ProjectionMatrix;
uniform int PrimitiveIdBase;
@@ -19,6 +19,7 @@ out vec3 varposition;
uniform bool osd_flat_shading;
uniform int osd_fvar_count;
+#endif
#define INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) \
{ \
@@ -38,8 +39,10 @@ uniform int osd_fvar_count;
result = vec3(tmp, 0); \
}
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform samplerBuffer FVarDataBuffer;
uniform isamplerBuffer FVarDataOffsetBuffer;
+#endif
out block
{
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl
index fc3f47c0aaa..37541bb91f3 100644
--- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl
@@ -1,16 +1,18 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec4 mColor;
in vec2 mTexCoord;
out vec4 fragColor;
+#endif
void main()
{
const vec2 center = vec2(0, 0.5);
- vec4 tColor = vec4(mColor);
+ vec4 tColor = vec4(geometry_out.mColor);
/* if alpha < 0, then encap */
- if (mColor.a < 0) {
+ if (geometry_out.mColor.a < 0) {
tColor.a = tColor.a * -1.0;
- float dist = length(mTexCoord - center);
+ float dist = length(geometry_out.mTexCoord - center);
if (dist > 0.25) {
discard;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
index b937323f62a..f076655b459 100644
--- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
@@ -1,3 +1,4 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform vec2 Viewport;
uniform int xraymode;
@@ -13,6 +14,7 @@ in float finalThickness[4];
out vec4 mColor;
out vec2 mTexCoord;
+#endif
#define GP_XRAY_FRONT 0
#define GP_XRAY_3DSPACE 1
@@ -23,19 +25,19 @@ out vec2 mTexCoord;
/* project 3d point to 2d on screen space */
vec2 toScreenSpace(vec4 vertex)
{
- return vec2(vertex.xy / vertex.w) * Viewport;
+ return vec2(vertex.xy / vertex.w) * gpencil_stroke_data.viewport;
}
/* get zdepth value */
float getZdepth(vec4 point)
{
- if (xraymode == GP_XRAY_FRONT) {
+ if (gpencil_stroke_data.xraymode == GP_XRAY_FRONT) {
return 0.0;
}
- if (xraymode == GP_XRAY_3DSPACE) {
+ if (gpencil_stroke_data.xraymode == GP_XRAY_3DSPACE) {
return (point.z / point.w);
}
- if (xraymode == GP_XRAY_BACK) {
+ if (gpencil_stroke_data.xraymode == GP_XRAY_BACK) {
return 1.0;
}
@@ -75,7 +77,7 @@ void main(void)
vec2 sp3 = toScreenSpace(P3); /* end of next segment */
/* culling outside viewport */
- vec2 area = Viewport * 4.0;
+ vec2 area = gpencil_stroke_data.viewport * 4.0;
if (sp1.x < -area.x || sp1.x > area.x) {
return;
}
@@ -112,8 +114,8 @@ void main(void)
if (bn1 == 0) {
bn1 = 1;
}
- float length_a = finalThickness[1] / an1;
- float length_b = finalThickness[2] / bn1;
+ float length_a = geometry_in[1].finalThickness / an1;
+ float length_b = geometry_in[2].finalThickness / bn1;
if (length_a <= 0.0) {
length_a = 0.01;
}
@@ -124,41 +126,49 @@ void main(void)
/* prevent excessively long miters at sharp corners */
if (dot(v0, v1) < -MiterLimit) {
miter_a = n1;
- length_a = finalThickness[1];
+ length_a = geometry_in[1].finalThickness;
/* close the gap */
if (dot(v0, n1) > 0) {
- mTexCoord = vec2(0, 0);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4((sp1 + geometry_in[1].finalThickness * n0) / gpencil_stroke_data.viewport,
+ getZdepth(P1),
+ 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4((sp1 + geometry_in[1].finalThickness * n1) / gpencil_stroke_data.viewport,
+ getZdepth(P1),
+ 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0.5);
- mColor = finalColor[1];
- gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0.5);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
EndPrimitive();
}
else {
- mTexCoord = vec2(0, 1);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4((sp1 - geometry_in[1].finalThickness * n1) / gpencil_stroke_data.viewport,
+ getZdepth(P1),
+ 1.0);
EmitVertex();
- mTexCoord = vec2(0, 1);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4((sp1 - geometry_in[1].finalThickness * n0) / gpencil_stroke_data.viewport,
+ getZdepth(P1),
+ 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0.5);
- mColor = finalColor[1];
- gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0.5);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
EndPrimitive();
@@ -167,66 +177,74 @@ void main(void)
if (dot(v1, v2) < -MiterLimit) {
miter_b = n1;
- length_b = finalThickness[2];
+ length_b = geometry_in[2].finalThickness;
}
/* Generate the start end-cap (alpha < 0 used as end-cap flag). */
- float extend = (fill_stroke > 0) ? 2 : 1;
- if ((caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)) {
- mTexCoord = vec2(1, 0.5);
- mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0);
+ float extend = gpencil_stroke_data.fill_stroke ? 2 : 1;
+ if ((gpencil_stroke_data.caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)) {
+ geometry_out.mTexCoord = vec2(1, 0.5);
+ geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0);
vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0 * extend;
- gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0);
+ gl_Position = vec4((sp1 + svn1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0);
- mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0);
- gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0);
+ gl_Position = vec4(
+ (sp1 - (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 1);
- mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0);
- gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0);
+ gl_Position = vec4(
+ (sp1 + (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
}
/* generate the triangle strip */
- mTexCoord = vec2(0, 0);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4(
+ (sp1 + length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 1);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = geometry_in[1].finalColor;
+ gl_Position = vec4(
+ (sp1 - length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0);
- mColor = finalColor[2];
- gl_Position = vec4((sp2 + length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = geometry_in[2].finalColor;
+ gl_Position = vec4(
+ (sp2 + length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 1);
- mColor = finalColor[2];
- gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = geometry_in[2].finalColor;
+ gl_Position = vec4(
+ (sp2 - length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
EmitVertex();
/* Generate the end end-cap (alpha < 0 used as end-cap flag). */
- if ((caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3)) {
- mTexCoord = vec2(0, 1);
- mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0);
- gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ if ((gpencil_stroke_data.caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3)) {
+ geometry_out.mTexCoord = vec2(0, 1);
+ geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0);
+ gl_Position = vec4(
+ (sp2 + (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
EmitVertex();
- mTexCoord = vec2(0, 0);
- mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0);
- gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
+ geometry_out.mTexCoord = vec2(0, 0);
+ geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0);
+ gl_Position = vec4(
+ (sp2 - (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
EmitVertex();
- mTexCoord = vec2(1, 0.5);
- mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0);
+ geometry_out.mTexCoord = vec2(1, 0.5);
+ geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0);
vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0 * extend;
- gl_Position = vec4((sp2 + svn2) / Viewport, getZdepth(P2), 1.0);
+ gl_Position = vec4((sp2 + svn2) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
EmitVertex();
}
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl
index 07b4ae52110..16e12b2989e 100644
--- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl
@@ -1,3 +1,4 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ProjectionMatrix;
@@ -12,22 +13,21 @@ in float thickness;
out vec4 finalColor;
out float finalThickness;
+#endif
-#define TRUE 1
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
+float defaultpixsize = gpencil_stroke_data.pixsize * (1000.0 / gpencil_stroke_data.pixfactor);
void main(void)
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
- finalColor = color;
+ geometry_in.finalColor = color;
- if (keep_size == TRUE) {
- finalThickness = thickness;
+ if (gpencil_stroke_data.keep_size) {
+ geometry_in.finalThickness = thickness;
}
else {
float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) :
(thickness / defaultpixsize);
- finalThickness = max(size * objscale, 1.0);
+ geometry_in.finalThickness = max(size * gpencil_stroke_data.objscale, 1.0);
}
}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl
index 6dc7a1618e1..1846dae346a 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec2 texCoord_interp;
out vec4 fragColor;
uniform vec4 color;
uniform sampler2D image;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl
index dfbaaeda7b5..ad52b9819ab 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl
@@ -1,10 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform float factor;
in vec2 texCoord_interp;
out vec4 fragColor;
uniform vec4 color;
uniform sampler2D image;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_image_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl
index aff6ddf01bf..befd6b57bf8 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl
@@ -1,8 +1,9 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec2 texCoord_interp;
out vec4 fragColor;
uniform sampler2D image;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl
index 613352b4ac8..ceebaae896d 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl
@@ -1,9 +1,11 @@
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec2 texCoord_interp;
out vec4 fragColor;
uniform float alpha;
uniform sampler2D image;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
index 7f3fe2f5252..2314dbbc5d5 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
@@ -1,6 +1,7 @@
/* Merge overlays texture on top of image texture and transform to display space (assume sRGB) */
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform sampler2D image_texture;
uniform sampler2D overlays_texture;
uniform bool display_transform;
@@ -9,6 +10,7 @@ uniform bool overlay;
in vec2 texCoord_interp;
out vec4 fragColor;
+#endif
float linearrgb_to_srgb(float c)
{
diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
index c6e9860d940..9b1e6fe9d23 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl
@@ -7,18 +7,20 @@
/* Composite stereo textures */
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform sampler2D imageTexture;
uniform sampler2D overlayTexture;
uniform int stereoDisplaySettings;
+layout(location = 0) out vec4 imageColor;
+layout(location = 1) out vec4 overlayColor;
+#endif
+
#define stereo_display_mode (stereoDisplaySettings & ((1 << 3) - 1))
#define stereo_interlace_mode ((stereoDisplaySettings >> 3) & ((1 << 3) - 1))
#define stereo_interlace_swap bool(stereoDisplaySettings >> 6)
-layout(location = 0) out vec4 imageColor;
-layout(location = 1) out vec4 overlayColor;
-
bool interlace(ivec2 texel)
{
int interlace_mode = stereo_interlace_mode;
diff --git a/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl
index ed69184ef14..e8bfb70b897 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl
@@ -1,15 +1,16 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec2 texCoord_interp;
out vec4 fragColor;
uniform sampler2D image;
uniform vec4 color;
uniform vec4 shuffle;
+#endif
void main()
{
- vec4 sample = texture(image, texCoord_interp);
- fragColor = vec4(sample.r * shuffle.r + sample.g * shuffle.g + sample.b * shuffle.b +
- sample.a * shuffle.a) *
+ vec4 sampled_color = texture(image, texCoord_interp);
+ fragColor = vec4(sampled_color.r * shuffle.r + sampled_color.g * shuffle.g +
+ sampled_color.b * shuffle.b + sampled_color.a * shuffle.a) *
color;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl
index becf0fbd133..3058f73ab37 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec2 texCoord_interp;
flat in vec4 finalColor;
out vec4 fragColor;
uniform sampler2D image;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
index 10228a1e985..14450037ca8 100644
--- a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ViewProjectionMatrix;
/* ---- Instantiated Attrs ---- */
@@ -7,13 +7,14 @@ in vec3 pos;
/* ---- Per instance Attrs ---- */
in mat4 InstanceModelMatrix;
in vec4 color;
-#ifdef UNIFORM_SCALE
+# ifdef UNIFORM_SCALE
in float size;
-#else
+# else
in vec3 size;
-#endif
+# endif
flat out vec4 finalColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl
index a3b61dca8b4..2a2eaab7340 100644
--- a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_frag.glsl
@@ -11,6 +11,7 @@
#define GPU_KEYFRAME_SHAPE_SQUARE \
(GPU_KEYFRAME_SHAPE_CLIPPED_VERTICAL | GPU_KEYFRAME_SHAPE_CLIPPED_HORIZONTAL)
+#ifndef USE_GPU_SHADER_CREATE_INFO
flat in vec4 radii;
flat in vec4 thresholds;
@@ -20,6 +21,7 @@ flat in vec4 finalOutlineColor;
flat in int finalFlags;
out vec4 fragColor;
+#endif
const float diagonal_scale = sqrt(0.5);
diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
index 18e8b76ba23..4ef3ff1a8d0 100644
--- a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
@@ -11,15 +11,16 @@
#define GPU_KEYFRAME_SHAPE_SQUARE \
(GPU_KEYFRAME_SHAPE_CLIPPED_VERTICAL | GPU_KEYFRAME_SHAPE_CLIPPED_HORIZONTAL)
-uniform mat4 ModelViewProjectionMatrix;
-uniform vec2 ViewportSize = vec2(-1, -1);
-uniform float outline_scale = 1.0;
-
const float line_falloff = 1.0;
const float circle_scale = sqrt(2.0 / 3.1416);
const float square_scale = sqrt(0.5);
const float diagonal_scale = sqrt(0.5);
+#ifndef USE_GPU_SHADER_CREATE_INFO
+uniform mat4 ModelViewProjectionMatrix;
+uniform vec2 ViewportSize = vec2(-1, -1);
+uniform float outline_scale = 1.0;
+
in vec2 pos;
in float size;
in vec4 color;
@@ -33,6 +34,7 @@ flat out int finalFlags;
flat out vec4 radii;
flat out vec4 thresholds;
+#endif
bool test(int bit)
{
diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl
index 52d59d2030f..960b5e6efac 100644
--- a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl
@@ -1,8 +1,9 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color;
in vec2 radii;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl
deleted file mode 100644
index 692320bea93..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl
+++ /dev/null
@@ -1,18 +0,0 @@
-
-uniform vec4 color;
-
-out vec4 fragColor;
-
-void main()
-{
- vec2 centered = gl_PointCoord - vec2(0.5);
- float dist_squared = dot(centered, centered);
- const float rad_squared = 0.25;
-
- // round point with jaggy edges
- if (dist_squared > rad_squared) {
- discard;
- }
-
- fragColor = color;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl
index 2ece73b3845..cdf3aa8024d 100644
--- a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl
@@ -1,9 +1,10 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color;
uniform vec4 outlineColor;
in vec4 radii;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl
index 86c0e5c950a..23e9f9bc20f 100644
--- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl
@@ -1,6 +1,11 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec4 finalColor;
out vec4 fragColor;
+#endif
+
+#if defined(VERT)
+in float vertexCrease;
+#endif
void main()
{
@@ -13,5 +18,14 @@ void main()
discard;
}
+#if defined(VERT)
+ fragColor = finalColor;
+
+ float midStroke = 0.5 * rad_squared;
+ if (vertexCrease > 0.0 && dist_squared > midStroke) {
+ fragColor.rgb = mix(finalColor.rgb, colorEdgeCrease.rgb, vertexCrease);
+ }
+#else
fragColor = finalColor;
+#endif
}
diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl
deleted file mode 100644
index 1d936e4e072..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl
+++ /dev/null
@@ -1,33 +0,0 @@
-
-uniform vec4 outlineColor;
-
-in vec4 radii;
-in vec4 fillColor;
-out vec4 fragColor;
-
-void main()
-{
- float dist = length(gl_PointCoord - vec2(0.5));
-
- /* transparent outside of point
- * --- 0 ---
- * smooth transition
- * --- 1 ---
- * pure outline color
- * --- 2 ---
- * smooth transition
- * --- 3 ---
- * pure fill color
- * ...
- * dist = 0 at center of point */
-
- float midStroke = 0.5 * (radii[1] + radii[2]);
-
- if (dist > midStroke) {
- fragColor.rgb = outlineColor.rgb;
- fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist));
- }
- else {
- fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist));
- }
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl
index c9bd9e881bf..04a7e3d80d0 100644
--- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl
@@ -1,8 +1,9 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
in vec4 radii;
in vec4 fillColor;
in vec4 outlineColor;
out vec4 fragColor;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl
index 6bce517fee3..6725bc82841 100644
--- a/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl
@@ -1,18 +1,19 @@
-
-#ifndef USE_INSTANCE_COLOR
+#ifndef USE_GPU_SHADER_CREATE_INFO
+# ifndef USE_INSTANCE_COLOR
uniform vec4 color;
-#endif
+# endif
uniform vec3 light;
in vec3 normal;
-#ifdef USE_INSTANCE_COLOR
+# ifdef USE_INSTANCE_COLOR
flat in vec4 finalColor;
-# define color finalColor
-#endif
+# define color finalColor
+# endif
out vec4 fragColor;
+#endif
void main()
{
- fragColor = color;
- fragColor.xyz *= clamp(dot(normalize(normal), light), 0.0, 1.0);
+ fragColor = simple_lighting_data.color;
+ fragColor.xyz *= clamp(dot(normalize(normal), simple_lighting_data.light), 0.0, 1.0);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
index 2568cd74445..1456bd0c732 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
flat in vec4 color_flat;
noperspective in vec2 texCoord_interp;
flat in int glyph_offset;
@@ -8,6 +8,7 @@ flat in int interp_size;
out vec4 fragColor;
uniform sampler2D glyph;
+#endif
const vec2 offsets4[4] = vec2[4](
vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(-0.5, -0.5), vec2(-0.5, -0.5));
diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
index 768638e5229..5b01fea5266 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
@@ -1,4 +1,4 @@
-
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform mat4 ModelViewProjectionMatrix;
in vec4 pos; /* rect */
@@ -11,6 +11,7 @@ noperspective out vec2 texCoord_interp;
flat out int glyph_offset;
flat out ivec2 glyph_dim;
flat out int interp_size;
+#endif
void main()
{
diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
index 2033401db67..b4a75cc489b 100644
--- a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
@@ -1,21 +1,10 @@
-#if defined(USE_COLOR_U32)
-uniform uint color;
-#else
+#ifndef USE_GPU_SHADER_CREATE_INFO
uniform vec4 color;
-#endif
-
out vec4 fragColor;
+#endif
void main()
{
-#if defined(USE_COLOR_U32)
- fragColor = vec4(((color)&uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 24)) * (1.0f / 255.0f));
-#else
- fragColor = color;
-#endif
- fragColor = blender_srgb_to_framebuffer_space(fragColor);
+ fragColor = blender_srgb_to_framebuffer_space(color);
}
diff --git a/source/blender/editors/space_node/node_toolbar.cc b/source/blender/gpu/shaders/infos/gpu_clip_planes_info.hh
index c32dcbef91b..81b3c523628 100644
--- a/source/blender/editors/space_node/node_toolbar.cc
+++ b/source/blender/gpu/shaders/infos/gpu_clip_planes_info.hh
@@ -13,27 +13,17 @@
* 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) 2012 Blender Foundation.
+ * The Original Code is Copyright (C) 2022 Blender Foundation.
* All rights reserved.
*/
/** \file
- * \ingroup nodes
+ * \ingroup gpu
*/
-#include "BLI_utildefines.h"
+#include "gpu_shader_create_info.hh"
-#include "DNA_node_types.h"
-
-#include "BKE_context.h"
-#include "BKE_screen.h"
-
-#include "WM_api.h"
-
-#include "node_intern.hh" /* own include */
-
-/* ******************* node toolbar registration ************** */
-
-void node_toolbar_register(ARegionType *UNUSED(art))
-{
-}
+GPU_SHADER_CREATE_INFO(gpu_clip_planes)
+ .uniform_buf(1, "GPUClipPlanes", "clipPlanes", Frequency::PASS)
+ .typedef_source("GPU_shader_shared.h")
+ .define("USE_WORLD_CLIP_PLANES");
diff --git a/source/blender/gpu/shaders/infos/gpu_interface_info.hh b/source/blender/gpu/shaders/infos/gpu_interface_info.hh
new file mode 100644
index 00000000000..d5ad333638f
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_interface_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(flat_color_iface, "").flat(Type::VEC4, "finalColor");
+GPU_SHADER_INTERFACE_INFO(no_perspective_color_iface, "").no_perspective(Type::VEC4, "finalColor");
+GPU_SHADER_INTERFACE_INFO(smooth_color_iface, "").smooth(Type::VEC4, "finalColor");
+GPU_SHADER_INTERFACE_INFO(smooth_tex_coord_interp_iface, "").smooth(Type::VEC2, "texCoord_interp");
+GPU_SHADER_INTERFACE_INFO(smooth_radii_iface, "").smooth(Type::VEC2, "radii");
+GPU_SHADER_INTERFACE_INFO(smooth_radii_outline_iface, "").smooth(Type::VEC4, "radii");
+GPU_SHADER_INTERFACE_INFO(flat_color_smooth_tex_coord_interp_iface, "")
+ .flat(Type::VEC4, "finalColor")
+ .smooth(Type::VEC2, "texCoord_interp");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_area_borders_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_area_borders_info.hh
new file mode 100644
index 00000000000..b5dce51fc1b
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_area_borders_info.hh
@@ -0,0 +1,39 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(smooth_uv_iface, "").smooth(Type::VEC2, "uv");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_area_borders)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_out(smooth_uv_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::VEC4, "rect")
+ .push_constant(Type::VEC4, "color")
+ .push_constant(Type::FLOAT, "scale")
+ .push_constant(Type::INT, "cornerLen")
+ .vertex_source("gpu_shader_2D_area_borders_vert.glsl")
+ .fragment_source("gpu_shader_2D_area_borders_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_checker_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_checker_info.hh
new file mode 100644
index 00000000000..b8dbca276ae
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_checker_info.hh
@@ -0,0 +1,35 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_checker)
+ .vertex_in(0, Type::VEC2, "pos")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::VEC4, "color1")
+ .push_constant(Type::VEC4, "color2")
+ .push_constant(Type::INT, "size")
+ .vertex_source("gpu_shader_2D_vert.glsl")
+ .fragment_source("gpu_shader_checker_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_diag_stripes_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_diag_stripes_info.hh
new file mode 100644
index 00000000000..b52be8b328e
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_diag_stripes_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_diag_stripes)
+ .vertex_in(0, Type::VEC2, "pos")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::VEC4, "color1")
+ .push_constant(Type::VEC4, "color2")
+ .push_constant(Type::INT, "size1")
+ .push_constant(Type::INT, "size2")
+ .vertex_source("gpu_shader_2D_vert.glsl")
+ .fragment_source("gpu_shader_diag_stripes_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_flat_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_flat_color_info.hh
new file mode 100644
index 00000000000..699b0a456f9
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_flat_color_info.hh
@@ -0,0 +1,37 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+#include "gpu_interface_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_flat_color)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_out(flat_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_flat_color_vert.glsl")
+ .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_color_info.hh
new file mode 100644
index 00000000000..8ac9f58d936
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_color_info.hh
@@ -0,0 +1,30 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_color)
+ .additional_info("gpu_shader_2D_image_common")
+ .push_constant(Type::VEC4, "color")
+ .fragment_source("gpu_shader_image_color_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh
new file mode 100644
index 00000000000..3e10c0e1651
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_desaturate_color_info.hh
@@ -0,0 +1,31 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_desaturate_color)
+ .additional_info("gpu_shader_2D_image_common")
+ .push_constant(Type::VEC4, "color")
+ .push_constant(Type::FLOAT, "factor")
+ .fragment_source("gpu_shader_image_desaturate_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_info.hh
new file mode 100644
index 00000000000..989e38527c0
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_info.hh
@@ -0,0 +1,39 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_common)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_in(1, Type::VEC2, "texCoord")
+ .vertex_out(smooth_tex_coord_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .sampler(0, ImageType::FLOAT_2D, "image")
+ .vertex_source("gpu_shader_2D_image_vert.glsl");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image)
+ .additional_info("gpu_shader_2D_image_common")
+ .fragment_source("gpu_shader_image_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh
new file mode 100644
index 00000000000..4b154a045ee
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_multi_rect_color_info.hh
@@ -0,0 +1,13 @@
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_multi_rect_color)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_out(flat_color_smooth_tex_coord_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .uniform_buf(0, "MultiRectCallData", "multi_rect_data")
+ .sampler(0, ImageType::FLOAT_2D, "image")
+ .typedef_source("GPU_shader_shared.h")
+ .vertex_source("gpu_shader_2D_image_multi_rect_vert.glsl")
+ .fragment_source("gpu_shader_image_varying_color_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh
new file mode 100644
index 00000000000..d1a2a8f6ee7
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_merge_info.hh
@@ -0,0 +1,39 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_overlays_merge)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_in(1, Type::VEC2, "texCoord")
+ .vertex_out(smooth_tex_coord_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::BOOL, "display_transform")
+ .push_constant(Type::BOOL, "overlay")
+ .sampler(0, ImageType::FLOAT_2D, "image_texture")
+ .sampler(1, ImageType::FLOAT_2D, "overlays_texture")
+ .vertex_source("gpu_shader_2D_image_vert.glsl")
+ .fragment_source("gpu_shader_image_overlays_merge_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
new file mode 100644
index 00000000000..d099d95e4b6
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_overlays_stereo_merge_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_overlays_stereo_merge)
+ .vertex_in(0, Type::VEC2, "pos")
+ .fragment_out(0, Type::VEC4, "imageColor")
+ .fragment_out(1, Type::VEC4, "overlayColor")
+ .sampler(0, ImageType::FLOAT_2D, "imageTexture")
+ .sampler(1, ImageType::FLOAT_2D, "overlayTexture")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::INT, "stereoDisplaySettings")
+ .vertex_source("gpu_shader_2D_vert.glsl")
+ .fragment_source("gpu_shader_image_overlays_stereo_merge_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_rect_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_rect_color_info.hh
new file mode 100644
index 00000000000..9d5fb152561
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_rect_color_info.hh
@@ -0,0 +1,37 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_rect_color)
+ .vertex_out(smooth_tex_coord_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::VEC4, "color")
+ .push_constant(Type::VEC4, "rect_icon")
+ .push_constant(Type::VEC4, "rect_geom")
+ .sampler(0, ImageType::FLOAT_2D, "image")
+ .vertex_source("gpu_shader_2D_image_rect_vert.glsl")
+ .fragment_source("gpu_shader_image_color_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh
new file mode 100644
index 00000000000..93950b37509
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_image_shuffle_color_info.hh
@@ -0,0 +1,31 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_shuffle_color)
+ .additional_info("gpu_shader_2D_image_common")
+ .push_constant(Type::VEC4, "color")
+ .push_constant(Type::VEC4, "shuffle")
+ .fragment_source("gpu_shader_image_shuffle_color_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_line_dashed_uniform_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_line_dashed_uniform_color_info.hh
new file mode 100644
index 00000000000..afac24e6241
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_line_dashed_uniform_color_info.hh
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+/* TODO(jbakker): Skipped as data doesn't fit as push constant. */
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_line_dashed_uniform_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_out(flat_color_iface)
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_line_dashed_uniform_color_vert.glsl")
+ .fragment_source("gpu_shader_2D_line_dashed_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_nodelink_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_nodelink_info.hh
new file mode 100644
index 00000000000..15451899d5d
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_nodelink_info.hh
@@ -0,0 +1,72 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(nodelink_iface, "")
+ .smooth(Type::VEC4, "finalColor")
+ .smooth(Type::FLOAT, "colorGradient")
+ .smooth(Type::FLOAT, "lineU")
+ .flat(Type::FLOAT, "lineLength")
+ .flat(Type::FLOAT, "dashFactor")
+ .flat(Type::FLOAT, "dashAlpha")
+ .flat(Type::INT, "isMainLine");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_nodelink)
+ .vertex_in(0, Type::VEC2, "uv")
+ .vertex_in(1, Type::VEC2, "pos")
+ .vertex_in(2, Type::VEC2, "expand")
+ .vertex_out(nodelink_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .uniform_buf(0, "NodeLinkData", "node_link_data", Frequency::PASS)
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_nodelink_vert.glsl")
+ .fragment_source("gpu_shader_2D_nodelink_frag.glsl")
+ .typedef_source("GPU_shader_shared.h")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_nodelink_inst)
+ .vertex_in(0, Type::VEC2, "uv")
+ .vertex_in(1, Type::VEC2, "pos")
+ .vertex_in(2, Type::VEC2, "expand")
+ .vertex_in(3, Type::VEC2, "P0")
+ .vertex_in(4, Type::VEC2, "P1")
+ .vertex_in(5, Type::VEC2, "P2")
+ .vertex_in(6, Type::VEC2, "P3")
+ .vertex_in(7, Type::IVEC4, "colid_doarrow")
+ .vertex_in(8, Type::VEC4, "start_color")
+ .vertex_in(9, Type::VEC4, "end_color")
+ .vertex_in(10, Type::IVEC2, "domuted")
+ .vertex_in(11, Type::FLOAT, "dim_factor")
+ .vertex_in(12, Type::FLOAT, "thickness")
+ .vertex_in(13, Type::FLOAT, "dash_factor")
+ .vertex_in(14, Type::FLOAT, "dash_alpha")
+ .vertex_out(nodelink_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .uniform_buf(0, "NodeLinkInstanceData", "node_link_data", Frequency::PASS)
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_nodelink_vert.glsl")
+ .fragment_source("gpu_shader_2D_nodelink_frag.glsl")
+ .typedef_source("GPU_shader_shared.h")
+ .define("USE_INSTANCE")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh
new file mode 100644
index 00000000000..2a3d5698ba4
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_aa_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_point_uniform_size_uniform_color_aa)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_out(smooth_radii_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::VEC4, "color")
+ .push_constant(Type::FLOAT, "size")
+ .vertex_source("gpu_shader_2D_point_uniform_size_aa_vert.glsl")
+ .fragment_source("gpu_shader_point_uniform_color_aa_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh
new file mode 100644
index 00000000000..c7cc61e745b
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_uniform_size_uniform_color_outline_aa_info.hh
@@ -0,0 +1,38 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_point_uniform_size_uniform_color_outline_aa)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_out(smooth_radii_outline_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::VEC4, "color")
+ .push_constant(Type::VEC4, "outlineColor")
+ .push_constant(Type::FLOAT, "size")
+ .push_constant(Type::FLOAT, "outlineWidth")
+ .vertex_source("gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl")
+ .fragment_source("gpu_shader_point_uniform_color_outline_aa_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_point_varying_size_varying_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_varying_size_varying_color_info.hh
new file mode 100644
index 00000000000..38dddb4357e
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_point_varying_size_varying_color_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_point_varying_size_varying_color)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_in(1, Type::FLOAT, "size")
+ .vertex_in(2, Type::VEC4, "color")
+ .vertex_out(smooth_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_point_varying_size_varying_color_vert.glsl")
+ .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_smooth_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_smooth_color_info.hh
new file mode 100644
index 00000000000..128be12a7d9
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_smooth_color_info.hh
@@ -0,0 +1,36 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_smooth_color)
+ .vertex_in(0, Type::VEC2, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_out(smooth_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_2D_smooth_color_vert.glsl")
+ .fragment_source("gpu_shader_2D_smooth_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_2D_uniform_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_2D_uniform_color_info.hh
new file mode 100644
index 00000000000..3dab6d36753
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_2D_uniform_color_info.hh
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_2D_uniform_color)
+ .vertex_in(0, Type::VEC2, "pos")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::VEC4, "color")
+ .vertex_source("gpu_shader_2D_vert.glsl")
+ .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh
new file mode 100644
index 00000000000..63a4e679215
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_depth_only_info.hh
@@ -0,0 +1,37 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_depth_only)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_out(flat_color_iface)
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_vert.glsl")
+ .fragment_source("gpu_shader_depth_only_frag.glsl")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_depth_only_clipped)
+ .additional_info("gpu_shader_3D_depth_only")
+ .additional_info("gpu_clip_planes");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh
new file mode 100644
index 00000000000..4628f8bd6c4
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_flat_color_info.hh
@@ -0,0 +1,40 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_flat_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_out(flat_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_flat_color_vert.glsl")
+ .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_flat_color_clipped)
+ .additional_info("gpu_shader_3D_flat_color")
+ .additional_info("gpu_clip_planes");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh
new file mode 100644
index 00000000000..d47df129501
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_image_modulate_alpha_info.hh
@@ -0,0 +1,37 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_image_modulate_alpha)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC2, "texCoord")
+ .vertex_out(smooth_tex_coord_interp_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::FLOAT, "alpha")
+ .sampler(0, ImageType::FLOAT_2D, "image", Frequency::PASS)
+ .vertex_source("gpu_shader_3D_image_vert.glsl")
+ .fragment_source("gpu_shader_image_modulate_alpha_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_line_dashed_uniform_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_line_dashed_uniform_color_info.hh
new file mode 100644
index 00000000000..62c05d4677c
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_line_dashed_uniform_color_info.hh
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+/* TODO(jbakker): Skipped as data doesn't fit as push constant. */
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_line_dashed_uniform_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_out(flat_color_iface)
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_line_dashed_uniform_color_vert.glsl")
+ .fragment_source("gpu_shader_2D_line_dashed_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh
new file mode 100644
index 00000000000..d7b6806acc6
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_point_info.hh
@@ -0,0 +1,60 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_point_fixed_size_varying_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_out(smooth_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_point_fixed_size_varying_color_vert.glsl")
+ .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_point_varying_size_varying_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_in(2, Type::FLOAT, "size")
+ .vertex_out(smooth_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_point_varying_size_varying_color_vert.glsl")
+ .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_point_uniform_size_uniform_color_aa)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_out(smooth_radii_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::VEC4, "color")
+ .push_constant(Type::FLOAT, "size")
+ .vertex_source("gpu_shader_3D_point_uniform_size_aa_vert.glsl")
+ .fragment_source("gpu_shader_point_uniform_color_aa_frag.glsl")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_point_uniform_size_uniform_color_aa_clipped)
+ .additional_info("gpu_shader_3D_point_uniform_size_uniform_color_aa")
+ .additional_info("gpu_clip_planes");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh
new file mode 100644
index 00000000000..d2961c10a1f
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh
@@ -0,0 +1,32 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+/* TODO(jbakker): Skipped as it needs a uniform/storage buffer. */
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_polyline_uniform_color)
+ .vertex_source("gpu_shader_3D_polyline_vert.glsl")
+ .geometry_source("gpu_shader_3D_polyline_geom.glsl")
+ .fragment_source("gpu_shader_3D_polyline_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh
new file mode 100644
index 00000000000..10f6e9a5b83
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_smooth_color_info.hh
@@ -0,0 +1,40 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_smooth_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC4, "color")
+ .vertex_out(smooth_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .vertex_source("gpu_shader_3D_smooth_color_vert.glsl")
+ .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_smooth_color_clipped)
+ .additional_info("gpu_shader_3D_smooth_color")
+ .additional_info("gpu_clip_planes");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh
new file mode 100644
index 00000000000..e96ce8842f1
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_uniform_color_info.hh
@@ -0,0 +1,38 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_uniform_color)
+ .vertex_in(0, Type::VEC3, "pos")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::VEC4, "color")
+ .vertex_source("gpu_shader_3D_vert.glsl")
+ .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpu_shader_3D_uniform_color_clipped)
+ .additional_info("gpu_shader_3D_uniform_color")
+ .additional_info("gpu_clip_planes");
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh
new file mode 100644
index 00000000000..460ef3f5acf
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(gpencil_stroke_vert_iface, "geometry_in")
+ .smooth(Type::VEC4, "finalColor")
+ .smooth(Type::FLOAT, "finalThickness");
+GPU_SHADER_INTERFACE_INFO(gpencil_stroke_geom_iface, "geometry_out")
+ .smooth(Type::VEC4, "mColor")
+ .smooth(Type::VEC2, "mTexCoord");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke)
+ .vertex_in(0, Type::VEC4, "color")
+ .vertex_in(1, Type::VEC3, "pos")
+ .vertex_in(2, Type::FLOAT, "thickness")
+ .vertex_out(gpencil_stroke_vert_iface)
+ .geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::TRIANGLE_STRIP, 13)
+ .geometry_out(gpencil_stroke_geom_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+
+ .uniform_buf(0, "GPencilStrokeData", "gpencil_stroke_data")
+
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::MAT4, "ProjectionMatrix")
+ .vertex_source("gpu_shader_gpencil_stroke_vert.glsl")
+ .geometry_source("gpu_shader_gpencil_stroke_geom.glsl")
+ .fragment_source("gpu_shader_gpencil_stroke_frag.glsl")
+ .typedef_source("GPU_shader_shared.h")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh
new file mode 100644
index 00000000000..418ec0bef2d
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_instance_varying_color_varying_size_info.hh
@@ -0,0 +1,38 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_interface_info.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_shader_instance_varying_color_varying_size)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::MAT4, "InstanceModelMatrix")
+ .vertex_in(2, Type::VEC4, "color")
+ .vertex_in(3, Type::FLOAT, "size")
+ .vertex_out(flat_color_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ViewProjectionMatrix")
+ .vertex_source("gpu_shader_instance_variying_size_variying_color_vert.glsl")
+ .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_keyframe_shape_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_keyframe_shape_info.hh
new file mode 100644
index 00000000000..bbd3b6a9f01
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_keyframe_shape_info.hh
@@ -0,0 +1,46 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(keyframe_shape_iface, "")
+ .flat(Type::VEC4, "finalColor")
+ .flat(Type::VEC4, "finalOutlineColor")
+ .flat(Type::VEC4, "radii")
+ .flat(Type::VEC4, "thresholds")
+ .flat(Type::INT, "finalFlags");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_keyframe_shape)
+ .vertex_in(0, Type::VEC4, "color")
+ .vertex_in(1, Type::VEC4, "outlineColor")
+ .vertex_in(2, Type::VEC2, "pos")
+ .vertex_in(3, Type::FLOAT, "size")
+ .vertex_in(4, Type ::INT, "flags")
+ .vertex_out(keyframe_shape_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::VEC2, "ViewportSize")
+ .push_constant(Type::FLOAT, "outline_scale")
+ .vertex_source("gpu_shader_keyframe_shape_vert.glsl")
+ .fragment_source("gpu_shader_keyframe_shape_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_simple_lighting_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_simple_lighting_info.hh
new file mode 100644
index 00000000000..8afa7d79f3f
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_simple_lighting_info.hh
@@ -0,0 +1,40 @@
+
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(smooth_normal_iface, "").smooth(Type::VEC3, "normal");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_simple_lighting)
+ .vertex_in(0, Type::VEC3, "pos")
+ .vertex_in(1, Type::VEC3, "nor")
+ .vertex_out(smooth_normal_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .uniform_buf(0, "SimpleLightingData", "simple_lighting_data", Frequency::PASS)
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .push_constant(Type::MAT3, "NormalMatrix")
+ .typedef_source("GPU_shader_shared.h")
+ .vertex_source("gpu_shader_3D_normal_vert.glsl")
+ .fragment_source("gpu_shader_simple_lighting_frag.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_shader_text_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_text_info.hh
new file mode 100644
index 00000000000..9429db66f90
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_shader_text_info.hh
@@ -0,0 +1,45 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(text_iface, "")
+ .flat(Type::VEC4, "color_flat")
+ .no_perspective(Type::VEC2, "texCoord_interp")
+ .flat(Type::INT, "glyph_offset")
+ .flat(Type::IVEC2, "glyph_dim")
+ .flat(Type::INT, "interp_size");
+
+GPU_SHADER_CREATE_INFO(gpu_shader_text)
+ .vertex_in(0, Type::VEC4, "pos")
+ .vertex_in(1, Type::VEC4, "col")
+ .vertex_in(2, Type ::IVEC2, "glyph_size")
+ .vertex_in(3, Type ::INT, "offset")
+ .vertex_out(text_iface)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .push_constant(Type::MAT4, "ModelViewProjectionMatrix")
+ .sampler(0, ImageType::FLOAT_2D, "glyph", Frequency::PASS)
+ .vertex_source("gpu_shader_text_vert.glsl")
+ .fragment_source("gpu_shader_text_frag.glsl")
+ .additional_info("gpu_srgb_to_framebuffer_space")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/infos/gpu_srgb_to_framebuffer_space_info.hh b/source/blender/gpu/shaders/infos/gpu_srgb_to_framebuffer_space_info.hh
new file mode 100644
index 00000000000..3af49b56ab1
--- /dev/null
+++ b/source/blender/gpu/shaders/infos/gpu_srgb_to_framebuffer_space_info.hh
@@ -0,0 +1,27 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpu_srgb_to_framebuffer_space)
+ .define("blender_srgb_to_framebuffer_space(a) a");
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
index 6ffa6b59572..59f0377869b 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair_info.glsl
@@ -1,15 +1,4 @@
-float wang_hash_noise(uint s)
-{
- s = (s ^ 61u) ^ (s >> 16u);
- s *= 9u;
- s = s ^ (s >> 4u);
- s *= 0x27d4eb2du;
- s = s ^ (s >> 15u);
-
- return fract(float(s) / 4294967296.0);
-}
-
void node_hair_info(float hair_length,
out float is_strand,
out float intercept,
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl
index 86191451e5f..cb798047791 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_hash.glsl
@@ -215,3 +215,14 @@ float integer_noise(int n)
nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
return 0.5 * (float(nn) / 1073741824.0);
}
+
+float wang_hash_noise(uint s)
+{
+ s = (s ^ 61u) ^ (s >> 16u);
+ s *= 9u;
+ s = s ^ (s >> 4u);
+ s *= 0x27d4eb2du;
+ s = s ^ (s >> 15u);
+
+ return fract(float(s) / 4294967296.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
new file mode 100644
index 00000000000..d717ac97b28
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_point_info.glsl
@@ -0,0 +1,13 @@
+
+void node_point_info(out vec3 position, out float radius, out float random)
+{
+#ifdef POINTCLOUD_SHADER
+ position = pointPosition;
+ radius = pointRadius;
+ random = wang_hash_noise(uint(pointID));
+#else
+ position = vec3(0.0, 0.0, 0.0);
+ radius = 0.0;
+ random = 0.0;
+#endif
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
index 0f69a4b9aa0..c8219848e29 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_voronoi.glsl
@@ -72,7 +72,7 @@ void node_tex_voronoi_smooth_f1_1d(vec3 coord,
out float outRadius)
{
randomness = clamp(randomness, 0.0, 1.0);
- smoothness = clamp(smoothness / 2.0, 0, 0.5);
+ smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
float scaledCoord = w * scale;
float cellPosition = floor(scaledCoord);
@@ -301,7 +301,7 @@ void node_tex_voronoi_smooth_f1_2d(vec3 coord,
out float outRadius)
{
randomness = clamp(randomness, 0.0, 1.0);
- smoothness = clamp(smoothness / 2.0, 0, 0.5);
+ smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
vec2 scaledCoord = coord.xy * scale;
vec2 cellPosition = floor(scaledCoord);
@@ -565,7 +565,7 @@ void node_tex_voronoi_smooth_f1_3d(vec3 coord,
out float outRadius)
{
randomness = clamp(randomness, 0.0, 1.0);
- smoothness = clamp(smoothness / 2.0, 0, 0.5);
+ smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
vec3 scaledCoord = coord * scale;
vec3 cellPosition = floor(scaledCoord);
@@ -852,7 +852,7 @@ void node_tex_voronoi_smooth_f1_4d(vec3 coord,
out float outRadius)
{
randomness = clamp(randomness, 0.0, 1.0);
- smoothness = clamp(smoothness / 2.0, 0, 0.5);
+ smoothness = clamp(smoothness / 2.0, 0.0, 0.5);
vec4 scaledCoord = vec4(coord, w) * scale;
vec4 cellPosition = floor(scaledCoord);
diff --git a/source/blender/gpu/tests/gpu_shader_builtin_test.cc b/source/blender/gpu/tests/gpu_shader_builtin_test.cc
index 523a7e5b881..6d6a772f5fb 100644
--- a/source/blender/gpu/tests/gpu_shader_builtin_test.cc
+++ b/source/blender/gpu/tests/gpu_shader_builtin_test.cc
@@ -29,7 +29,6 @@ static void test_shader_builtin()
test_compile_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE);
test_compile_builtin_shader(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
test_compile_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- test_compile_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
test_compile_builtin_shader(GPU_SHADER_TEXT, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_KEYFRAME_SHAPE, GPU_SHADER_CFG_DEFAULT);
@@ -53,40 +52,22 @@ static void test_shader_builtin()
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR,
- GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA,
- GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR,
- GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR,
- GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR,
GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR,
- GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR,
GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_GPENCIL_STROKE, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_AREA_EDGES, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_AREA_BORDERS, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_BASE, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_BASE_INST, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_SHADOW, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_NODELINK, GPU_SHADER_CFG_DEFAULT);
test_compile_builtin_shader(GPU_SHADER_2D_NODELINK_INST, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_VERTS, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_FACEDOTS, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_EDGES, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_EDGES_SMOOTH, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_FACES, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_FACES_STRETCH_AREA, GPU_SHADER_CFG_DEFAULT);
- test_compile_builtin_shader(GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE, GPU_SHADER_CFG_DEFAULT);
}
GPU_TEST(shader_builtin)
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index 949efb522f3..4a4e22ed884 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -284,7 +284,7 @@ static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *co
/* setup the chain data */
/* create a target */
- target = (PoseTarget *)MEM_callocN(sizeof(PoseTarget), "posetarget");
+ target = MEM_cnew<PoseTarget>("posetarget");
target->con = con;
/* by construction there can be only one tree per channel
* and each channel can be part of at most one tree. */
@@ -292,7 +292,7 @@ static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *co
if (tree == nullptr) {
/* make new tree */
- tree = (PoseTree *)MEM_callocN(sizeof(PoseTree), "posetree");
+ tree = MEM_cnew<PoseTree>("posetree");
tree->iterations = data->iterations;
tree->totchannel = segcount;
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 3ea8ac47f17..30f2f24447f 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -72,7 +72,7 @@ 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
+ * Gray-scale, 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
@@ -177,20 +177,20 @@ void IMB_colormanagement_colorspace_to_scene_linear(float *buffer,
bool predivide);
void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
- const int x,
- const int y,
- const int width,
- const int height,
+ int x,
+ int y,
+ int width,
+ int height,
const struct ImBuf *ibuf,
- const bool compress_as_srgb,
- const bool store_premultiplied);
+ bool compress_as_srgb,
+ bool store_premultiplied);
void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
- const int offset_x,
- const int offset_y,
- const int width,
- const int height,
+ int offset_x,
+ int offset_y,
+ int width,
+ int height,
const struct ImBuf *ibuf,
- const bool store_premultiplied);
+ bool store_premultiplied);
/**
* Conversion between color picking role. Typically we would expect such a
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index ecc14e72108..a557d7dc6d1 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -379,7 +379,8 @@ struct IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size proxy_sizes_in_use,
int quality,
const bool overwrite,
- struct GSet *file_list);
+ struct GSet *file_list,
+ bool build_only_on_bad_performance);
/**
* Will rebuild all used indices and proxies at once.
@@ -431,6 +432,7 @@ bool IMB_anim_can_produce_frames(const struct anim *anim);
int ismovie(const char *filepath);
int IMB_anim_get_image_width(struct anim *anim);
int IMB_anim_get_image_height(struct anim *anim);
+bool IMB_get_gop_decode_time(struct anim *anim);
/**
*
@@ -536,7 +538,7 @@ void IMB_scaleImBuf_threaded(struct ImBuf *ibuf, unsigned int newx, unsigned int
* \attention Defined in writeimage.c
*/
bool IMB_saveiff(struct ImBuf *ibuf, const char *filepath, int flags);
-bool IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf);
+bool IMB_prepare_write_ImBuf(bool isfloat, struct ImBuf *ibuf);
/**
*
@@ -544,7 +546,7 @@ bool IMB_prepare_write_ImBuf(const bool isfloat, struct ImBuf *ibuf);
*/
bool IMB_ispic(const char *filepath);
bool IMB_ispic_type_matches(const char *filepath, int filetype);
-int IMB_ispic_type_from_memory(const unsigned char *buf, const size_t buf_size);
+int IMB_ispic_type_from_memory(const unsigned char *buf, size_t buf_size);
int IMB_ispic_type(const char *filepath);
/**
@@ -837,7 +839,7 @@ void IMB_rectfill_area(struct ImBuf *ibuf,
*/
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);
+void IMB_rectfill_alpha(struct ImBuf *ibuf, float value);
/**
* This should not be here, really,
@@ -921,16 +923,16 @@ typedef enum eIMBTransformMode {
* 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.
+ * 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 grey scale value.
+ * 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,
- const eIMBTransformMode mode,
- const eIMBInterpolationFilterMode filter,
+ eIMBTransformMode mode,
+ eIMBInterpolationFilterMode filter,
const float transform_matrix[4][4],
const struct rctf *src_crop);
@@ -972,28 +974,20 @@ void IMB_update_gpu_texture_sub(struct GPUTexture *tex,
/**
* \attention defined in stereoimbuf.c
*/
-void IMB_stereo3d_write_dimensions(const char mode,
- const bool is_squeezed,
- const size_t width,
- const size_t height,
- size_t *r_width,
- size_t *r_height);
-void IMB_stereo3d_read_dimensions(const char mode,
- const bool is_squeezed,
- const size_t width,
- const size_t height,
- size_t *r_width,
- size_t *r_height);
+void IMB_stereo3d_write_dimensions(
+ char mode, bool is_squeezed, size_t width, size_t height, size_t *r_width, size_t *r_height);
+void IMB_stereo3d_read_dimensions(
+ char mode, bool is_squeezed, size_t width, size_t height, size_t *r_width, size_t *r_height);
int *IMB_stereo3d_from_rect(struct ImageFormatData *im_format,
- const size_t x,
- const size_t y,
- const size_t channels,
+ size_t x,
+ size_t y,
+ size_t channels,
int *rect_left,
int *rect_right);
float *IMB_stereo3d_from_rectf(struct ImageFormatData *im_format,
- const size_t x,
- const size_t y,
- const size_t channels,
+ size_t x,
+ size_t y,
+ size_t channels,
float *rectf_left,
float *rectf_right);
/**
diff --git a/source/blender/imbuf/IMB_metadata.h b/source/blender/imbuf/IMB_metadata.h
index 652ce913ee5..50982d08c3e 100644
--- a/source/blender/imbuf/IMB_metadata.h
+++ b/source/blender/imbuf/IMB_metadata.h
@@ -58,10 +58,7 @@ void IMB_metadata_free(struct IDProperty *metadata);
* \param len: length of value buffer allocated by user.
* \return 1 (true) if metadata is present and value for the key found, 0 (false) otherwise.
*/
-bool IMB_metadata_get_field(struct IDProperty *metadata,
- const char *key,
- char *value,
- const size_t len);
+bool IMB_metadata_get_field(struct IDProperty *metadata, const char *key, char *value, size_t len);
/**
* Set user data in the metadata.
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 104458ffa7a..bf6aef3ecd3 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -41,7 +41,7 @@ typedef struct ImFileType {
* \note that this may only read in a small part of the files header,
* see: #IMB_ispic_type for details.
*/
- bool (*is_a)(const unsigned char *buf, const size_t size);
+ bool (*is_a)(const unsigned char *buf, size_t size);
/** Load an image from memory. */
struct ImBuf *(*load)(const unsigned char *mem,
@@ -93,7 +93,7 @@ void imb_tile_cache_tile_free(struct ImBuf *ibuf, int tx, int ty);
/** \name Format: PNG (#IMB_FTYPE_PNG)
* \{ */
-bool imb_is_a_png(const unsigned char *mem, const size_t size);
+bool imb_is_a_png(const unsigned char *mem, size_t size);
struct ImBuf *imb_loadpng(const unsigned char *mem,
size_t size,
int flags,
@@ -106,7 +106,7 @@ bool imb_savepng(struct ImBuf *ibuf, const char *filepath, int flags);
/** \name Format: TARGA (#IMB_FTYPE_TGA)
* \{ */
-bool imb_is_a_targa(const unsigned char *buf, const size_t size);
+bool imb_is_a_targa(const unsigned char *buf, size_t size);
struct ImBuf *imb_loadtarga(const unsigned char *mem,
size_t size,
int flags,
@@ -119,7 +119,7 @@ bool imb_savetarga(struct ImBuf *ibuf, const char *filepath, int flags);
/** \name Format: IRIS (#IMB_FTYPE_IMAGIC)
* \{ */
-bool imb_is_a_iris(const unsigned char *mem, const size_t size);
+bool imb_is_a_iris(const unsigned char *mem, size_t size);
/**
* Read in a B/W RGB or RGBA iris image file and return an image buffer.
*/
@@ -135,7 +135,7 @@ bool imb_saveiris(struct ImBuf *ibuf, const char *filepath, int flags);
/** \name Format: JP2 (#IMB_FTYPE_JP2)
* \{ */
-bool imb_is_a_jp2(const unsigned char *buf, const size_t size);
+bool imb_is_a_jp2(const unsigned char *buf, size_t size);
struct ImBuf *imb_load_jp2(const unsigned char *mem,
size_t size,
int flags,
@@ -151,7 +151,7 @@ bool imb_save_jp2(struct ImBuf *ibuf, const char *filepath, int flags);
/** \name Format: JPEG (#IMB_FTYPE_JPG)
* \{ */
-bool imb_is_a_jpeg(const unsigned char *mem, const size_t size);
+bool imb_is_a_jpeg(const unsigned char *mem, size_t size);
bool imb_savejpeg(struct ImBuf *ibuf, const char *filepath, int flags);
struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
size_t size,
@@ -164,7 +164,7 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
/** \name Format: BMP (#IMB_FTYPE_BMP)
* \{ */
-bool imb_is_a_bmp(const unsigned char *buf, const size_t size);
+bool imb_is_a_bmp(const unsigned char *buf, size_t size);
struct ImBuf *imb_bmp_decode(const unsigned char *mem,
size_t size,
int flags,
@@ -178,7 +178,7 @@ bool imb_savebmp(struct ImBuf *ibuf, const char *filepath, int flags);
/** \name Format: CINEON (#IMB_FTYPE_CINEON)
* \{ */
-bool imb_is_a_cineon(const unsigned char *buf, const size_t size);
+bool imb_is_a_cineon(const unsigned char *buf, size_t size);
bool imb_save_cineon(struct ImBuf *buf, const char *filepath, int flags);
struct ImBuf *imb_load_cineon(const unsigned char *mem,
size_t size,
@@ -191,7 +191,7 @@ struct ImBuf *imb_load_cineon(const unsigned char *mem,
/** \name Format: DPX (#IMB_FTYPE_DPX)
* \{ */
-bool imb_is_a_dpx(const unsigned char *buf, const size_t size);
+bool imb_is_a_dpx(const unsigned char *buf, size_t size);
bool imb_save_dpx(struct ImBuf *buf, const char *filepath, int flags);
struct ImBuf *imb_load_dpx(const unsigned char *mem,
size_t size,
@@ -204,7 +204,7 @@ struct ImBuf *imb_load_dpx(const unsigned char *mem,
/** \name Format: HDR (#IMB_FTYPE_RADHDR)
* \{ */
-bool imb_is_a_hdr(const unsigned char *buf, const size_t size);
+bool imb_is_a_hdr(const unsigned char *buf, size_t size);
struct ImBuf *imb_loadhdr(const unsigned char *mem,
size_t size,
int flags,
@@ -218,7 +218,7 @@ bool imb_savehdr(struct ImBuf *ibuf, const char *filepath, int flags);
* \{ */
void imb_inittiff(void);
-bool imb_is_a_tiff(const unsigned char *buf, const size_t size);
+bool imb_is_a_tiff(const unsigned char *buf, size_t size);
/**
* Loads a TIFF file.
* \param mem: Memory containing the TIFF file.
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 1d81653c7cd..17e82fc79c9 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -504,11 +504,6 @@ static ImBuf *avi_fetchibuf(struct anim *anim, int position)
#ifdef WITH_FFMPEG
-BLI_INLINE bool need_aligned_ffmpeg_buffer(struct anim *anim)
-{
- return (anim->x & 31) != 0;
-}
-
static int startffmpeg(struct anim *anim)
{
int i, video_stream_index;
@@ -707,23 +702,20 @@ static int startffmpeg(struct anim *anim)
anim->pFrameComplete = false;
anim->pFrameDeinterlaced = av_frame_alloc();
anim->pFrameRGB = av_frame_alloc();
+ anim->pFrameRGB->format = AV_PIX_FMT_RGBA;
+ anim->pFrameRGB->width = anim->x;
+ anim->pFrameRGB->height = anim->y;
- if (need_aligned_ffmpeg_buffer(anim)) {
- anim->pFrameRGB->format = AV_PIX_FMT_RGBA;
- anim->pFrameRGB->width = anim->x;
- anim->pFrameRGB->height = anim->y;
-
- if (av_frame_get_buffer(anim->pFrameRGB, 32) < 0) {
- fprintf(stderr, "Could not allocate frame data.\n");
- avcodec_free_context(&anim->pCodecCtx);
- avformat_close_input(&anim->pFormatCtx);
- av_packet_free(&anim->cur_packet);
- av_frame_free(&anim->pFrameRGB);
- av_frame_free(&anim->pFrameDeinterlaced);
- av_frame_free(&anim->pFrame);
- anim->pCodecCtx = NULL;
- return -1;
- }
+ if (av_frame_get_buffer(anim->pFrameRGB, 0) < 0) {
+ fprintf(stderr, "Could not allocate frame data.\n");
+ avcodec_free_context(&anim->pCodecCtx);
+ avformat_close_input(&anim->pFormatCtx);
+ av_packet_free(&anim->cur_packet);
+ av_frame_free(&anim->pFrameRGB);
+ av_frame_free(&anim->pFrameDeinterlaced);
+ av_frame_free(&anim->pFrame);
+ anim->pCodecCtx = NULL;
+ return -1;
}
if (av_image_get_buffer_size(AV_PIX_FMT_RGBA, anim->x, anim->y, 1) != anim->x * anim->y * 4) {
@@ -851,91 +843,26 @@ static void ffmpeg_postprocess(struct anim *anim)
}
}
- if (!need_aligned_ffmpeg_buffer(anim)) {
- av_image_fill_arrays(anim->pFrameRGB->data,
- anim->pFrameRGB->linesize,
- (unsigned char *)ibuf->rect,
- AV_PIX_FMT_RGBA,
- anim->x,
- anim->y,
- 1);
- }
-
-# if defined(__x86_64__) || defined(_M_X64)
- /* Scale and flip image over Y axis in one go, using negative strides.
- * This doesn't work with ARM/PowerPC though and may be misusing the API.
- * Limit it x86_64 where it appears to work.
- * http://trac.ffmpeg.org/ticket/9060 */
- int *dstStride = anim->pFrameRGB->linesize;
- uint8_t **dst = anim->pFrameRGB->data;
- const int dstStride2[4] = {-dstStride[0], 0, 0, 0};
- uint8_t *dst2[4] = {dst[0] + (anim->y - 1) * dstStride[0], 0, 0, 0};
-
sws_scale(anim->img_convert_ctx,
(const uint8_t *const *)input->data,
input->linesize,
0,
anim->y,
- dst2,
- dstStride2);
-# else
- /* Scale with swscale then flip image over Y axis. */
- int *dstStride = anim->pFrameRGB->linesize;
- uint8_t **dst = anim->pFrameRGB->data;
- const int dstStride2[4] = {dstStride[0], 0, 0, 0};
- uint8_t *dst2[4] = {dst[0], 0, 0, 0};
- int x, y, h, w;
- unsigned char *bottom;
- unsigned char *top;
-
- sws_scale(anim->img_convert_ctx,
- (const uint8_t *const *)input->data,
- input->linesize,
- 0,
- anim->y,
- dst2,
- dstStride2);
-
- bottom = (unsigned char *)ibuf->rect;
- top = bottom + ibuf->x * (ibuf->y - 1) * 4;
-
- h = (ibuf->y + 1) / 2;
- w = ibuf->x;
-
- for (y = 0; y < h; y++) {
- unsigned char tmp[4];
- unsigned int *tmp_l = (unsigned int *)tmp;
-
- for (x = 0; x < w; x++) {
- tmp[0] = bottom[0];
- tmp[1] = bottom[1];
- tmp[2] = bottom[2];
- tmp[3] = bottom[3];
-
- bottom[0] = top[0];
- bottom[1] = top[1];
- bottom[2] = top[2];
- bottom[3] = top[3];
-
- *(unsigned int *)top = *tmp_l;
-
- bottom += 4;
- top += 4;
- }
- top -= 8 * w;
- }
-# endif
-
- if (need_aligned_ffmpeg_buffer(anim)) {
- uint8_t *buf_src = anim->pFrameRGB->data[0];
- uint8_t *buf_dst = (uint8_t *)ibuf->rect;
- for (int y = 0; y < anim->y; y++) {
- memcpy(buf_dst, buf_src, anim->x * 4);
- buf_dst += anim->x * 4;
- buf_src += anim->pFrameRGB->linesize[0];
- }
- }
-
+ anim->pFrameRGB->data,
+ anim->pFrameRGB->linesize);
+
+ /* Copy the valid bytes from the aligned buffer vertically flipped into ImBuf */
+ int aligned_stride = anim->pFrameRGB->linesize[0];
+ const uint8_t *const src[4] = {
+ anim->pFrameRGB->data[0] + (anim->y - 1) * aligned_stride, 0, 0, 0};
+ /* NOTE: Negative linesize is used to copy and flip image at once with function
+ * `av_image_copy_to_buffer`. This could cause issues in future and image may need to be flipped
+ * explicitly. */
+ const int src_linesize[4] = {-anim->pFrameRGB->linesize[0], 0, 0, 0};
+ int dst_size = av_image_get_buffer_size(
+ anim->pFrameRGB->format, anim->pFrameRGB->width, anim->pFrameRGB->height, 1);
+ av_image_copy_to_buffer(
+ (uint8_t *)ibuf->rect, dst_size, src, src_linesize, AV_PIX_FMT_RGBA, anim->x, anim->y, 1);
if (filter_y) {
IMB_filtery(ibuf);
}
@@ -1481,20 +1408,6 @@ static void free_anim_ffmpeg(struct anim *anim)
av_packet_free(&anim->cur_packet);
av_frame_free(&anim->pFrame);
-
- if (!need_aligned_ffmpeg_buffer(anim)) {
- /* If there's no need for own aligned buffer it means that FFmpeg's
- * frame shares the same buffer as temporary ImBuf. In this case we
- * should not free the buffer when freeing the FFmpeg buffer.
- */
- av_image_fill_arrays(anim->pFrameRGB->data,
- anim->pFrameRGB->linesize,
- NULL,
- AV_PIX_FMT_RGBA,
- anim->x,
- anim->y,
- 1);
- }
av_frame_free(&anim->pFrameRGB);
av_frame_free(&anim->pFrameDeinterlaced);
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c
index 1223033f535..758b21f8cda 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.c
+++ b/source/blender/imbuf/intern/cineon/cineonlib.c
@@ -239,13 +239,13 @@ LogImageFile *cineonOpen(const unsigned char *byteStuff, int fromMemory, size_t
}
if (cineon->depth == 1) {
- /* Grayscale image */
+ /* Gray-scale image. */
cineon->element[0].descriptor = descriptor_Luminance;
cineon->element[0].transfer = transfer_Linear;
cineon->element[0].depth = 1;
}
else if (cineon->depth == 3) {
- /* RGB image */
+ /* RGB image. */
if (cineon->numElements == 1) {
cineon->element[0].descriptor = descriptor_RGB;
cineon->element[0].transfer = transfer_PrintingDensity;
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp
index 359d6f30cdc..6686d56e9d1 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.cpp
+++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp
@@ -168,9 +168,16 @@ static void FlipDXT5BlockHalf(uint8_t *block)
FlipDXT1BlockHalf(block + 8);
}
-int FlipDXTCImage(
- unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data)
+int FlipDXTCImage(unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ int fourcc,
+ uint8_t *data,
+ int data_size,
+ unsigned int *r_num_valid_levels)
{
+ *r_num_valid_levels = 0;
+
/* Must have valid dimensions. */
if (width == 0 || height == 0) {
return 0;
@@ -204,14 +211,25 @@ int FlipDXTCImage(
return 0;
}
+ *r_num_valid_levels = levels;
+
unsigned int mip_width = width;
unsigned int mip_height = height;
+ const uint8_t *data_end = data + data_size;
+
for (unsigned int i = 0; i < levels; i++) {
unsigned int blocks_per_row = (mip_width + 3) / 4;
unsigned int blocks_per_col = (mip_height + 3) / 4;
unsigned int blocks = blocks_per_row * blocks_per_col;
+ if (data + block_bytes * blocks > data_end) {
+ /* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
+ * on a malformed files. */
+ *r_num_valid_levels = i;
+ break;
+ }
+
if (mip_height == 1) {
/* no flip to do, and we're done. */
break;
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.h b/source/blender/imbuf/intern/dds/FlipDXT.h
index b4f71e4eca7..f9d3ce6112e 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.h
+++ b/source/blender/imbuf/intern/dds/FlipDXT.h
@@ -23,5 +23,10 @@
*
* Use to flip vertically to fit OpenGL convention.
*/
-int FlipDXTCImage(
- unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data);
+int FlipDXTCImage(unsigned int width,
+ unsigned int height,
+ unsigned int levels,
+ int fourcc,
+ uint8_t *data,
+ int data_size,
+ unsigned int *r_num_valid_levels);
diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp
index 3dab3c35675..31bf2076ed1 100644
--- a/source/blender/imbuf/intern/dds/Stream.cpp
+++ b/source/blender/imbuf/intern/dds/Stream.cpp
@@ -26,6 +26,21 @@
static const char *msg_error_seek = "DDS: trying to seek beyond end of stream (corrupt file?)";
static const char *msg_error_read = "DDS: trying to read beyond end of stream (corrupt file?)";
+inline bool is_read_within_bounds(const Stream &mem, unsigned int cnt)
+{
+ if (mem.pos >= mem.size) {
+ /* No more data remained in the memory buffer. */
+ return false;
+ }
+
+ if (cnt > mem.size - mem.pos) {
+ /* Reading past the memory bounds. */
+ return false;
+ }
+
+ return true;
+}
+
unsigned int Stream::seek(unsigned int p)
{
if (p > size) {
@@ -40,7 +55,7 @@ unsigned int Stream::seek(unsigned int p)
unsigned int mem_read(Stream &mem, unsigned long long &i)
{
- if (mem.pos + 8 > mem.size) {
+ if (!is_read_within_bounds(mem, 8)) {
mem.set_failed(msg_error_seek);
return 0;
}
@@ -51,7 +66,7 @@ unsigned int mem_read(Stream &mem, unsigned long long &i)
unsigned int mem_read(Stream &mem, unsigned int &i)
{
- if (mem.pos + 4 > mem.size) {
+ if (!is_read_within_bounds(mem, 4)) {
mem.set_failed(msg_error_read);
return 0;
}
@@ -62,7 +77,7 @@ unsigned int mem_read(Stream &mem, unsigned int &i)
unsigned int mem_read(Stream &mem, unsigned short &i)
{
- if (mem.pos + 2 > mem.size) {
+ if (!is_read_within_bounds(mem, 2)) {
mem.set_failed(msg_error_read);
return 0;
}
@@ -73,7 +88,7 @@ unsigned int mem_read(Stream &mem, unsigned short &i)
unsigned int mem_read(Stream &mem, unsigned char &i)
{
- if (mem.pos + 1 > mem.size) {
+ if (!is_read_within_bounds(mem, 1)) {
mem.set_failed(msg_error_read);
return 0;
}
@@ -84,7 +99,7 @@ unsigned int mem_read(Stream &mem, unsigned char &i)
unsigned int mem_read(Stream &mem, unsigned char *i, unsigned int cnt)
{
- if (mem.pos + cnt > mem.size) {
+ if (!is_read_within_bounds(mem, cnt)) {
mem.set_failed(msg_error_read);
return 0;
}
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index 1729a9a64f8..f576209ff62 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -186,8 +186,13 @@ struct ImBuf *imb_load_dds(const unsigned char *mem,
/* flip compressed texture */
if (ibuf->dds_data.data) {
- FlipDXTCImage(
- dds.width(), dds.height(), dds.mipmapCount(), dds.fourCC(), ibuf->dds_data.data);
+ FlipDXTCImage(dds.width(),
+ dds.height(),
+ ibuf->dds_data.nummipmaps,
+ dds.fourCC(),
+ ibuf->dds_data.data,
+ ibuf->dds_data.size,
+ &ibuf->dds_data.nummipmaps);
}
}
else {
diff --git a/source/blender/imbuf/intern/dds/dds_api.h b/source/blender/imbuf/intern/dds/dds_api.h
index 931c4f267f9..2d540f13a52 100644
--- a/source/blender/imbuf/intern/dds/dds_api.h
+++ b/source/blender/imbuf/intern/dds/dds_api.h
@@ -26,7 +26,7 @@
extern "C" {
#endif
-bool imb_is_a_dds(const unsigned char *mem, const size_t size);
+bool imb_is_a_dds(const unsigned char *mem, size_t size);
bool imb_save_dds(struct ImBuf *ibuf, const char *name, int flags);
struct ImBuf *imb_load_dds(const unsigned char *mem,
size_t size,
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index 4841f7b5039..ff86fbfdd38 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -824,7 +824,7 @@ void IMB_float_from_rect(ImBuf *ibuf)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Color to Grayscale
+/** \name Color to Gray-Scale
* \{ */
void IMB_color_to_bw(ImBuf *ibuf)
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 6cd87e29c9d..a85ba65d014 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -37,6 +37,8 @@
# include "BLI_winstuff.h"
#endif
+#include "PIL_time.h"
+
#include "IMB_anim.h"
#include "IMB_indexer.h"
#include "imbuf.h"
@@ -170,7 +172,6 @@ struct anim_index *IMB_indexer_open(const char *name)
int i;
if (!fp) {
- fprintf(stderr, "Couldn't open indexer file: %s\n", name);
return NULL;
}
@@ -815,12 +816,16 @@ typedef struct FFmpegIndexBuilderContext {
double pts_time_base;
int frameno, frameno_gapless;
int start_pts_set;
+
+ bool build_only_on_bad_performance;
+ bool building_cancelled;
} FFmpegIndexBuilderContext;
static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
IMB_Timecode_Type tcs_in_use,
IMB_Proxy_Size proxy_sizes_in_use,
- int quality)
+ int quality,
+ bool build_only_on_bad_performance)
{
FFmpegIndexBuilderContext *context = MEM_callocN(sizeof(FFmpegIndexBuilderContext),
"FFmpeg index builder context");
@@ -832,6 +837,7 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
context->proxy_sizes_in_use = proxy_sizes_in_use;
context->num_proxy_sizes = IMB_PROXY_MAX_SLOT;
context->num_indexers = IMB_TC_MAX_SLOT;
+ context->build_only_on_bad_performance = build_only_on_bad_performance;
memset(context->proxy_ctx, 0, sizeof(context->proxy_ctx));
memset(context->indexer, 0, sizeof(context->indexer));
@@ -937,15 +943,17 @@ static void index_rebuild_ffmpeg_finish(FFmpegIndexBuilderContext *context, int
{
int i;
+ const bool do_rollback = stop || context->building_cancelled;
+
for (i = 0; i < context->num_indexers; i++) {
if (context->tcs_in_use & tc_types[i]) {
- IMB_index_builder_finish(context->indexer[i], stop);
+ IMB_index_builder_finish(context->indexer[i], do_rollback);
}
}
for (i = 0; i < context->num_proxy_sizes; i++) {
if (context->proxy_sizes_in_use & proxy_sizes[i]) {
- free_proxy_output_ffmpeg(context->proxy_ctx[i], stop);
+ free_proxy_output_ffmpeg(context->proxy_ctx[i], do_rollback);
}
}
@@ -1096,6 +1104,111 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
return 1;
}
+/* Get number of frames, that can be decoded in specified time period. */
+static int indexer_performance_get_decode_rate(FFmpegIndexBuilderContext *context,
+ const double time_period)
+{
+ AVFrame *in_frame = av_frame_alloc();
+ AVPacket *packet = av_packet_alloc();
+
+ const double start = PIL_check_seconds_timer();
+ int frames_decoded = 0;
+
+ while (av_read_frame(context->iFormatCtx, packet) >= 0) {
+ if (packet->stream_index != context->videoStream) {
+ continue;
+ }
+
+ int ret = avcodec_send_packet(context->iCodecCtx, packet);
+ while (ret >= 0) {
+ ret = avcodec_receive_frame(context->iCodecCtx, in_frame);
+
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+ break;
+ }
+
+ if (ret < 0) {
+ fprintf(stderr, "Error decoding proxy frame: %s\n", av_err2str(ret));
+ break;
+ }
+ frames_decoded++;
+ }
+
+ const double end = PIL_check_seconds_timer();
+
+ if (end > start + time_period) {
+ break;
+ }
+ }
+
+ avcodec_flush_buffers(context->iCodecCtx);
+ av_seek_frame(context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
+ return frames_decoded;
+}
+
+/* Read up to 10k movie packets and return max GOP size detected.
+ * Number of packets is arbitrary. It should be as large as possible, but processed within
+ * reasonable time period, so detected GOP size is as close to real as possible. */
+static int indexer_performance_get_max_gop_size(FFmpegIndexBuilderContext *context)
+{
+ AVPacket *packet = av_packet_alloc();
+
+ const int packets_max = 10000;
+ int packet_index = 0;
+ int max_gop = 0;
+ int cur_gop = 0;
+
+ while (av_read_frame(context->iFormatCtx, packet) >= 0) {
+ if (packet->stream_index != context->videoStream) {
+ continue;
+ }
+ packet_index++;
+ cur_gop++;
+
+ if (packet->flags & AV_PKT_FLAG_KEY) {
+ max_gop = max_ii(max_gop, cur_gop);
+ cur_gop = 0;
+ }
+
+ if (packet_index > packets_max) {
+ break;
+ }
+ }
+
+ av_seek_frame(context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
+ return max_gop;
+}
+
+/* Assess scrubbing performance of provided file. This function is not meant to be very exact.
+ * It compares number number of frames decoded in reasonable time with largest detected GOP size.
+ * Because seeking happens in single GOP, it means, that maximum seek time can be detected this
+ * way.
+ * Since proxies use GOP size of 10 frames, skip building if detected GOP size is less or
+ * equal.
+ */
+static bool indexer_need_to_build_proxy(FFmpegIndexBuilderContext *context)
+{
+ if (!context->build_only_on_bad_performance) {
+ return true;
+ }
+
+ /* Make sure, that file is not cold read. */
+ indexer_performance_get_decode_rate(context, 0.1);
+ /* Get decode rate per 100ms. This is arbitrary, but seems to be good baseline cadence of
+ * seeking. */
+ const int decode_rate = indexer_performance_get_decode_rate(context, 0.1);
+ const int max_gop_size = indexer_performance_get_max_gop_size(context);
+
+ if (max_gop_size <= 10 || max_gop_size < decode_rate) {
+ printf("Skipping proxy building for %s: Decoding performance is already good.\n",
+ context->iFormatCtx->url);
+ context->building_cancelled = true;
+ return false;
+ }
+
+ return true;
+}
+
#endif
/* ----------------------------------------------------------------------
@@ -1275,7 +1388,8 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size proxy_sizes_in_use,
int quality,
const bool overwrite,
- GSet *file_list)
+ GSet *file_list,
+ bool build_only_on_bad_performance)
{
IndexBuildContext *context = NULL;
IMB_Proxy_Size proxy_sizes_to_build = proxy_sizes_in_use;
@@ -1329,9 +1443,13 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
switch (anim->curtype) {
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
- context = index_ffmpeg_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
+ context = index_ffmpeg_create_context(
+ anim, tcs_in_use, proxy_sizes_to_build, quality, build_only_on_bad_performance);
break;
+#else
+ UNUSED_VARS(build_only_on_bad_performance);
#endif
+
#ifdef WITH_AVI
default:
context = index_fallback_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
@@ -1359,7 +1477,9 @@ void IMB_anim_index_rebuild(struct IndexBuildContext *context,
switch (context->anim_type) {
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
- index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
+ if (indexer_need_to_build_proxy((FFmpegIndexBuilderContext *)context)) {
+ index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
+ }
break;
#endif
#ifdef WITH_AVI
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index dc714e6e85a..1c8548009e8 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -536,7 +536,7 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
}
}
else if (image.zsize == 2) {
- /* grayscale with alpha */
+ /* Gray-scale with alpha. */
rect = (uchar *)ibuf->rect;
for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
rect[0] = rect[2];
@@ -564,7 +564,7 @@ struct ImBuf *imb_loadiris(const uchar *mem, size_t size, int flags, char colors
}
}
else if (image.zsize == 2) {
- /* grayscale with alpha */
+ /* Gray-scale with alpha. */
fbase = ibuf->rect_float;
for (size_t x = (size_t)ibuf->x * (size_t)ibuf->y; x > 0; x--) {
fbase[0] = fbase[2];
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 83e93f16f1b..3af7367ef6e 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -424,13 +424,13 @@ static ImBuf *imb_load_jp2_stream(opj_stream_t *stream,
h = image->comps[0].h;
switch (image->numcomps) {
- case 1: /* Grayscale */
- case 3: /* Color */
+ case 1: /* Gray-scale. */
+ case 3: /* Color. */
planes = 24;
use_alpha = false;
break;
- default: /* 2 or 4 - Grayscale or Color + alpha */
- planes = 32; /* grayscale + alpha */
+ default: /* 2 or 4 - Gray-scale or Color + alpha. */
+ planes = 32; /* Gray-scale + alpha. */
use_alpha = true;
break;
}
@@ -529,7 +529,7 @@ static ImBuf *imb_load_jp2_stream(opj_stream_t *stream,
r = image->comps[0].data;
a = (use_alpha) ? image->comps[1].data : NULL;
- /* grayscale */
+ /* Gray-scale. */
if (use_alpha) {
a = image->comps[3].data;
PIXEL_LOOPER_BEGIN (rect_uchar) {
@@ -891,8 +891,8 @@ static opj_image_t *ibuftoimage(ImBuf *ibuf, opj_cparameters_t *parameters)
prec = 8;
}
- /* 32bit images == alpha channel */
- /* grayscale not supported yet */
+ /* 32bit images == alpha channel. */
+ /* Gray-scale not supported yet. */
numcomps = (ibuf->planes == 32) ? 4 : 3;
}
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.h b/source/blender/imbuf/intern/oiio/openimageio_api.h
index 659050cdb00..1201bd1b5e0 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.h
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.h
@@ -31,7 +31,7 @@ extern "C" {
struct ImBuf;
-bool imb_is_a_photoshop(const unsigned char *mem, const size_t size);
+bool imb_is_a_photoshop(const unsigned char *mem, size_t size);
int imb_save_photoshop(struct ImBuf *ibuf, const char *name, int flags);
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index e1b9853ac21..ec8cf36dd49 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -683,7 +683,7 @@ static bool imb_exr_multilayer_parse_channels_from_file(ExrHandle *data);
void *IMB_exr_get_handle(void)
{
- ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
+ ExrHandle *data = MEM_cnew<ExrHandle>("exr handle");
data->multiView = new StringVector();
BLI_addtail(&exrhandles, data);
@@ -789,7 +789,7 @@ void IMB_exr_add_channel(void *handle,
ExrHandle *data = (ExrHandle *)handle;
ExrChannel *echan;
- echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel");
+ echan = MEM_cnew<ExrChannel>("exr channel");
echan->m = new MultiViewChannelName();
if (layname && layname[0] != '\0') {
@@ -1496,7 +1496,7 @@ static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
ExrLayer *lay = (ExrLayer *)BLI_findstring(lb, layname, offsetof(ExrLayer, name));
if (lay == nullptr) {
- lay = (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
+ lay = MEM_cnew<ExrLayer>("exr layer");
BLI_addtail(lb, lay);
BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
}
@@ -1509,7 +1509,7 @@ static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
ExrPass *pass = (ExrPass *)BLI_findstring(lb, passname, offsetof(ExrPass, name));
if (pass == nullptr) {
- pass = (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
+ pass = MEM_cnew<ExrPass>("exr pass");
if (STREQ(passname, "Combined")) {
BLI_addhead(lb, pass);
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h
index 14336620926..4321c95db30 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.h
+++ b/source/blender/imbuf/intern/openexr/openexr_api.h
@@ -36,7 +36,7 @@ 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_is_a_openexr(const unsigned char *mem, 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 6694c32820b..0c3c4a4400f 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -60,7 +60,7 @@ void IMB_exr_add_channel(void *handle,
* Read from file.
*/
bool IMB_exr_begin_read(
- void *handle, const char *filename, int *width, int *height, const bool parse_channels);
+ void *handle, const char *filename, int *width, int *height, bool parse_channels);
/**
* Used for output files (from #RenderResult) (single and multi-layer, single and multi-view).
*/
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c
index 7f4e4dd31df..925ef0a8502 100644
--- a/source/blender/imbuf/intern/radiance_hdr.c
+++ b/source/blender/imbuf/intern/radiance_hdr.c
@@ -77,7 +77,7 @@ static const unsigned char *oldreadcolrs(RGBE *scan,
scan[0][BLU] = *mem++;
scan[0][EXP] = *mem++;
if (scan[0][RED] == 1 && scan[0][GRN] == 1 && scan[0][BLU] == 1) {
- for (i = scan[0][EXP] << rshift; i > 0; i--) {
+ for (i = scan[0][EXP] << rshift; i > 0 && len > 0; i--) {
COPY_RGBE(scan[-1], scan[0]);
scan++;
len--;
@@ -227,7 +227,7 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem,
int found = 0;
int width = 0, height = 0;
const unsigned char *ptr, *mem_eof = mem + size;
- char oriY[80], oriX[80];
+ char oriY[3], oriX[3];
if (!imb_is_a_hdr(mem, size)) {
return NULL;
@@ -244,22 +244,33 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem,
}
}
- if ((found && (x < (size + 2))) == 0) {
+ if ((found && (x < (size - 1))) == 0) {
/* Data not found! */
return NULL;
}
- if (sscanf((const char *)&mem[x + 1],
- "%79s %d %79s %d",
- (char *)&oriY,
- &height,
- (char *)&oriX,
- &width) != 4) {
+ x++;
+
+ /* sscanf requires a null-terminated buffer argument */
+ char buf[32] = {0};
+ memcpy(buf, &mem[x], MIN2(sizeof(buf) - 1, size - x));
+
+ if (sscanf(buf, "%2s %d %2s %d", (char *)&oriY, &height, (char *)&oriX, &width) != 4) {
+ return NULL;
+ }
+
+ if (width < 1 || height < 1) {
return NULL;
}
+ /* Checking that width x height does not extend past mem_eof is not easily possible
+ * since the format uses RLE compression. Can cause excessive memory allocation to occur. */
+
/* find end of this line, data right behind it */
- ptr = (const unsigned char *)strchr((const char *)&mem[x + 1], '\n');
+ ptr = (const unsigned char *)strchr((const char *)&mem[x], '\n');
+ if (ptr == NULL || ptr >= mem_eof) {
+ return NULL;
+ }
ptr++;
if (flags & IB_test) {
diff --git a/source/blender/imbuf/intern/rotate.c b/source/blender/imbuf/intern/rotate.c
index 83dc29aa107..f02f3e37d6a 100644
--- a/source/blender/imbuf/intern/rotate.c
+++ b/source/blender/imbuf/intern/rotate.c
@@ -32,7 +32,7 @@
void IMB_flipy(struct ImBuf *ibuf)
{
- int x, y;
+ size_t x_size, y_size;
if (ibuf == NULL) {
return;
@@ -41,21 +41,23 @@ void IMB_flipy(struct ImBuf *ibuf)
if (ibuf->rect) {
unsigned int *top, *bottom, *line;
- x = ibuf->x;
- y = ibuf->y;
+ x_size = ibuf->x;
+ y_size = ibuf->y;
+
+ const size_t stride = x_size * sizeof(int);
top = ibuf->rect;
- bottom = top + ((y - 1) * x);
- line = MEM_mallocN(x * sizeof(int), "linebuf");
+ bottom = top + ((y_size - 1) * x_size);
+ line = MEM_mallocN(stride, "linebuf");
- y >>= 1;
+ y_size >>= 1;
- for (; y > 0; y--) {
- memcpy(line, top, x * sizeof(int));
- memcpy(top, bottom, x * sizeof(int));
- memcpy(bottom, line, x * sizeof(int));
- bottom -= x;
- top += x;
+ for (; y_size > 0; y_size--) {
+ memcpy(line, top, stride);
+ memcpy(top, bottom, stride);
+ memcpy(bottom, line, stride);
+ bottom -= x_size;
+ top += x_size;
}
MEM_freeN(line);
@@ -64,21 +66,23 @@ void IMB_flipy(struct ImBuf *ibuf)
if (ibuf->rect_float) {
float *topf = NULL, *bottomf = NULL, *linef = NULL;
- x = ibuf->x;
- y = ibuf->y;
+ x_size = ibuf->x;
+ y_size = ibuf->y;
+
+ const size_t stride = x_size * 4 * sizeof(float);
topf = ibuf->rect_float;
- bottomf = topf + 4 * ((y - 1) * x);
- linef = MEM_mallocN(4 * x * sizeof(float), "linebuf");
+ bottomf = topf + 4 * ((y_size - 1) * x_size);
+ linef = MEM_mallocN(stride, "linebuf");
- y >>= 1;
+ y_size >>= 1;
- for (; y > 0; y--) {
- memcpy(linef, topf, 4 * x * sizeof(float));
- memcpy(topf, bottomf, 4 * x * sizeof(float));
- memcpy(bottomf, linef, 4 * x * sizeof(float));
- bottomf -= 4 * x;
- topf += 4 * x;
+ for (; y_size > 0; y_size--) {
+ memcpy(linef, topf, stride);
+ memcpy(topf, bottomf, stride);
+ memcpy(bottomf, linef, stride);
+ bottomf -= 4 * x_size;
+ topf += 4 * x_size;
}
MEM_freeN(linef);
@@ -99,20 +103,22 @@ void IMB_flipx(struct ImBuf *ibuf)
if (ibuf->rect) {
for (yi = y - 1; yi >= 0; yi--) {
+ const size_t x_offset = (size_t)x * yi;
for (xr = x - 1, xl = 0; xr >= xl; xr--, xl++) {
- SWAP(unsigned int, ibuf->rect[(x * yi) + xr], ibuf->rect[(x * yi) + xl]);
+ SWAP(unsigned int, ibuf->rect[x_offset + xr], ibuf->rect[x_offset + xl]);
}
}
}
if (ibuf->rect_float) {
for (yi = y - 1; yi >= 0; yi--) {
+ const size_t x_offset = (size_t)x * yi;
for (xr = x - 1, xl = 0; xr >= xl; xr--, xl++) {
- memcpy(&px_f, &ibuf->rect_float[((x * yi) + xr) * 4], sizeof(float[4]));
- memcpy(&ibuf->rect_float[((x * yi) + xr) * 4],
- &ibuf->rect_float[((x * yi) + xl) * 4],
+ memcpy(&px_f, &ibuf->rect_float[(x_offset + xr) * 4], sizeof(float[4]));
+ memcpy(&ibuf->rect_float[(x_offset + xr) * 4],
+ &ibuf->rect_float[(x_offset + xl) * 4],
sizeof(float[4]));
- memcpy(&ibuf->rect_float[((x * yi) + xl) * 4], &px_f, sizeof(float[4]));
+ memcpy(&ibuf->rect_float[(x_offset + xl) * 4], &px_f, sizeof(float[4]));
}
}
}
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 6ad373845fc..1d3589f00a6 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -29,7 +29,7 @@
* high-level routine that loads all images as 32-bit RGBA, handling all the
* required conversions between many different TIFF types internally.
*
- * Saving supports RGB, RGBA and BW (grayscale) images correctly, with
+ * Saving supports RGB, RGBA and BW (gray-scale) images correctly, with
* 8 bits per channel in all cases. The "deflate" compression algorithm is
* used to compress images.
*/
@@ -488,7 +488,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
if (chan == 3 && spp == 3) { /* fill alpha if only RGB TIFF */
copy_vn_fl(fbuf, ibuf->x, 1.0f);
}
- else if (chan >= spp) { /* for grayscale, duplicate first channel into G and B */
+ else if (chan >= spp) { /* For gray-scale, duplicate first channel into G and B. */
success |= TIFFReadScanline(image, fbuf, row, 0);
}
else {
@@ -500,7 +500,7 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
if (chan == 3 && spp == 3) { /* fill alpha if only RGB TIFF */
copy_vn_ushort(sbuf, ibuf->x, 65535);
}
- else if (chan >= spp) { /* for grayscale, duplicate first channel into G and B */
+ else if (chan >= spp) { /* For gray-scale, duplicate first channel into G and B. */
success |= TIFFReadScanline(image, fbuf, row, 0);
}
else {
@@ -848,7 +848,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
}
else if (samplesperpixel == 1) {
- /* grayscale images, 1 channel */
+ /* Gray-scale images, 1 channel */
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index 82c8747d28d..e1c451a8412 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -305,34 +305,32 @@ class Sampler {
void sample(const ImBuf *source, const float u, const float v, SampleType &r_sample)
{
- const float wrapped_u = uv_wrapper.modify_u(source, u);
- const float wrapped_v = uv_wrapper.modify_v(source, v);
-
if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float> &&
NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
bilinear_interpolation_color_fl(source, nullptr, &r_sample[0], wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_NEAREST &&
std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
nearest_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_BILINEAR &&
std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
bilinear_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) {
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);
+ 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,
@@ -343,6 +341,8 @@ class Sampler {
}
}
else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<StorageType, float>) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
sample_nearest_float(source, wrapped_u, wrapped_v, r_sample);
}
else {
diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt
index f11ad7627b9..b97b3ef97de 100644
--- a/source/blender/io/CMakeLists.txt
+++ b/source/blender/io/CMakeLists.txt
@@ -19,6 +19,7 @@
# ***** END GPL LICENSE BLOCK *****
add_subdirectory(common)
+add_subdirectory(wavefront_obj)
if(WITH_ALEMBIC)
add_subdirectory(alembic)
diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h
index 0b5e927f02f..18b0c91b67c 100644
--- a/source/blender/io/alembic/ABC_alembic.h
+++ b/source/blender/io/alembic/ABC_alembic.h
@@ -26,6 +26,7 @@ extern "C" {
#endif
struct CacheArchiveHandle;
+struct CacheFileLayer;
struct CacheReader;
struct ListBase;
struct Main;
@@ -102,6 +103,7 @@ bool ABC_import(struct bContext *C,
struct CacheArchiveHandle *ABC_create_handle(struct Main *bmain,
const char *filename,
+ const struct CacheFileLayer *layers,
struct ListBase *object_paths);
void ABC_free_handle(struct CacheArchiveHandle *handle);
@@ -115,16 +117,16 @@ void ABC_get_transform(struct CacheReader *reader,
struct Mesh *ABC_read_mesh(struct CacheReader *reader,
struct Object *ob,
struct Mesh *existing_mesh,
- const float time,
+ float time,
const char **err_str,
- const int read_flags,
+ int read_flags,
const char *velocity_name,
- const float velocity_scale);
+ float velocity_scale);
bool ABC_mesh_topology_changed(struct CacheReader *reader,
struct Object *ob,
struct Mesh *existing_mesh,
- const float time,
+ float time,
const char **err_str);
void ABC_CacheReader_incref(struct CacheReader *reader);
diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc
index 80f2cadd08c..e8c156a2b8d 100644
--- a/source/blender/io/alembic/exporter/abc_writer_hair.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc
@@ -136,6 +136,7 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context,
MTFace *mtface = mesh->mtface;
MFace *mface = mesh->mface;
MVert *mverts = mesh->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
if ((!mtface || !mface) && !uv_warning_shown_) {
std::fprintf(stderr,
@@ -173,8 +174,17 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context,
psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv);
uv_values.emplace_back(r_uv[0], r_uv[1]);
- psys_interpolate_face(
- mverts, face, tface, nullptr, mapfw, vec, normal, nullptr, nullptr, nullptr);
+ psys_interpolate_face(mverts,
+ vert_normals,
+ face,
+ tface,
+ nullptr,
+ mapfw,
+ vec,
+ normal,
+ nullptr,
+ nullptr,
+ nullptr);
copy_yup_from_zup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
@@ -206,10 +216,7 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context,
if (vtx[o] == num) {
uv_values.emplace_back(tface->uv[o][0], tface->uv[o][1]);
-
- MVert *mv = mverts + vtx[o];
-
- normal_short_to_float_v3(normal, mv->no);
+ copy_v3_v3(normal, vert_normals[vtx[o]]);
copy_yup_from_zup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
found = true;
@@ -250,6 +257,7 @@ void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context,
MTFace *mtface = mesh->mtface;
MVert *mverts = mesh->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
ParticleSystem *psys = context.particle_system;
ParticleSettings *part = psys->part;
@@ -281,8 +289,17 @@ void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context,
psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
uv_values.emplace_back(r_uv[0], r_uv[1]);
- psys_interpolate_face(
- mverts, face, tface, nullptr, mapfw, vec, tmpnor, nullptr, nullptr, nullptr);
+ psys_interpolate_face(mverts,
+ vert_normals,
+ face,
+ tface,
+ nullptr,
+ mapfw,
+ vec,
+ tmpnor,
+ nullptr,
+ nullptr,
+ nullptr);
/* Convert Z-up to Y-up. */
norm_values.emplace_back(tmpnor[0], tmpnor[2], -tmpnor[1]);
diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
index 7275d0addf0..6ab4b06fba6 100644
--- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
@@ -76,10 +76,13 @@ static void get_topology(struct Mesh *mesh,
std::vector<int32_t> &poly_verts,
std::vector<int32_t> &loop_counts,
bool &r_has_flat_shaded_poly);
-static void get_creases(struct Mesh *mesh,
- std::vector<int32_t> &indices,
- std::vector<int32_t> &lengths,
- std::vector<float> &sharpnesses);
+static void get_edge_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<int32_t> &lengths,
+ std::vector<float> &sharpnesses);
+static void get_vert_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<float> &sharpnesses);
static void get_loop_normals(struct Mesh *mesh,
std::vector<Imath::V3f> &normals,
bool has_flat_shaded_poly);
@@ -283,15 +286,16 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *mesh)
{
- std::vector<float> crease_sharpness;
+ std::vector<float> edge_crease_sharpness, vert_crease_sharpness;
std::vector<Imath::V3f> points;
std::vector<int32_t> poly_verts, loop_counts;
- std::vector<int32_t> crease_indices, crease_lengths;
+ std::vector<int32_t> edge_crease_indices, edge_crease_lengths, vert_crease_indices;
bool has_flat_poly = false;
get_vertices(mesh, points);
get_topology(mesh, poly_verts, loop_counts, has_flat_poly);
- get_creases(mesh, crease_indices, crease_lengths, crease_sharpness);
+ get_edge_creases(mesh, edge_crease_indices, edge_crease_lengths, edge_crease_sharpness);
+ get_vert_creases(mesh, vert_crease_indices, vert_crease_sharpness);
if (!frame_has_been_written_ && args_.export_params->face_sets) {
write_face_sets(context.object, mesh, abc_subdiv_schema_);
@@ -322,10 +326,15 @@ void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *me
write_generated_coordinates(abc_poly_mesh_schema_.getArbGeomParams(), m_custom_data_config);
}
- if (!crease_indices.empty()) {
- subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices));
- subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths));
- subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness));
+ if (!edge_crease_indices.empty()) {
+ subdiv_sample.setCreaseIndices(Int32ArraySample(edge_crease_indices));
+ subdiv_sample.setCreaseLengths(Int32ArraySample(edge_crease_lengths));
+ subdiv_sample.setCreaseSharpnesses(FloatArraySample(edge_crease_sharpness));
+ }
+
+ if (!vert_crease_indices.empty()) {
+ subdiv_sample.setCornerIndices(Int32ArraySample(vert_crease_indices));
+ subdiv_sample.setCornerSharpnesses(FloatArraySample(vert_crease_sharpness));
}
update_bounding_box(context.object);
@@ -477,10 +486,10 @@ static void get_topology(struct Mesh *mesh,
}
}
-static void get_creases(struct Mesh *mesh,
- std::vector<int32_t> &indices,
- std::vector<int32_t> &lengths,
- std::vector<float> &sharpnesses)
+static void get_edge_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<int32_t> &lengths,
+ std::vector<float> &sharpnesses)
{
const float factor = 1.0f / 255.0f;
@@ -503,6 +512,29 @@ static void get_creases(struct Mesh *mesh,
lengths.resize(sharpnesses.size(), 2);
}
+static void get_vert_creases(struct Mesh *mesh,
+ std::vector<int32_t> &indices,
+ std::vector<float> &sharpnesses)
+{
+ indices.clear();
+ sharpnesses.clear();
+
+ const float *creases = static_cast<const float *>(CustomData_get_layer(&mesh->vdata, CD_CREASE));
+
+ if (!creases) {
+ return;
+ }
+
+ for (int i = 0, v = mesh->totvert; i < v; i++) {
+ const float sharpness = creases[i];
+
+ if (sharpness != 0.0f) {
+ indices.push_back(i);
+ sharpnesses.push_back(sharpness);
+ }
+ }
+}
+
static void get_loop_normals(struct Mesh *mesh,
std::vector<Imath::V3f> &normals,
bool has_flat_shaded_poly)
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index 830ec731e20..c3ff64fd0ad 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -541,10 +541,16 @@ 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();
+ Alembic::AbcGeom::V3fArraySamplePtr abc_orco = sample.getVals();
+ const size_t totvert = abc_orco.get()->size();
Mesh *mesh = config.mesh;
+ if (totvert != mesh->totvert) {
+ /* Either the data is somehow corrupted, or we have a dynamic simulation where only the ORCOs
+ * for the first frame were exported. */
+ return;
+ }
+
void *cd_data;
if (CustomData_has_layer(&mesh->vdata, CD_ORCO)) {
cd_data = CustomData_get_layer(&mesh->vdata, CD_ORCO);
@@ -555,7 +561,7 @@ void read_generated_coordinates(const ICompoundProperty &prop,
float(*orcodata)[3] = static_cast<float(*)[3]>(cd_data);
for (int vertex_idx = 0; vertex_idx < totvert; ++vertex_idx) {
- const Imath::V3f &abc_coords = (*abc_ocro)[vertex_idx];
+ const Imath::V3f &abc_coords = (*abc_orco)[vertex_idx];
copy_zup_from_yup(orcodata[vertex_idx], abc_coords.getValue());
}
@@ -614,7 +620,7 @@ AbcUvScope get_uv_scope(const Alembic::AbcGeom::GeometryScope scope,
/* kVaryingScope is sometimes used for vertex scopes as the values vary across the vertices. To
* be sure, one has to check the size of the data against the number of vertices, as it could
* also be a varying attribute across the faces (i.e. one value per face). */
- if ((scope == kVaryingScope || scope == kVertexScope) && indices->size() == config.totvert) {
+ if ((ELEM(scope, kVaryingScope, kVertexScope)) && indices->size() == config.totvert) {
return ABC_UV_SCOPE_VERTEX;
}
diff --git a/source/blender/io/alembic/intern/abc_reader_archive.cc b/source/blender/io/alembic/intern/abc_reader_archive.cc
index 4951dc0e035..94def041285 100644
--- a/source/blender/io/alembic/intern/abc_reader_archive.cc
+++ b/source/blender/io/alembic/intern/abc_reader_archive.cc
@@ -23,6 +23,8 @@
#include "abc_reader_archive.h"
+#include "Alembic/AbcCoreLayer/Read.h"
+
#include "BKE_main.h"
#include "BLI_path_util.h"
@@ -76,6 +78,46 @@ static IArchive open_archive(const std::string &filename,
return IArchive();
}
+ArchiveReader *ArchiveReader::get(struct Main *bmain, const std::vector<const char *> &filenames)
+{
+ std::vector<ArchiveReader *> readers;
+
+ for (const char *filename : filenames) {
+ auto reader = new ArchiveReader(bmain, filename);
+
+ if (!reader->valid()) {
+ delete reader;
+ continue;
+ }
+
+ readers.push_back(reader);
+ }
+
+ if (readers.size() == 0) {
+ return nullptr;
+ }
+
+ if (readers.size() == 1) {
+ return readers[0];
+ }
+
+ return new ArchiveReader(readers);
+}
+
+ArchiveReader::ArchiveReader(const std::vector<ArchiveReader *> &readers) : m_readers(readers)
+{
+ Alembic::AbcCoreLayer::ArchiveReaderPtrs archives;
+
+ for (auto &reader : readers) {
+ archives.push_back(reader->m_archive.getPtr());
+ }
+
+ Alembic::AbcCoreLayer::ReadArchive layer;
+ Alembic::AbcCoreAbstract::ArchiveReaderPtr arPtr = layer(archives);
+
+ m_archive = IArchive(arPtr, kWrapExisting, ErrorHandler::kThrowPolicy);
+}
+
ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename)
{
char abs_filename[FILE_MAX];
@@ -96,6 +138,13 @@ ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename)
m_archive = open_archive(abs_filename, m_streams);
}
+ArchiveReader::~ArchiveReader()
+{
+ for (ArchiveReader *reader : m_readers) {
+ delete reader;
+ }
+}
+
bool ArchiveReader::valid() const
{
return m_archive.valid();
diff --git a/source/blender/io/alembic/intern/abc_reader_archive.h b/source/blender/io/alembic/intern/abc_reader_archive.h
index 67000194aa1..937e3a190cf 100644
--- a/source/blender/io/alembic/intern/abc_reader_archive.h
+++ b/source/blender/io/alembic/intern/abc_reader_archive.h
@@ -41,9 +41,17 @@ class ArchiveReader {
std::ifstream m_infile;
std::vector<std::istream *> m_streams;
- public:
+ std::vector<ArchiveReader *> m_readers;
+
+ ArchiveReader(const std::vector<ArchiveReader *> &readers);
+
ArchiveReader(struct Main *bmain, const char *filename);
+ public:
+ static ArchiveReader *get(struct Main *bmain, const std::vector<const char *> &filenames);
+
+ ~ArchiveReader();
+
bool valid() const;
Alembic::Abc::IObject getTop();
diff --git a/source/blender/io/alembic/intern/abc_reader_curves.h b/source/blender/io/alembic/intern/abc_reader_curves.h
index 6bc0691a870..e7e6fa9f0b2 100644
--- a/source/blender/io/alembic/intern/abc_reader_curves.h
+++ b/source/blender/io/alembic/intern/abc_reader_curves.h
@@ -45,16 +45,16 @@ class AbcCurveReader final : public AbcObjectReader {
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
+ * 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,
+ int read_flag,
const char *velocity_name,
- const float velocity_scale,
+ float velocity_scale,
const char **err_str) override;
void read_curve_sample(Curve *cu,
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index adf1a3e241c..43581ad48d9 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -34,6 +34,7 @@
#include "DNA_object_types.h"
#include "BLI_compiler_compat.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_geom.h"
@@ -44,6 +45,7 @@
#include "BKE_modifier.h"
#include "BKE_object.h"
+using Alembic::Abc::FloatArraySamplePtr;
using Alembic::Abc::Int32ArraySamplePtr;
using Alembic::Abc::IV3fArrayProperty;
using Alembic::Abc::P3fArraySamplePtr;
@@ -160,27 +162,26 @@ static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
return;
}
- read_mverts(mverts, positions, nullptr);
+ read_mverts(*config.mesh, positions, nullptr);
}
-void read_mverts(MVert *mverts, const P3fArraySamplePtr positions, const N3fArraySamplePtr normals)
+void read_mverts(Mesh &mesh, const P3fArraySamplePtr positions, const N3fArraySamplePtr normals)
{
for (int i = 0; i < positions->size(); i++) {
- MVert &mvert = mverts[i];
+ MVert &mvert = mesh.mvert[i];
Imath::V3f pos_in = (*positions)[i];
copy_zup_from_yup(mvert.co, pos_in.getValue());
mvert.bweight = 0;
-
- if (normals) {
+ }
+ if (normals) {
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(&mesh);
+ for (const int i : IndexRange(normals->size())) {
Imath::V3f nor_in = (*normals)[i];
-
- short no[3];
- normal_float_to_short_v3(no, nor_in.getValue());
-
- copy_zup_from_yup(mvert.no, no);
+ copy_zup_from_yup(vert_normals[i], nor_in.getValue());
}
+ BKE_mesh_vertex_normals_clear_dirty(&mesh);
}
}
@@ -463,13 +464,17 @@ static void read_velocity(const V3fArraySamplePtr &velocities,
const CDStreamConfig &config,
const float velocity_scale)
{
+ const int num_velocity_vectors = static_cast<int>(velocities->size());
+ if (num_velocity_vectors != config.mesh->totvert) {
+ /* Files containing videogrammetry data may be malformed and export velocity data on missing
+ * frames (most likely by copying the last valid data). */
+ return;
+ }
+
CustomDataLayer *velocity_layer = BKE_id_attribute_new(
&config.mesh->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT, nullptr);
float(*velocity)[3] = (float(*)[3])velocity_layer->data;
- const int num_velocity_vectors = static_cast<int>(velocities->size());
- BLI_assert(num_velocity_vectors == config.mesh->totvert);
-
for (int i = 0; i < num_velocity_vectors; i++) {
const Imath::V3f &vel_in = (*velocities)[i];
copy_zup_from_yup(velocity[i], vel_in.getValue());
@@ -906,6 +911,66 @@ static void read_subd_sample(const std::string &iobject_full_name,
}
}
+static void read_vertex_creases(Mesh *mesh,
+ const Int32ArraySamplePtr &indices,
+ const FloatArraySamplePtr &sharpnesses)
+{
+ if (!(indices && sharpnesses && indices->size() == sharpnesses->size() &&
+ indices->size() != 0)) {
+ return;
+ }
+
+ float *vertex_crease_data = (float *)CustomData_add_layer(
+ &mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert);
+ const int totvert = mesh->totvert;
+
+ for (int i = 0, v = indices->size(); i < v; ++i) {
+ const int idx = (*indices)[i];
+
+ if (idx >= totvert) {
+ continue;
+ }
+
+ vertex_crease_data[idx] = (*sharpnesses)[i];
+ }
+
+ mesh->cd_flag |= ME_CDFLAG_VERT_CREASE;
+}
+
+static void read_edge_creases(Mesh *mesh,
+ const Int32ArraySamplePtr &indices,
+ const FloatArraySamplePtr &sharpnesses)
+{
+ if (!(indices && sharpnesses)) {
+ return;
+ }
+
+ MEdge *edges = mesh->medge;
+ int totedge = mesh->totedge;
+
+ for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) {
+ int v1 = (*indices)[i];
+ int v2 = (*indices)[i + 1];
+
+ if (v2 < v1) {
+ /* It appears to be common to store edges with the smallest index first, in which case this
+ * prevents us from doing the second search below. */
+ std::swap(v1, v2);
+ }
+
+ MEdge *edge = find_edge(edges, totedge, v1, v2);
+ if (edge == nullptr) {
+ edge = find_edge(edges, totedge, v2, v1);
+ }
+
+ if (edge) {
+ edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]);
+ }
+ }
+
+ mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+}
+
/* ************************************************************************** */
AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
@@ -969,35 +1034,9 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
return;
}
- Int32ArraySamplePtr indices = sample.getCreaseIndices();
- Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
-
- if (indices && sharpnesses) {
- MEdge *edges = mesh->medge;
- int totedge = mesh->totedge;
-
- for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) {
- int v1 = (*indices)[i];
- int v2 = (*indices)[i + 1];
-
- if (v2 < v1) {
- /* It appears to be common to store edges with the smallest index first, in which case this
- * prevents us from doing the second search below. */
- std::swap(v1, v2);
- }
-
- MEdge *edge = find_edge(edges, totedge, v1, v2);
- if (edge == nullptr) {
- edge = find_edge(edges, totedge, v2, v1);
- }
-
- if (edge) {
- edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]);
- }
- }
+ read_edge_creases(mesh, sample.getCreaseIndices(), sample.getCreaseSharpnesses());
- mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- }
+ read_vertex_creases(mesh, sample.getCornerIndices(), sample.getCornerSharpnesses());
if (m_settings->validate_meshes) {
BKE_mesh_validate(mesh, false, false);
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.h b/source/blender/io/alembic/intern/abc_reader_mesh.h
index 2e34ca8ded0..1123616943e 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.h
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.h
@@ -42,9 +42,9 @@ class AbcMeshReader final : public AbcObjectReader {
struct Mesh *read_mesh(struct Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
- const int read_flag,
+ int read_flag,
const char *velocity_name,
- const float velocity_scale,
+ float velocity_scale,
const char **err_str) override;
bool topology_changed(Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel) override;
@@ -75,13 +75,13 @@ class AbcSubDReader final : public AbcObjectReader {
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override;
struct Mesh *read_mesh(struct Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
- const int read_flag,
+ int read_flag,
const char *velocity_name,
- const float velocity_scale,
+ float velocity_scale,
const char **err_str) override;
};
-void read_mverts(MVert *mverts,
+void read_mverts(Mesh &mesh,
const Alembic::AbcGeom::P3fArraySamplePtr positions,
const Alembic::AbcGeom::N3fArraySamplePtr normals);
diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc
index 4a359c49d26..86fa580bf1f 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.cc
+++ b/source/blender/io/alembic/intern/abc_reader_object.cc
@@ -120,29 +120,10 @@ static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1,
* the matrices manually.
*/
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- mat0[i][j] = static_cast<float>(m0[i][j]);
- }
- }
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- mat1[i][j] = static_cast<float>(m1[i][j]);
- }
- }
-
+ convert_matrix_datatype(m0, mat0);
+ convert_matrix_datatype(m1, mat1);
interp_m4_m4m4(ret, mat0, mat1, weight);
-
- Imath::M44d m;
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- m[i][j] = ret[i][j];
- }
- }
-
- return m;
+ return convert_matrix_datatype(ret);
}
Imath::M44d get_matrix(const IXformSchema &schema, const float time)
diff --git a/source/blender/io/alembic/intern/abc_reader_object.h b/source/blender/io/alembic/intern/abc_reader_object.h
index f1c07da0764..5b327a9ddd9 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.h
+++ b/source/blender/io/alembic/intern/abc_reader_object.h
@@ -149,15 +149,15 @@ class AbcObjectReader {
virtual struct Mesh *read_mesh(struct Mesh *mesh,
const Alembic::Abc::ISampleSelector &sample_sel,
- const int read_flag,
+ int read_flag,
const char *velocity_name,
- const float velocity_scale,
+ float velocity_scale,
const char **err_str);
virtual bool topology_changed(Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel);
/** Reads the object matrix and sets up an object transform if animated. */
- void setupObjectTransform(const float time);
+ void setupObjectTransform(float time);
void addCacheModifier();
@@ -168,13 +168,13 @@ class AbcObjectReader {
void incref();
void decref();
- void read_matrix(float r_mat[4][4], const float time, const float scale, bool &is_constant);
+ void read_matrix(float r_mat[4][4], float time, float scale, bool &is_constant);
protected:
/** Determine whether we can inherit our parent's XForm. */
void determine_inherits_xform();
};
-Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time);
+Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, float time);
} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/intern/abc_reader_points.cc b/source/blender/io/alembic/intern/abc_reader_points.cc
index 75ed18f57f2..0135e150097 100644
--- a/source/blender/io/alembic/intern/abc_reader_points.cc
+++ b/source/blender/io/alembic/intern/abc_reader_points.cc
@@ -121,7 +121,7 @@ void read_points_sample(const IPointsSchema &schema,
}
}
- read_mverts(config.mvert, positions, vnormals);
+ read_mverts(*config.mesh, positions, vnormals);
}
struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh,
diff --git a/source/blender/io/alembic/intern/abc_reader_points.h b/source/blender/io/alembic/intern/abc_reader_points.h
index 105d1276f7a..2f91e07d26a 100644
--- a/source/blender/io/alembic/intern/abc_reader_points.h
+++ b/source/blender/io/alembic/intern/abc_reader_points.h
@@ -45,7 +45,7 @@ class AbcPointsReader final : public AbcObjectReader {
const Alembic::Abc::ISampleSelector &sample_sel,
int read_flag,
const char *velocity_name,
- const float velocity_scale,
+ float velocity_scale,
const char **err_str) override;
};
diff --git a/source/blender/io/alembic/intern/abc_util.h b/source/blender/io/alembic/intern/abc_util.h
index 3a0b2852eea..672494e80db 100644
--- a/source/blender/io/alembic/intern/abc_util.h
+++ b/source/blender/io/alembic/intern/abc_util.h
@@ -51,7 +51,7 @@ Imath::M44d convert_matrix_datatype(float mat[4][4]);
/* Convert from Alembic to float matrix representations. Does NOT convert from Y-up to Z-up. */
void convert_matrix_datatype(const Imath::M44d &xform, float r_mat[4][4]);
-void split(const std::string &s, const char delim, std::vector<std::string> &tokens);
+void split(const std::string &s, char delim, std::vector<std::string> &tokens);
template<class TContainer> bool begins_with(const TContainer &input, const TContainer &match)
{
diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc
index d7b176eea50..58fc4dd599d 100644
--- a/source/blender/io/alembic/intern/alembic_capi.cc
+++ b/source/blender/io/alembic/intern/alembic_capi.cc
@@ -159,11 +159,25 @@ static bool gather_objects_paths(const IObject &object, ListBase *object_paths)
CacheArchiveHandle *ABC_create_handle(struct Main *bmain,
const char *filename,
+ const CacheFileLayer *layers,
ListBase *object_paths)
{
- ArchiveReader *archive = new ArchiveReader(bmain, filename);
+ std::vector<const char *> filenames;
+ filenames.push_back(filename);
- if (!archive->valid()) {
+ while (layers) {
+ if ((layers->flag & CACHEFILE_LAYER_HIDDEN) == 0) {
+ filenames.push_back(layers->filepath);
+ }
+ layers = layers->next;
+ }
+
+ /* We need to reverse the order as overriding archives should come first. */
+ std::reverse(filenames.begin(), filenames.end());
+
+ ArchiveReader *archive = ArchiveReader::get(bmain, filenames);
+
+ if (!archive || !archive->valid()) {
delete archive;
return nullptr;
}
@@ -447,9 +461,9 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
WM_set_locked_interface(data->wm, true);
- ArchiveReader *archive = new ArchiveReader(data->bmain, data->filename);
+ ArchiveReader *archive = ArchiveReader::get(data->bmain, {data->filename});
- if (!archive->valid()) {
+ if (!archive || !archive->valid()) {
data->error_code = ABC_ARCHIVE_FAIL;
delete archive;
return;
diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp
index 870db4a15d3..49a4b22dbc3 100644
--- a/source/blender/io/collada/AnimationImporter.cpp
+++ b/source/blender/io/collada/AnimationImporter.cpp
@@ -237,7 +237,7 @@ void AnimationImporter::add_fcurves_to_object(Main *bmain,
/* no matching groups, so add one */
if (grp == nullptr) {
/* Add a new group, and make it active */
- grp = (bActionGroup *)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
+ grp = MEM_cnew<bActionGroup>("bActionGroup");
grp->flag = AGRP_SELECTED;
BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
@@ -2177,7 +2177,7 @@ void AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurv
/* no matching groups, so add one */
if (grp == nullptr) {
/* Add a new group, and make it active */
- grp = (bActionGroup *)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
+ grp = MEM_cnew<bActionGroup>("bActionGroup");
grp->flag = AGRP_SELECTED;
BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
diff --git a/source/blender/io/collada/AnimationImporter.h b/source/blender/io/collada/AnimationImporter.h
index a4624a18cd5..909a3017e66 100644
--- a/source/blender/io/collada/AnimationImporter.h
+++ b/source/blender/io/collada/AnimationImporter.h
@@ -211,7 +211,7 @@ class AnimationImporter : private TransformReader, public AnimationImporterBase
*/
void Assign_lens_animations(const COLLADAFW::UniqueId &listid,
ListBase *AnimCurves,
- const double aspect,
+ double aspect,
Camera *cam,
const char *anim_type,
int fov_type);
diff --git a/source/blender/io/collada/ArmatureImporter.h b/source/blender/io/collada/ArmatureImporter.h
index ea78efeb5d7..fc0333b0ab1 100644
--- a/source/blender/io/collada/ArmatureImporter.h
+++ b/source/blender/io/collada/ArmatureImporter.h
@@ -120,7 +120,7 @@ class ArmatureImporter : private TransformReader {
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);
- void connect_bone_chains(bArmature *armature, Bone *bone, const int max_chain_length);
+ void connect_bone_chains(bArmature *armature, Bone *bone, int max_chain_length);
void set_pose(Object *ob_arm,
COLLADAFW::Node *root_node,
diff --git a/source/blender/io/collada/BCAnimationCurve.h b/source/blender/io/collada/BCAnimationCurve.h
index 36b2a5e8509..cf4cb4e0642 100644
--- a/source/blender/io/collada/BCAnimationCurve.h
+++ b/source/blender/io/collada/BCAnimationCurve.h
@@ -59,8 +59,8 @@ class BCCurveKey {
BCCurveKey();
BCCurveKey(const BC_animation_type type,
const std::string path,
- const int array_index,
- const int subindex = -1);
+ int array_index,
+ int subindex = -1);
void operator=(const BCCurveKey &other);
std::string get_full_path() const;
std::string get_path() const;
@@ -127,7 +127,7 @@ class BCAnimationCurve {
FCurve *get_fcurve() const;
int sample_count() const;
- float get_value(const float frame);
+ float get_value(float frame);
void get_values(BCValues &values) const;
void get_value_map(BCValueMap &value_map);
@@ -135,14 +135,14 @@ class BCAnimationCurve {
/* Curve edit functions create a copy of the underlying #FCurve. */
FCurve *get_edit_fcurve();
- bool add_value_from_rna(const int frame);
- bool add_value_from_matrix(const BCSample &sample, const int frame);
- void add_value(const float val, const int frame);
+ bool add_value_from_rna(int frame);
+ bool add_value_from_matrix(const BCSample &sample, int frame);
+ void add_value(float val, int frame);
void clean_handles();
/* experimental stuff */
- int closest_index_above(const float sample_frame, const int start_at) const;
- int closest_index_below(const float sample_frame) const;
+ int closest_index_above(float sample_frame, int start_at) const;
+ int closest_index_below(float sample_frame) const;
};
typedef std::map<BCCurveKey, BCAnimationCurve *> BCAnimationCurveMap;
diff --git a/source/blender/io/collada/BCMath.h b/source/blender/io/collada/BCMath.h
index 503a76541fd..dbcfe96bc61 100644
--- a/source/blender/io/collada/BCMath.h
+++ b/source/blender/io/collada/BCMath.h
@@ -82,25 +82,25 @@ class 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(DMatrix &matrix, bool transposed = false, int precision = -1) const;
void get_matrix(Matrix &matrix,
- const bool transposed = false,
- const int precision = -1,
- const bool inverted = false) const;
+ bool transposed = false,
+ int precision = -1,
+ bool inverted = false) const;
void set_transform(Object *ob);
void set_transform(Matrix &mat);
void add_transform(Matrix &to,
const Matrix &transform,
const Matrix &from,
- const bool inverted = false);
+ bool inverted = false);
void apply_transform(Matrix &to,
const Matrix &transform,
const Matrix &from,
- const bool inverse = false);
+ bool inverse = false);
void add_inverted_transform(Matrix &to, const Matrix &transform, const Matrix &from);
- void add_transform(const Matrix &matrix, const bool inverted = false);
- void add_transform(const BCMatrix &matrix, const bool inverted = false);
- void apply_transform(const BCMatrix &matrix, const bool inverted = false);
+ void add_transform(const Matrix &matrix, bool inverted = false);
+ void add_transform(const BCMatrix &matrix, bool inverted = false);
+ void apply_transform(const BCMatrix &matrix, bool inverted = false);
bool in_range(const BCMatrix &other, float distance) const;
diff --git a/source/blender/io/collada/BCSampleData.h b/source/blender/io/collada/BCSampleData.h
index dccc5228c4f..a76466a42f5 100644
--- a/source/blender/io/collada/BCSampleData.h
+++ b/source/blender/io/collada/BCSampleData.h
@@ -54,7 +54,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;
+ bool get_value(std::string channel_target, 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/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp
index eeee220fd2c..73e3eeda462 100644
--- a/source/blender/io/collada/GeometryExporter.cpp
+++ b/source/blender/io/collada/GeometryExporter.cpp
@@ -631,6 +631,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
int last_normal_index = -1;
MVert *verts = me->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me);
MLoop *mloops = me->mloop;
float(*lnors)[3] = nullptr;
bool use_custom_normals = false;
@@ -666,7 +667,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
normalize_v3_v3(normalized, lnors[loop_idx]);
}
else {
- normal_short_to_float_v3(normalized, verts[mloops[loop_index].v].no);
+ copy_v3_v3(normalized, vert_normals[mloops[loop_index].v]);
normalize_v3(normalized);
}
Normal n = {normalized[0], normalized[1], normalized[2]};
diff --git a/source/blender/io/collada/Materials.cpp b/source/blender/io/collada/Materials.cpp
index 1f358accc4e..6e17172f642 100644
--- a/source/blender/io/collada/Materials.cpp
+++ b/source/blender/io/collada/Materials.cpp
@@ -16,6 +16,8 @@
#include "Materials.h"
+#include "BKE_node_tree_update.h"
+
MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map)
: mContext(C), material(ma), effect(nullptr), key_image_map(&key_image_map)
{
@@ -106,7 +108,7 @@ bNodeTree *MaterialNode::prepare_material_nodetree()
void MaterialNode::update_material_nodetree()
{
- ntreeUpdateTree(CTX_data_main(mContext), ntree);
+ BKE_ntree_update_main_tree(CTX_data_main(mContext), ntree, nullptr);
}
bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label)
diff --git a/source/blender/io/collada/collada_utils.h b/source/blender/io/collada/collada_utils.h
index cf62ea0a275..e06f7b2cb8b 100644
--- a/source/blender/io/collada/collada_utils.h
+++ b/source/blender/io/collada/collada_utils.h
@@ -291,23 +291,23 @@ extern bool bc_has_animations(Object *ob);
extern void bc_add_global_transform(Matrix &to_mat,
const Matrix &from_mat,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
extern void bc_add_global_transform(Vector &to_vec,
const Vector &from_vec,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
extern void bc_add_global_transform(Vector &to_vec,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
extern void bc_add_global_transform(Matrix &to_mat,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
extern void bc_apply_global_transform(Matrix &to_mat,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
extern void bc_apply_global_transform(Vector &to_vec,
const BCMatrix &global_transform,
- const bool invert = false);
+ bool invert = false);
/**
* Check if custom information about bind matrix exists and modify the from_mat
* accordingly.
@@ -382,7 +382,7 @@ class BoneExtended {
void set_name(char *aName);
char *get_name();
- void set_chain_length(const int aLength);
+ void set_chain_length(int aLength);
int get_chain_length();
void set_leaf_bone(bool state);
diff --git a/source/blender/io/common/IO_abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
index 0bebc4384a9..e024b766c99 100644
--- a/source/blender/io/common/IO_abstract_hierarchy_iterator.h
+++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
@@ -111,7 +111,7 @@ struct HierarchyContext {
void mark_as_instance_of(const std::string &reference_export_path);
void mark_as_not_instanced();
- bool is_object_visible(const enum eEvaluationMode evaluation_mode) const;
+ bool is_object_visible(enum eEvaluationMode evaluation_mode) const;
};
/* Abstract writer for objects. Create concrete subclasses to write to USD, Alembic, etc.
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.cc b/source/blender/io/gpencil/intern/gpencil_io_base.cc
index f031648d2ed..7868bade8c1 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.cc
@@ -23,9 +23,8 @@
* \ingroup bgpencil
*/
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_path_util.h"
#include "BLI_span.hh"
@@ -283,7 +282,7 @@ float GpencilIO::stroke_point_radius_get(bGPDlayer *gpl, bGPDstroke *gps)
const float2 screen_ex = gpencil_3D_point_to_2D(&pt->x);
const float2 v1 = screen_co - screen_ex;
- float radius = v1.length();
+ float radius = math::length(v1);
BKE_gpencil_free_stroke(gps_perimeter);
return MAX2(radius, 1.0f);
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.hh b/source/blender/io/gpencil/intern/gpencil_io_base.hh
index 6437796648d..ae54d5056dc 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.hh
@@ -22,9 +22,8 @@
* \ingroup bgpencil
*/
-#include "BLI_float2.hh"
-#include "BLI_float3.hh"
#include "BLI_float4x4.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_vector.hh"
#include "DNA_space_types.h" /* for FILE_MAX */
@@ -49,7 +48,7 @@ class GpencilIO {
public:
GpencilIO(const GpencilIOParams *iparams);
- void frame_number_set(const int value);
+ void frame_number_set(int value);
void prepare_camera_params(Scene *scene, const GpencilIOParams *iparams);
protected:
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
index 7539fba1343..c856e60c4b8 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
@@ -238,7 +238,7 @@ void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
/* Get the thickness in pixels using a simple 1 point stroke. */
bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, false, false);
gps_temp->totpoints = 1;
- gps_temp->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
+ gps_temp->points = MEM_cnew<bGPDspoint>("gp_stroke_points");
const bGPDspoint *pt_src = &gps->points[0];
bGPDspoint *pt_dst = &gps_temp->points[0];
copy_v3_v3(&pt_dst->x, &pt_src->x);
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
index 18de321914c..5de22530fec 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
@@ -61,16 +61,13 @@ class GpencilExporterPDF : public GpencilExporter {
* 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);
+ void export_stroke_to_polyline(
+ bGPDlayer *gpl, bGPDstroke *gps, bool is_stroke, bool do_fill, bool normalize);
/**
* Set color.
* \param do_fill: True if the stroke is only fill.
*/
- void color_set(bGPDlayer *gpl, const bool do_fill);
+ void color_set(bGPDlayer *gpl, bool do_fill);
};
} // namespace blender::io::gpencil
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
index 09eac7a2813..3ca6ed6cd45 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
@@ -308,7 +308,7 @@ void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
/* Get the thickness in pixels using a simple 1 point stroke. */
bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, false, false);
gps_temp->totpoints = 1;
- gps_temp->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
+ gps_temp->points = MEM_cnew<bGPDspoint>("gp_stroke_points");
bGPDspoint *pt_src = &gps->points[0];
bGPDspoint *pt_dst = &gps_temp->points[0];
copy_v3_v3(&pt_dst->x, &pt_src->x);
diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh b/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
index b3175978072..8b88e9dc142 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
@@ -69,12 +69,8 @@ class GpencilExporterSVG : public GpencilExporter {
* \param size: Size of the text
* \param hexcolor: Color of the text
*/
- static void add_text(pugi::xml_node node,
- float x,
- float y,
- std::string text,
- const float size,
- std::string hexcolor);
+ static void add_text(
+ pugi::xml_node node, float x, float y, std::string text, float size, std::string hexcolor);
private:
/** XML doc. */
@@ -96,7 +92,7 @@ class GpencilExporterSVG : public GpencilExporter {
void export_stroke_to_path(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gpl,
- const bool do_fill);
+ bool do_fill);
/**
* Export a stroke using poly-line or polygon
@@ -106,8 +102,8 @@ class GpencilExporterSVG : public GpencilExporter {
void export_stroke_to_polyline(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gpl,
- const bool is_stroke,
- const bool do_fill);
+ bool is_stroke,
+ bool do_fill);
/**
* Set color SVG string for stroke
@@ -117,7 +113,7 @@ class GpencilExporterSVG : public GpencilExporter {
void color_string_set(struct bGPDlayer *gpl,
struct bGPDstroke *gps,
pugi::xml_node node_gps,
- const bool do_fill);
+ 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/gpencil/intern/gpencil_io_import_base.hh b/source/blender/io/gpencil/intern/gpencil_io_import_base.hh
index 7d6fad2340b..31ded8234c8 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_import_base.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_import_base.hh
@@ -33,7 +33,7 @@ class GpencilImporter : public GpencilIO {
protected:
struct Object *create_object();
- int32_t create_material(const char *name, const bool stroke, const bool fill);
+ int32_t create_material(const char *name, bool stroke, bool fill);
private:
};
diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc
index 941d1137f4d..455ebb7c3cb 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc
@@ -21,8 +21,8 @@
* \ingroup bgpencil
*/
-#include "BLI_float3.hh"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "DNA_gpencil_types.h"
diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh b/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh
index 99e8b1ed4fd..24e80563a14 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh
@@ -47,10 +47,10 @@ class GpencilImporterSVG : public GpencilImporter {
struct bGPDframe *gpf,
struct NSVGshape *shape,
struct NSVGpath *path,
- const int32_t mat_index,
+ int32_t mat_index,
const float matrix[4][4]);
- void convert_color(const int32_t color, float r_linear_rgba[4]);
+ void convert_color(int32_t color, float r_linear_rgba[4]);
};
} // namespace blender::io::gpencil
diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc
index db0c5785a68..645dea42971 100644
--- a/source/blender/io/usd/intern/usd_reader_material.cc
+++ b/source/blender/io/usd/intern/usd_reader_material.cc
@@ -23,6 +23,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BLI_math_vector.h"
#include "BLI_string.h"
@@ -339,7 +340,7 @@ void USDMaterialReader::import_usd_preview(Material *mtl,
nodeSetActive(ntree, output);
- ntreeUpdateTree(bmain_, ntree);
+ BKE_ntree_update_main_tree(bmain_, ntree, nullptr);
/* Optionally, set the material blend mode. */
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 3ad1d4adf18..95b73c85da6 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -30,6 +30,8 @@
#include "BLI_math.h"
#include "BLI_math_geom.h"
+#include "BLI_math_vec_types.hh"
+#include "BLI_span.hh"
#include "BLI_string.h"
#include "DNA_customdata_types.h"
@@ -520,6 +522,38 @@ void USDMeshReader::read_colors(Mesh *mesh, const double motionSampleTime)
}
}
+void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTime)
+{
+ pxr::VtIntArray corner_indices;
+ if (!mesh_prim_.GetCornerIndicesAttr().Get(&corner_indices, motionSampleTime)) {
+ return;
+ }
+
+ pxr::VtIntArray corner_sharpnesses;
+ if (!mesh_prim_.GetCornerSharpnessesAttr().Get(&corner_sharpnesses, motionSampleTime)) {
+ return;
+ }
+
+ /* It is fine to have fewer indices than vertices, but never the other way other. */
+ if (corner_indices.size() > mesh->totvert) {
+ std::cerr << "WARNING: too many vertex crease for mesh " << prim_path_ << std::endl;
+ return;
+ }
+
+ if (corner_indices.size() != corner_sharpnesses.size()) {
+ std::cerr << "WARNING: vertex crease indices and sharpnesses count mismatch for mesh "
+ << prim_path_ << std::endl;
+ return;
+ }
+
+ float *creases = static_cast<float *>(
+ CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert));
+
+ for (size_t i = 0; i < corner_indices.size(); i++) {
+ creases[corner_indices[i]] = corner_sharpnesses[i];
+ }
+}
+
void USDMeshReader::process_normals_vertex_varying(Mesh *mesh)
{
if (!mesh) {
@@ -527,34 +561,32 @@ void USDMeshReader::process_normals_vertex_varying(Mesh *mesh)
}
if (normals_.empty()) {
- BKE_mesh_calc_normals(mesh);
return;
}
if (normals_.size() != mesh->totvert) {
std::cerr << "WARNING: vertex varying normals count mismatch for mesh " << prim_path_
<< std::endl;
- BKE_mesh_calc_normals(mesh);
return;
}
- for (int i = 0; i < normals_.size(); i++) {
- MVert &mvert = mesh->mvert[i];
- normal_float_to_short_v3(mvert.no, normals_[i].data());
- }
+ MutableSpan vert_normals{(float3 *)BKE_mesh_vertex_normals_for_write(mesh), mesh->totvert};
+ BLI_STATIC_ASSERT(sizeof(normals_[0]) == sizeof(float3), "Expected float3 normals size");
+ vert_normals.copy_from({(float3 *)normals_.data(), static_cast<int64_t>(normals_.size())});
+ BKE_mesh_vertex_normals_clear_dirty(mesh);
}
void USDMeshReader::process_normals_face_varying(Mesh *mesh)
{
if (normals_.empty()) {
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
/* Check for normals count mismatches to prevent crashes. */
if (normals_.size() != mesh->totloop) {
std::cerr << "WARNING: loop normal count mismatch for mesh " << mesh->id.name << std::endl;
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
@@ -592,14 +624,14 @@ void USDMeshReader::process_normals_face_varying(Mesh *mesh)
void USDMeshReader::process_normals_uniform(Mesh *mesh)
{
if (normals_.empty()) {
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
/* Check for normals count mismatches to prevent crashes. */
if (normals_.size() != mesh->totpoly) {
std::cerr << "WARNING: uniform normal count mismatch for mesh " << mesh->id.name << std::endl;
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
@@ -640,6 +672,8 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings,
mvert.co[1] = positions_[i][1];
mvert.co[2] = positions_[i][2];
}
+
+ read_vertex_creases(mesh, motionSampleTime);
}
if (new_mesh || (settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
@@ -652,14 +686,11 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings,
}
else {
/* Default */
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
}
}
- /* Process point normals after reading polys. This
- * is important in the case where the normals are empty
- * and we invoke BKE_mesh_calc_normals(mesh), which requires
- * edges to be defined. */
+ /* Process point normals after reading polys. */
if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0 &&
normal_interpolation_ == pxr::UsdGeomTokens->vertex) {
process_normals_vertex_varying(mesh);
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h
index 9ed73ba5a28..c5869fcbd32 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.h
+++ b/source/blender/io/usd/intern/usd_reader_mesh.h
@@ -86,6 +86,7 @@ class USDMeshReader : public USDGeomReader {
void read_mpolys(Mesh *mesh);
void read_uvs(Mesh *mesh, double motionSampleTime, bool load_uvs = false);
void read_colors(Mesh *mesh, double motionSampleTime);
+ void read_vertex_creases(Mesh *mesh, double motionSampleTime);
void read_mesh_sample(ImportSettings *settings,
Mesh *mesh,
diff --git a/source/blender/io/usd/intern/usd_reader_xform.h b/source/blender/io/usd/intern/usd_reader_xform.h
index 587ac373a4f..7720a054772 100644
--- a/source/blender/io/usd/intern/usd_reader_xform.h
+++ b/source/blender/io/usd/intern/usd_reader_xform.h
@@ -46,7 +46,7 @@ class USDXformReader : public USDPrimReader {
void create_object(Main *bmain, double motionSampleTime) override;
void read_object_data(Main *bmain, double motionSampleTime) override;
- void read_matrix(float r_mat[4][4], const float time, const float scale, bool *r_is_constant);
+ void read_matrix(float r_mat[4][4], float time, float scale, bool *r_is_constant);
bool use_parent_xform() const
{
diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc
index 61b14155dd0..b061a2ff795 100644
--- a/source/blender/io/usd/intern/usd_writer_mesh.cc
+++ b/source/blender/io/usd/intern/usd_writer_mesh.cc
@@ -110,6 +110,12 @@ struct USDMeshData {
* single sharpness or a value per-edge, USD will encode either a single sharpness per crease on
* a mesh, or sharpness's for all edges making up the creases on a mesh. */
pxr::VtFloatArray crease_sharpnesses;
+
+ /* The lengths of this array specifies the number of sharp corners (or vertex crease) on the
+ * surface. Each value is the index of a vertex in the mesh's vertex list. */
+ pxr::VtIntArray corner_indices;
+ /* The per-vertex sharpnesses. The lengths of this array must match that of `corner_indices`. */
+ pxr::VtFloatArray corner_sharpnesses;
};
void USDGenericMeshWriter::write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh)
@@ -214,6 +220,23 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
attr_crease_sharpness, pxr::VtValue(usd_mesh_data.crease_sharpnesses), timecode);
}
+ if (!usd_mesh_data.corner_indices.empty() &&
+ usd_mesh_data.corner_indices.size() == usd_mesh_data.corner_sharpnesses.size()) {
+ pxr::UsdAttribute attr_corner_indices = usd_mesh.CreateCornerIndicesAttr(pxr::VtValue(), true);
+ pxr::UsdAttribute attr_corner_sharpnesses = usd_mesh.CreateCornerSharpnessesAttr(
+ pxr::VtValue(), true);
+
+ if (!attr_corner_indices.HasValue()) {
+ attr_corner_indices.Set(usd_mesh_data.corner_indices, defaultTime);
+ attr_corner_sharpnesses.Set(usd_mesh_data.corner_sharpnesses, defaultTime);
+ }
+
+ usd_value_writer_.SetAttribute(
+ attr_corner_indices, pxr::VtValue(usd_mesh_data.corner_indices), timecode);
+ usd_value_writer_.SetAttribute(
+ attr_corner_sharpnesses, pxr::VtValue(usd_mesh_data.crease_sharpnesses), timecode);
+ }
+
if (usd_export_context_.export_params.export_uvmaps) {
write_uv_maps(mesh, usd_mesh);
}
@@ -268,7 +291,7 @@ static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data)
}
}
-static void get_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
+static void get_edge_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
{
const float factor = 1.0f / 255.0f;
@@ -293,11 +316,30 @@ static void get_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
}
}
+static void get_vert_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
+{
+ const float *creases = static_cast<const float *>(CustomData_get_layer(&mesh->vdata, CD_CREASE));
+
+ if (!creases) {
+ return;
+ }
+
+ for (int i = 0, v = mesh->totvert; i < v; i++) {
+ const float sharpness = creases[i];
+
+ if (sharpness != 0.0f) {
+ usd_mesh_data.corner_indices.push_back(i);
+ usd_mesh_data.corner_sharpnesses.push_back(sharpness);
+ }
+ }
+}
+
void USDGenericMeshWriter::get_geometry_data(const Mesh *mesh, USDMeshData &usd_mesh_data)
{
get_vertices(mesh, usd_mesh_data);
get_loops_polys(mesh, usd_mesh_data);
- get_creases(mesh, usd_mesh_data);
+ get_edge_creases(mesh, usd_mesh_data);
+ get_vert_creases(mesh, usd_mesh_data);
}
void USDGenericMeshWriter::assign_materials(const HierarchyContext &context,
@@ -378,16 +420,15 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_
}
else {
/* Compute the loop normals based on the 'smooth' flag. */
- float normal[3];
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
MPoly *mpoly = mesh->mpoly;
- const MVert *mvert = mesh->mvert;
for (int poly_idx = 0, totpoly = mesh->totpoly; poly_idx < totpoly; ++poly_idx, ++mpoly) {
MLoop *mloop = mesh->mloop + mpoly->loopstart;
if ((mpoly->flag & ME_SMOOTH) == 0) {
/* Flat shaded, use common normal for all verts. */
- BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, normal);
- pxr::GfVec3f pxr_normal(normal);
+ pxr::GfVec3f pxr_normal(face_normals[poly_idx]);
for (int loop_idx = 0; loop_idx < mpoly->totloop; ++loop_idx) {
loop_normals.push_back(pxr_normal);
}
@@ -395,8 +436,7 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_
else {
/* Smooth shaded, use individual vert normals. */
for (int loop_idx = 0; loop_idx < mpoly->totloop; ++loop_idx, ++mloop) {
- normal_short_to_float_v3(normal, mvert[mloop->v].no);
- loop_normals.push_back(pxr::GfVec3f(normal));
+ loop_normals.push_back(pxr::GfVec3f(vert_normals[mloop->v]));
}
}
}
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index 2a036c3d398..16bd826ecdd 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -106,14 +106,14 @@ void USD_get_transform(struct CacheReader *reader, float r_mat[4][4], float time
struct Mesh *USD_read_mesh(struct CacheReader *reader,
struct Object *ob,
struct Mesh *existing_mesh,
- const float time,
+ float time,
const char **err_str,
int read_flag);
bool USD_mesh_topology_changed(struct CacheReader *reader,
struct Object *ob,
struct Mesh *existing_mesh,
- const float time,
+ float time,
const char **err_str);
struct CacheReader *CacheReader_open_usd_object(struct CacheArchiveHandle *handle,
diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt
new file mode 100644
index 00000000000..296dd70b5a2
--- /dev/null
+++ b/source/blender/io/wavefront_obj/CMakeLists.txt
@@ -0,0 +1,84 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ./exporter
+ ../../blenkernel
+ ../../blenlib
+ ../../bmesh
+ ../../bmesh/intern
+ ../../depsgraph
+ ../../editors/include
+ ../../makesdna
+ ../../makesrna
+ ../../nodes
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ IO_wavefront_obj.cc
+ exporter/obj_export_file_writer.cc
+ exporter/obj_export_mesh.cc
+ exporter/obj_export_mtl.cc
+ exporter/obj_export_nurbs.cc
+ exporter/obj_exporter.cc
+
+ IO_wavefront_obj.h
+ exporter/obj_export_file_writer.hh
+ exporter/obj_export_io.hh
+ exporter/obj_export_mesh.hh
+ exporter/obj_export_mtl.hh
+ exporter/obj_export_nurbs.hh
+ exporter/obj_exporter.hh
+)
+
+set(LIB
+ bf_blenkernel
+)
+
+blender_add_lib(bf_wavefront_obj "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_GTESTS)
+ set(TEST_SRC
+ tests/obj_exporter_tests.cc
+ tests/obj_exporter_tests.hh
+ )
+
+ set(TEST_INC
+ ${INC}
+
+ ../../blenloader
+ ../../../../tests/gtests
+ )
+
+ set(TEST_LIB
+ ${LIB}
+
+ bf_blenloader_tests
+ bf_wavefront_obj
+ )
+
+ include(GTestTesting)
+ blender_add_test_lib(bf_wavefront_obj_tests "${TEST_SRC}" "${TEST_INC}" "${INC_SYS}" "${TEST_LIB}")
+ add_dependencies(bf_wavefront_obj_tests bf_wavefront_obj)
+endif()
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.cc b/source/blender/io/wavefront_obj/IO_wavefront_obj.cc
new file mode 100644
index 00000000000..1c93eafe91a
--- /dev/null
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.cc
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include "BLI_timeit.hh"
+
+#include "IO_wavefront_obj.h"
+
+#include "obj_exporter.hh"
+
+/**
+ * C-interface for the exporter.
+ */
+void OBJ_export(bContext *C, const OBJExportParams *export_params)
+{
+ SCOPED_TIMER("OBJ export");
+ blender::io::obj::exporter_main(C, *export_params);
+}
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
new file mode 100644
index 00000000000..684eb3eda41
--- /dev/null
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -0,0 +1,97 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include "BKE_context.h"
+#include "BLI_path_util.h"
+#include "DEG_depsgraph.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ OBJ_AXIS_X_UP = 0,
+ OBJ_AXIS_Y_UP = 1,
+ OBJ_AXIS_Z_UP = 2,
+ OBJ_AXIS_NEGATIVE_X_UP = 3,
+ OBJ_AXIS_NEGATIVE_Y_UP = 4,
+ OBJ_AXIS_NEGATIVE_Z_UP = 5,
+} eTransformAxisUp;
+
+typedef enum {
+ OBJ_AXIS_X_FORWARD = 0,
+ OBJ_AXIS_Y_FORWARD = 1,
+ OBJ_AXIS_Z_FORWARD = 2,
+ OBJ_AXIS_NEGATIVE_X_FORWARD = 3,
+ OBJ_AXIS_NEGATIVE_Y_FORWARD = 4,
+ OBJ_AXIS_NEGATIVE_Z_FORWARD = 5,
+} eTransformAxisForward;
+
+static const int TOTAL_AXES = 3;
+
+struct OBJExportParams {
+ /** Full path to the destination .OBJ file. */
+ char filepath[FILE_MAX];
+
+ /** Full path to current blender file (used for comments in output). */
+ const char *blen_filepath;
+
+ /** Whether multiple frames should be exported. */
+ bool export_animation;
+ /** The first frame to be exported. */
+ int start_frame;
+ /** The last frame to be exported. */
+ int end_frame;
+
+ /* Geometry Transform options. */
+ eTransformAxisForward forward_axis;
+ eTransformAxisUp up_axis;
+ float scaling_factor;
+
+ /* File Write Options. */
+ bool export_selected_objects;
+ eEvaluationMode export_eval_mode;
+ bool export_uv;
+ bool export_normals;
+ bool export_materials;
+ bool export_triangulated_mesh;
+ bool export_curves_as_nurbs;
+
+ /* Grouping options. */
+ bool export_object_groups;
+ bool export_material_groups;
+ bool export_vertex_groups;
+ /**
+ * Calculate smooth groups from sharp edges.
+ */
+ bool export_smooth_groups;
+ /**
+ * Create bitflags instead of the default "0"/"1" group IDs.
+ */
+ bool smooth_groups_bitflags;
+};
+
+void OBJ_export(bContext *C, const struct OBJExportParams *export_params);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
new file mode 100644
index 00000000000..d31353c4a76
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
@@ -0,0 +1,521 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include <algorithm>
+#include <cstdio>
+
+#include "BKE_blender_version.h"
+
+#include "BLI_path_util.h"
+
+#include "obj_export_mesh.hh"
+#include "obj_export_mtl.hh"
+#include "obj_export_nurbs.hh"
+
+#include "obj_export_file_writer.hh"
+
+namespace blender::io::obj {
+/**
+ * Per reference http://www.martinreddy.net/gfx/3d/OBJ.spec:
+ * To turn off smoothing groups, use a value of 0 or off.
+ * Polygonal elements use group numbers to put elements in different smoothing groups.
+ * For free-form surfaces, smoothing groups are either turned on or off;
+ * there is no difference between values greater than 0.
+ */
+const int SMOOTH_GROUP_DISABLED = 0;
+const int SMOOTH_GROUP_DEFAULT = 1;
+
+const char *DEFORM_GROUP_DISABLED = "off";
+/* There is no deform group default name. Use what the user set in the UI. */
+
+/**
+ * Per reference http://www.martinreddy.net/gfx/3d/OBJ.spec:
+ * Once a material is assigned, it cannot be turned off; it can only be changed.
+ * If a material name is not specified, a white material is used.
+ * So an empty material name is written. */
+const char *MATERIAL_GROUP_DISABLED = "";
+
+void OBJWriter::write_vert_uv_normal_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> normal_indices) const
+{
+ BLI_assert(vert_indices.size() == uv_indices.size() &&
+ vert_indices.size() == normal_indices.size());
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (int j = 0; j < vert_indices.size(); j++) {
+ file_handler_->write<eOBJSyntaxElement::vertex_uv_normal_indices>(
+ vert_indices[j] + index_offsets_.vertex_offset + 1,
+ uv_indices[j] + index_offsets_.uv_vertex_offset + 1,
+ normal_indices[j] + index_offsets_.normal_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+void OBJWriter::write_vert_normal_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> normal_indices) const
+{
+ BLI_assert(vert_indices.size() == normal_indices.size());
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (int j = 0; j < vert_indices.size(); j++) {
+ file_handler_->write<eOBJSyntaxElement::vertex_normal_indices>(
+ vert_indices[j] + index_offsets_.vertex_offset + 1,
+ normal_indices[j] + index_offsets_.normal_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+void OBJWriter::write_vert_uv_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> /*normal_indices*/) const
+{
+ BLI_assert(vert_indices.size() == uv_indices.size());
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (int j = 0; j < vert_indices.size(); j++) {
+ file_handler_->write<eOBJSyntaxElement::vertex_uv_indices>(
+ vert_indices[j] + index_offsets_.vertex_offset + 1,
+ uv_indices[j] + index_offsets_.uv_vertex_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+void OBJWriter::write_vert_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> /*normal_indices*/) const
+{
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (const int vert_index : vert_indices) {
+ file_handler_->write<eOBJSyntaxElement::vertex_indices>(vert_index +
+ index_offsets_.vertex_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+void OBJWriter::write_header() const
+{
+ using namespace std::string_literals;
+ file_handler_->write<eOBJSyntaxElement::string>("# Blender "s + BKE_blender_version_string() +
+ "\n");
+ file_handler_->write<eOBJSyntaxElement::string>("# www.blender.org\n");
+}
+
+void OBJWriter::write_mtllib_name(const StringRefNull mtl_filepath) const
+{
+ /* Split .MTL file path into parent directory and filename. */
+ char mtl_file_name[FILE_MAXFILE];
+ char mtl_dir_name[FILE_MAXDIR];
+ BLI_split_dirfile(mtl_filepath.data(), mtl_dir_name, mtl_file_name, FILE_MAXDIR, FILE_MAXFILE);
+ file_handler_->write<eOBJSyntaxElement::mtllib>(mtl_file_name);
+}
+
+void OBJWriter::write_object_group(const OBJMesh &obj_mesh_data) const
+{
+ /* "o object_name" is not mandatory. A valid .OBJ file may contain neither
+ * "o name" nor "g group_name". */
+ BLI_assert(export_params_.export_object_groups);
+ if (!export_params_.export_object_groups) {
+ return;
+ }
+ const std::string object_name = obj_mesh_data.get_object_name();
+ const char *object_mesh_name = obj_mesh_data.get_object_mesh_name();
+ const char *object_material_name = obj_mesh_data.get_object_material_name(0);
+ if (export_params_.export_materials && export_params_.export_material_groups &&
+ object_material_name) {
+ file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name +
+ "_" + object_material_name);
+ return;
+ }
+ file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name);
+}
+
+void OBJWriter::write_object_name(const OBJMesh &obj_mesh_data) const
+{
+ const char *object_name = obj_mesh_data.get_object_name();
+ if (export_params_.export_object_groups) {
+ write_object_group(obj_mesh_data);
+ return;
+ }
+ file_handler_->write<eOBJSyntaxElement::object_name>(object_name);
+}
+
+void OBJWriter::write_vertex_coords(const OBJMesh &obj_mesh_data) const
+{
+ const int tot_vertices = obj_mesh_data.tot_vertices();
+ for (int i = 0; i < tot_vertices; i++) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ file_handler_->write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
+ }
+}
+
+void OBJWriter::write_uv_coords(OBJMesh &r_obj_mesh_data) const
+{
+ Vector<std::array<float, 2>> uv_coords;
+ /* UV indices are calculated and stored in an OBJMesh member here. */
+ r_obj_mesh_data.store_uv_coords_and_indices(uv_coords);
+
+ for (const std::array<float, 2> &uv_vertex : uv_coords) {
+ file_handler_->write<eOBJSyntaxElement::uv_vertex_coords>(uv_vertex[0], uv_vertex[1]);
+ }
+}
+
+void OBJWriter::write_poly_normals(OBJMesh &obj_mesh_data)
+{
+ obj_mesh_data.ensure_mesh_normals();
+ Vector<float3> normals;
+ obj_mesh_data.store_normal_coords_and_indices(normals);
+ for (const float3 &normal : normals) {
+ file_handler_->write<eOBJSyntaxElement::normal>(normal[0], normal[1], normal[2]);
+ }
+}
+
+int OBJWriter::write_smooth_group(const OBJMesh &obj_mesh_data,
+ const int poly_index,
+ const int last_poly_smooth_group) const
+{
+ int current_group = SMOOTH_GROUP_DISABLED;
+ if (!export_params_.export_smooth_groups && obj_mesh_data.is_ith_poly_smooth(poly_index)) {
+ /* Smooth group calculation is disabled, but polygon is smooth-shaded. */
+ current_group = SMOOTH_GROUP_DEFAULT;
+ }
+ else if (obj_mesh_data.is_ith_poly_smooth(poly_index)) {
+ /* Smooth group calc is enabled and polygon is smooth–shaded, so find the group. */
+ current_group = obj_mesh_data.ith_smooth_group(poly_index);
+ }
+
+ if (current_group == last_poly_smooth_group) {
+ /* Group has already been written, even if it is "s 0". */
+ return current_group;
+ }
+ file_handler_->write<eOBJSyntaxElement::smooth_group>(current_group);
+ return current_group;
+}
+
+int16_t OBJWriter::write_poly_material(const OBJMesh &obj_mesh_data,
+ const int poly_index,
+ const int16_t last_poly_mat_nr,
+ std::function<const char *(int)> matname_fn) const
+{
+ if (!export_params_.export_materials || obj_mesh_data.tot_materials() <= 0) {
+ return last_poly_mat_nr;
+ }
+ const int16_t current_mat_nr = obj_mesh_data.ith_poly_matnr(poly_index);
+ /* Whenever a polygon with a new material is encountered, write its material
+ * and/or group, otherwise pass. */
+ if (last_poly_mat_nr == current_mat_nr) {
+ return current_mat_nr;
+ }
+ if (current_mat_nr == NOT_FOUND) {
+ file_handler_->write<eOBJSyntaxElement::poly_usemtl>(MATERIAL_GROUP_DISABLED);
+ return current_mat_nr;
+ }
+ if (export_params_.export_object_groups) {
+ write_object_group(obj_mesh_data);
+ }
+ const char *mat_name = matname_fn(current_mat_nr);
+ if (!mat_name) {
+ mat_name = MATERIAL_GROUP_DISABLED;
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_usemtl>(mat_name);
+
+ return current_mat_nr;
+}
+
+int16_t OBJWriter::write_vertex_group(const OBJMesh &obj_mesh_data,
+ const int poly_index,
+ const int16_t last_poly_vertex_group) const
+{
+ if (!export_params_.export_vertex_groups) {
+ return last_poly_vertex_group;
+ }
+ const int16_t current_group = obj_mesh_data.get_poly_deform_group_index(poly_index);
+
+ if (current_group == last_poly_vertex_group) {
+ /* No vertex group found in this polygon, just like in the last iteration. */
+ return current_group;
+ }
+ if (current_group == NOT_FOUND) {
+ file_handler_->write<eOBJSyntaxElement::object_group>(DEFORM_GROUP_DISABLED);
+ return current_group;
+ }
+ file_handler_->write<eOBJSyntaxElement::object_group>(
+ obj_mesh_data.get_poly_deform_group_name(current_group));
+ return current_group;
+}
+
+OBJWriter::func_vert_uv_normal_indices OBJWriter::get_poly_element_writer(
+ const int total_uv_vertices) const
+{
+ if (export_params_.export_normals) {
+ if (export_params_.export_uv && (total_uv_vertices > 0)) {
+ /* Write both normals and UV indices. */
+ return &OBJWriter::write_vert_uv_normal_indices;
+ }
+ /* Write normals indices. */
+ return &OBJWriter::write_vert_normal_indices;
+ }
+ /* Write UV indices. */
+ if (export_params_.export_uv && (total_uv_vertices > 0)) {
+ return &OBJWriter::write_vert_uv_indices;
+ }
+ /* Write neither normals nor UV indices. */
+ return &OBJWriter::write_vert_indices;
+}
+
+void OBJWriter::write_poly_elements(const OBJMesh &obj_mesh_data,
+ std::function<const char *(int)> matname_fn)
+{
+ int last_poly_smooth_group = NEGATIVE_INIT;
+ int16_t last_poly_vertex_group = NEGATIVE_INIT;
+ int16_t last_poly_mat_nr = NEGATIVE_INIT;
+
+ const func_vert_uv_normal_indices poly_element_writer = get_poly_element_writer(
+ obj_mesh_data.tot_uv_vertices());
+
+ const int tot_polygons = obj_mesh_data.tot_polygons();
+ for (int i = 0; i < tot_polygons; i++) {
+ Vector<int> poly_vertex_indices = obj_mesh_data.calc_poly_vertex_indices(i);
+ Span<int> poly_uv_indices = obj_mesh_data.calc_poly_uv_indices(i);
+ Vector<int> poly_normal_indices = obj_mesh_data.calc_poly_normal_indices(i);
+
+ last_poly_smooth_group = write_smooth_group(obj_mesh_data, i, last_poly_smooth_group);
+ last_poly_vertex_group = write_vertex_group(obj_mesh_data, i, last_poly_vertex_group);
+ last_poly_mat_nr = write_poly_material(obj_mesh_data, i, last_poly_mat_nr, matname_fn);
+ (this->*poly_element_writer)(poly_vertex_indices, poly_uv_indices, poly_normal_indices);
+ }
+}
+
+void OBJWriter::write_edges_indices(const OBJMesh &obj_mesh_data) const
+{
+ obj_mesh_data.ensure_mesh_edges();
+ const int tot_edges = obj_mesh_data.tot_edges();
+ for (int edge_index = 0; edge_index < tot_edges; edge_index++) {
+ const std::optional<std::array<int, 2>> vertex_indices =
+ obj_mesh_data.calc_loose_edge_vert_indices(edge_index);
+ if (!vertex_indices) {
+ continue;
+ }
+ file_handler_->write<eOBJSyntaxElement::edge>(
+ (*vertex_indices)[0] + index_offsets_.vertex_offset + 1,
+ (*vertex_indices)[1] + index_offsets_.vertex_offset + 1);
+ }
+}
+
+void OBJWriter::write_nurbs_curve(const OBJCurve &obj_nurbs_data) const
+{
+ const int total_splines = obj_nurbs_data.total_splines();
+ for (int spline_idx = 0; spline_idx < total_splines; spline_idx++) {
+ const int total_vertices = obj_nurbs_data.total_spline_vertices(spline_idx);
+ for (int vertex_idx = 0; vertex_idx < total_vertices; vertex_idx++) {
+ const float3 vertex_coords = obj_nurbs_data.vertex_coordinates(
+ spline_idx, vertex_idx, export_params_.scaling_factor);
+ file_handler_->write<eOBJSyntaxElement::vertex_coords>(
+ vertex_coords[0], vertex_coords[1], vertex_coords[2]);
+ }
+
+ const char *nurbs_name = obj_nurbs_data.get_curve_name();
+ const int nurbs_degree = obj_nurbs_data.get_nurbs_degree(spline_idx);
+ file_handler_->write<eOBJSyntaxElement::object_group>(nurbs_name);
+ file_handler_->write<eOBJSyntaxElement::cstype>();
+ file_handler_->write<eOBJSyntaxElement::nurbs_degree>(nurbs_degree);
+ /**
+ * The numbers written here are indices into the vertex coordinates written
+ * earlier, relative to the line that is going to be written.
+ * [0.0 - 1.0] is the curve parameter range.
+ * 0.0 1.0 -1 -2 -3 -4 for a non-cyclic curve with 4 vertices.
+ * 0.0 1.0 -1 -2 -3 -4 -1 -2 -3 for a cyclic curve with 4 vertices.
+ */
+ const int total_control_points = obj_nurbs_data.total_spline_control_points(spline_idx);
+ file_handler_->write<eOBJSyntaxElement::curve_element_begin>();
+ for (int i = 0; i < total_control_points; i++) {
+ /* "+1" to keep indices one-based, even if they're negative: i.e., -1 refers to the
+ * last vertex coordinate, -2 second last. */
+ file_handler_->write<eOBJSyntaxElement::vertex_indices>(-((i % total_vertices) + 1));
+ }
+ file_handler_->write<eOBJSyntaxElement::curve_element_end>();
+
+ /**
+ * In `parm u 0 0.1 ..` line:, (total control points + 2) equidistant numbers in the
+ * parameter range are inserted.
+ */
+ file_handler_->write<eOBJSyntaxElement::nurbs_parameter_begin>();
+ for (int i = 1; i <= total_control_points + 2; i++) {
+ file_handler_->write<eOBJSyntaxElement::nurbs_parameters>(1.0f * i /
+ (total_control_points + 2 + 1));
+ }
+ file_handler_->write<eOBJSyntaxElement::nurbs_parameter_end>();
+
+ file_handler_->write<eOBJSyntaxElement::nurbs_group_end>();
+ }
+}
+
+void OBJWriter::update_index_offsets(const OBJMesh &obj_mesh_data)
+{
+ index_offsets_.vertex_offset += obj_mesh_data.tot_vertices();
+ index_offsets_.uv_vertex_offset += obj_mesh_data.tot_uv_vertices();
+ index_offsets_.normal_offset += obj_mesh_data.tot_normal_indices();
+}
+
+/* -------------------------------------------------------------------- */
+/** \name .MTL writers.
+ * \{ */
+
+/**
+ * Convert #float3 to string of space-separated numbers, with no leading or trailing space.
+ * Only to be used in NON-performance-critical code.
+ */
+static std::string float3_to_string(const float3 &numbers)
+{
+ std::ostringstream r_string;
+ r_string << numbers[0] << " " << numbers[1] << " " << numbers[2];
+ return r_string.str();
+};
+
+MTLWriter::MTLWriter(const char *obj_filepath) noexcept(false)
+{
+ mtl_filepath_ = obj_filepath;
+ const bool ok = BLI_path_extension_replace(mtl_filepath_.data(), FILE_MAX, ".mtl");
+ if (!ok) {
+ throw std::system_error(ENAMETOOLONG, std::system_category(), "");
+ }
+ file_handler_ = std::make_unique<FormattedFileHandler<eFileType::MTL>>(mtl_filepath_);
+}
+
+void MTLWriter::write_header(const char *blen_filepath) const
+{
+ using namespace std::string_literals;
+ const char *blen_basename = (blen_filepath && blen_filepath[0] != '\0') ?
+ BLI_path_basename(blen_filepath) :
+ "None";
+ file_handler_->write<eMTLSyntaxElement::string>("# Blender "s + BKE_blender_version_string() +
+ " MTL File: '" + blen_basename + "'\n");
+ file_handler_->write<eMTLSyntaxElement::string>("# www.blender.org\n");
+}
+
+StringRefNull MTLWriter::mtl_file_path() const
+{
+ return mtl_filepath_;
+}
+
+void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl_material)
+{
+ file_handler_->write<eMTLSyntaxElement::Ns>(mtl_material.Ns);
+ file_handler_->write<eMTLSyntaxElement::Ka>(
+ mtl_material.Ka.x, mtl_material.Ka.y, mtl_material.Ka.z);
+ file_handler_->write<eMTLSyntaxElement::Kd>(
+ mtl_material.Kd.x, mtl_material.Kd.y, mtl_material.Kd.z);
+ file_handler_->write<eMTLSyntaxElement::Ks>(
+ mtl_material.Ks.x, mtl_material.Ks.y, mtl_material.Ks.z);
+ file_handler_->write<eMTLSyntaxElement::Ke>(
+ mtl_material.Ke.x, mtl_material.Ke.y, mtl_material.Ke.z);
+ file_handler_->write<eMTLSyntaxElement::Ni>(mtl_material.Ni);
+ file_handler_->write<eMTLSyntaxElement::d>(mtl_material.d);
+ file_handler_->write<eMTLSyntaxElement::illum>(mtl_material.illum);
+}
+
+void MTLWriter::write_texture_map(
+ const MTLMaterial &mtl_material,
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map)
+{
+ std::string translation;
+ std::string scale;
+ std::string map_bump_strength;
+ /* Optional strings should have their own leading spaces. */
+ if (texture_map.value.translation != float3{0.0f, 0.0f, 0.0f}) {
+ translation.append(" -s ").append(float3_to_string(texture_map.value.translation));
+ }
+ if (texture_map.value.scale != float3{1.0f, 1.0f, 1.0f}) {
+ scale.append(" -o ").append(float3_to_string(texture_map.value.scale));
+ }
+ if (texture_map.key == eMTLSyntaxElement::map_Bump && mtl_material.map_Bump_strength > 0.0001f) {
+ map_bump_strength.append(" -bm ").append(std::to_string(mtl_material.map_Bump_strength));
+ }
+
+#define SYNTAX_DISPATCH(eMTLSyntaxElement) \
+ if (texture_map.key == eMTLSyntaxElement) { \
+ file_handler_->write<eMTLSyntaxElement>(translation + scale + map_bump_strength, \
+ texture_map.value.image_path); \
+ return; \
+ }
+
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Kd);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ks);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ns);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_d);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_refl);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ke);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Bump);
+
+ BLI_assert(!"This map type was not written to the file.");
+}
+
+void MTLWriter::write_materials()
+{
+ if (mtlmaterials_.size() == 0) {
+ return;
+ }
+ std::sort(mtlmaterials_.begin(),
+ mtlmaterials_.end(),
+ [](const MTLMaterial &a, const MTLMaterial &b) { return a.name < b.name; });
+ for (const MTLMaterial &mtlmat : mtlmaterials_) {
+ file_handler_->write<eMTLSyntaxElement::string>("\n");
+ file_handler_->write<eMTLSyntaxElement::newmtl>(mtlmat.name);
+ write_bsdf_properties(mtlmat);
+ for (const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map :
+ mtlmat.texture_maps.items()) {
+ if (!texture_map.value.image_path.empty()) {
+ write_texture_map(mtlmat, texture_map);
+ }
+ }
+ }
+}
+
+Vector<int> MTLWriter::add_materials(const OBJMesh &mesh_to_export)
+{
+ Vector<int> r_mtl_indices;
+ r_mtl_indices.resize(mesh_to_export.tot_materials());
+ for (int16_t i = 0; i < mesh_to_export.tot_materials(); i++) {
+ const Material *material = mesh_to_export.get_object_material(i);
+ if (!material) {
+ r_mtl_indices[i] = -1;
+ continue;
+ }
+ int mtlmat_index = material_map_.lookup_default(material, -1);
+ if (mtlmat_index != -1) {
+ r_mtl_indices[i] = mtlmat_index;
+ }
+ else {
+ mtlmaterials_.append(mtlmaterial_for_material(material));
+ r_mtl_indices[i] = mtlmaterials_.size() - 1;
+ material_map_.add_new(material, r_mtl_indices[i]);
+ }
+ }
+ return r_mtl_indices;
+}
+
+const char *MTLWriter::mtlmaterial_name(int index)
+{
+ if (index < 0 || index >= mtlmaterials_.size()) {
+ return nullptr;
+ }
+ return mtlmaterials_[index].name.c_str();
+}
+/** \} */
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
new file mode 100644
index 00000000000..7385d9fabe2
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -0,0 +1,217 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include "DNA_meshdata_types.h"
+
+#include "BLI_map.hh"
+#include "BLI_vector.hh"
+
+#include "IO_wavefront_obj.h"
+#include "obj_export_io.hh"
+#include "obj_export_mtl.hh"
+
+namespace blender::io::obj {
+
+class OBJCurve;
+class OBJMesh;
+/**
+ * Total vertices/ UV vertices/ normals of previous Objects
+ * should be added to the current Object's indices.
+ */
+struct IndexOffsets {
+ int vertex_offset;
+ int uv_vertex_offset;
+ int normal_offset;
+};
+
+/**
+ * Responsible for writing a .OBJ file.
+ */
+class OBJWriter : NonMovable, NonCopyable {
+ private:
+ const OBJExportParams &export_params_;
+ std::unique_ptr<FormattedFileHandler<eFileType::OBJ>> file_handler_ = nullptr;
+ IndexOffsets index_offsets_{0, 0, 0};
+
+ public:
+ OBJWriter(const char *filepath, const OBJExportParams &export_params) noexcept(false)
+ : export_params_(export_params)
+ {
+ file_handler_ = std::make_unique<FormattedFileHandler<eFileType::OBJ>>(filepath);
+ }
+
+ void write_header() const;
+
+ /**
+ * Write object's name or group.
+ */
+ void write_object_name(const OBJMesh &obj_mesh_data) const;
+ /**
+ * Write an object's group with mesh and/or material name appended conditionally.
+ */
+ void write_object_group(const OBJMesh &obj_mesh_data) const;
+ /**
+ * Write file name of Material Library in .OBJ file.
+ */
+ void write_mtllib_name(const StringRefNull mtl_filepath) const;
+ /**
+ * Write vertex coordinates for all vertices as "v x y z".
+ */
+ void write_vertex_coords(const OBJMesh &obj_mesh_data) const;
+ /**
+ * Write UV vertex coordinates for all vertices as `vt u v`.
+ * \note UV indices are stored here, but written with polygons later.
+ */
+ void write_uv_coords(OBJMesh &obj_mesh_data) const;
+ /**
+ * Write loop normals for smooth-shaded polygons, and polygon normals otherwise, as "vn x y z".
+ * \note Normal indices ares stored here, but written with polygons later.
+ */
+ void write_poly_normals(OBJMesh &obj_mesh_data);
+ /**
+ * Write smooth group if polygon at the given index is shaded smooth else "s 0"
+ */
+ int write_smooth_group(const OBJMesh &obj_mesh_data,
+ int poly_index,
+ int last_poly_smooth_group) const;
+ /**
+ * Write material name and material group of a polygon in the .OBJ file.
+ * \return #mat_nr of the polygon at the given index.
+ * \note It doesn't write to the material library.
+ */
+ int16_t write_poly_material(const OBJMesh &obj_mesh_data,
+ int poly_index,
+ int16_t last_poly_mat_nr,
+ std::function<const char *(int)> matname_fn) const;
+ /**
+ * Write the name of the deform group of a polygon.
+ */
+ int16_t write_vertex_group(const OBJMesh &obj_mesh_data,
+ int poly_index,
+ int16_t last_poly_vertex_group) const;
+ /**
+ * Write polygon elements with at least vertex indices, and conditionally with UV vertex
+ * indices and polygon normal indices. Also write groups: smooth, vertex, material.
+ * The matname_fn turns a 0-indexed material slot number in an Object into the
+ * name used in the .obj file.
+ * \note UV indices were stored while writing UV vertices.
+ */
+ void write_poly_elements(const OBJMesh &obj_mesh_data,
+ std::function<const char *(int)> matname_fn);
+ /**
+ * Write loose edges of a mesh as "l v1 v2".
+ */
+ void write_edges_indices(const OBJMesh &obj_mesh_data) const;
+ /**
+ * Write a NURBS curve to the .OBJ file in parameter form.
+ */
+ void write_nurbs_curve(const OBJCurve &obj_nurbs_data) const;
+
+ /**
+ * When there are multiple objects in a frame, the indices of previous objects' coordinates or
+ * normals add up.
+ */
+ void update_index_offsets(const OBJMesh &obj_mesh_data);
+
+ private:
+ using func_vert_uv_normal_indices = void (OBJWriter::*)(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> normal_indices) const;
+ /**
+ * \return Writer function with appropriate polygon-element syntax.
+ */
+ func_vert_uv_normal_indices get_poly_element_writer(int total_uv_vertices) const;
+
+ /**
+ * Write one line of polygon indices as "f v1/vt1/vn1 v2/vt2/vn2 ...".
+ */
+ void write_vert_uv_normal_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> normal_indices) const;
+ /**
+ * Write one line of polygon indices as "f v1//vn1 v2//vn2 ...".
+ */
+ void write_vert_normal_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> normal_indices) const;
+ /**
+ * Write one line of polygon indices as "f v1/vt1 v2/vt2 ...".
+ */
+ void write_vert_uv_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> /*normal_indices*/) const;
+ /**
+ * Write one line of polygon indices as "f v1 v2 ...".
+ */
+ void write_vert_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> /*normal_indices*/) const;
+};
+
+/**
+ * Responsible for writing a .MTL file.
+ */
+class MTLWriter : NonMovable, NonCopyable {
+ private:
+ std::unique_ptr<FormattedFileHandler<eFileType::MTL>> file_handler_ = nullptr;
+ std::string mtl_filepath_;
+ Vector<MTLMaterial> mtlmaterials_;
+ /* Map from a Material* to an index into mtlmaterials_. */
+ Map<const Material *, int> material_map_;
+
+ public:
+ /*
+ * Create the .MTL file.
+ */
+ MTLWriter(const char *obj_filepath) noexcept(false);
+
+ void write_header(const char *blen_filepath) const;
+ /**
+ * Write all of the material specifications to the MTL file.
+ * For consistency of output from run to run (useful for testing),
+ * the materials are sorted by name before writing.
+ */
+ void write_materials();
+ StringRefNull mtl_file_path() const;
+ /**
+ * Add the materials of the given object to #MTLWriter, de-duplicating
+ * against ones that are already there.
+ * Return a Vector of indices into mtlmaterials_ that hold the #MTLMaterial
+ * that corresponds to each material slot, in order, of the given Object.
+ * Indexes are returned rather than pointers to the MTLMaterials themselves
+ * because the mtlmaterials_ Vector may move around when resized.
+ */
+ Vector<int> add_materials(const OBJMesh &mesh_to_export);
+ const char *mtlmaterial_name(int index);
+
+ private:
+ /**
+ * Write properties sourced from p-BSDF node or #Object.Material.
+ */
+ void write_bsdf_properties(const MTLMaterial &mtl_material);
+ /**
+ * Write a texture map in the form "map_XX -s 1. 1. 1. -o 0. 0. 0. [-bm 1.] path/to/image".
+ */
+ void write_texture_map(const MTLMaterial &mtl_material,
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map);
+};
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
new file mode 100644
index 00000000000..1bbefaee75f
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
@@ -0,0 +1,353 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include <cstdio>
+#include <string>
+#include <system_error>
+#include <type_traits>
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_fileops.h"
+#include "BLI_string_ref.hh"
+#include "BLI_utility_mixins.hh"
+
+namespace blender::io::obj {
+
+enum class eFileType {
+ OBJ,
+ MTL,
+};
+
+enum class eOBJSyntaxElement {
+ vertex_coords,
+ uv_vertex_coords,
+ normal,
+ poly_element_begin,
+ vertex_uv_normal_indices,
+ vertex_normal_indices,
+ vertex_uv_indices,
+ vertex_indices,
+ poly_element_end,
+ poly_usemtl,
+ edge,
+ cstype,
+ nurbs_degree,
+ curve_element_begin,
+ curve_element_end,
+ nurbs_parameter_begin,
+ nurbs_parameters,
+ nurbs_parameter_end,
+ nurbs_group_end,
+ new_line,
+ mtllib,
+ smooth_group,
+ object_group,
+ object_name,
+ /* Use rarely. New line is NOT included for string. */
+ string,
+};
+
+enum class eMTLSyntaxElement {
+ newmtl,
+ Ni,
+ d,
+ Ns,
+ illum,
+ Ka,
+ Kd,
+ Ks,
+ Ke,
+ map_Kd,
+ map_Ks,
+ map_Ns,
+ map_d,
+ map_refl,
+ map_Ke,
+ map_Bump,
+ /* Use rarely. New line is NOT included for string. */
+ string,
+};
+
+template<eFileType filetype> struct FileTypeTraits;
+
+/* Used to prevent mixing of say OBJ file format with MTL syntax elements. */
+template<> struct FileTypeTraits<eFileType::OBJ> {
+ using SyntaxType = eOBJSyntaxElement;
+};
+
+template<> struct FileTypeTraits<eFileType::MTL> {
+ using SyntaxType = eMTLSyntaxElement;
+};
+
+struct FormattingSyntax {
+ /* Formatting syntax with the file format key like `newmtl %s\n`. */
+ const char *fmt = nullptr;
+ /* Number of arguments needed by the syntax. */
+ const int total_args = 0;
+ /* Whether types of the given arguments are accepted by the syntax above. Fail to compile by
+ * default.
+ */
+ const bool are_types_valid = false;
+};
+
+/**
+ * Type dependent but always false. Use to add a `constexpr` conditional compile-time error.
+ */
+template<typename T> struct always_false : std::false_type {
+};
+
+template<typename... T>
+constexpr bool is_type_float = (... && std::is_floating_point_v<std::decay_t<T>>);
+
+template<typename... T>
+constexpr bool is_type_integral = (... && std::is_integral_v<std::decay_t<T>>);
+
+template<typename... T>
+constexpr bool is_type_string_related = (... && std::is_constructible_v<std::string, T>);
+
+template<typename... T>
+constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key)
+{
+ switch (key) {
+ case eOBJSyntaxElement::vertex_coords: {
+ return {"v %f %f %f\n", 3, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::uv_vertex_coords: {
+ return {"vt %f %f\n", 2, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::normal: {
+ return {"vn %.4f %.4f %.4f\n", 3, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::poly_element_begin: {
+ return {"f", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::vertex_uv_normal_indices: {
+ return {" %d/%d/%d", 3, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::vertex_normal_indices: {
+ return {" %d//%d", 2, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::vertex_uv_indices: {
+ return {" %d/%d", 2, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::vertex_indices: {
+ return {" %d", 1, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::poly_usemtl: {
+ return {"usemtl %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::edge: {
+ return {"l %d %d\n", 2, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::cstype: {
+ return {"cstype bspline\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_degree: {
+ return {"deg %d\n", 1, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::curve_element_begin: {
+ return {"curv 0.0 1.0", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_parameter_begin: {
+ return {"parm 0.0", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_parameters: {
+ return {" %f", 1, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_parameter_end: {
+ return {" 1.0\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_group_end: {
+ return {"end\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::poly_element_end: {
+ ATTR_FALLTHROUGH;
+ }
+ case eOBJSyntaxElement::curve_element_end: {
+ ATTR_FALLTHROUGH;
+ }
+ case eOBJSyntaxElement::new_line: {
+ return {"\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::mtllib: {
+ return {"mtllib %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::smooth_group: {
+ return {"s %d\n", 1, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::object_group: {
+ return {"g %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::object_name: {
+ return {"o %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::string: {
+ return {"%s", 1, is_type_string_related<T...>};
+ }
+ }
+}
+
+template<typename... T>
+constexpr FormattingSyntax syntax_elem_to_formatting(const eMTLSyntaxElement key)
+{
+ switch (key) {
+ case eMTLSyntaxElement::newmtl: {
+ return {"newmtl %s\n", 1, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::Ni: {
+ return {"Ni %.6f\n", 1, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::d: {
+ return {"d %.6f\n", 1, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Ns: {
+ return {"Ns %.6f\n", 1, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::illum: {
+ return {"illum %d\n", 1, is_type_integral<T...>};
+ }
+ case eMTLSyntaxElement::Ka: {
+ return {"Ka %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Kd: {
+ return {"Kd %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Ks: {
+ return {"Ks %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Ke: {
+ return {"Ke %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ /* Keep only one space between options since filepaths may have leading spaces too. */
+ case eMTLSyntaxElement::map_Kd: {
+ return {"map_Kd %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Ks: {
+ return {"map_Ks %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Ns: {
+ return {"map_Ns %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_d: {
+ return {"map_d %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_refl: {
+ return {"map_refl %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Ke: {
+ return {"map_Ke %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Bump: {
+ return {"map_Bump %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::string: {
+ return {"%s", 1, is_type_string_related<T...>};
+ }
+ }
+}
+
+/**
+ * File format and syntax agnostic file writer.
+ */
+template<eFileType filetype> class FormattedFileHandler : NonCopyable, NonMovable {
+ private:
+ std::FILE *outfile_ = nullptr;
+ std::string outfile_path_;
+
+ public:
+ FormattedFileHandler(std::string outfile_path) noexcept(false)
+ : outfile_path_(std::move(outfile_path))
+ {
+ outfile_ = BLI_fopen(outfile_path_.c_str(), "w");
+ if (!outfile_) {
+ throw std::system_error(errno, std::system_category(), "Cannot open file " + outfile_path_);
+ }
+ }
+
+ ~FormattedFileHandler()
+ {
+ if (outfile_ && std::fclose(outfile_)) {
+ std::cerr << "Error: could not close the file '" << outfile_path_
+ << "' properly, it may be corrupted." << std::endl;
+ }
+ }
+
+ /**
+ * Example invocation: `writer->write<eMTLSyntaxElement::newmtl>("foo")`.
+ *
+ * \param key Must match what the instance's filetype expects; i.e., `eMTLSyntaxElement` for
+ * `eFileType::MTL`.
+ */
+ template<typename FileTypeTraits<filetype>::SyntaxType key, typename... T>
+ constexpr void write(T &&...args) const
+ {
+ /* Get format syntax, number of arguments expected and whether types of given arguments are
+ * valid.
+ */
+ constexpr FormattingSyntax fmt_nargs_valid = syntax_elem_to_formatting<T...>(key);
+ BLI_STATIC_ASSERT(fmt_nargs_valid.are_types_valid &&
+ (sizeof...(T) == fmt_nargs_valid.total_args),
+ "Types of all arguments and the number of arguments should match what the "
+ "formatting specifies.");
+ write_impl(fmt_nargs_valid.fmt, std::forward<T>(args)...);
+ }
+
+ private:
+ /* Remove this after upgrading to C++20. */
+ template<typename T> using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
+
+ /**
+ * Make #std::string etc., usable for `fprintf` family. int float etc. are not affected.
+ * \return: `const char *` or the original argument if the argument is
+ * not related to #std::string.
+ */
+ template<typename T> constexpr auto convert_to_primitive(T &&arg) const
+ {
+ if constexpr (std::is_same_v<remove_cvref_t<T>, std::string> ||
+ std::is_same_v<remove_cvref_t<T>, blender::StringRefNull>) {
+ return arg.c_str();
+ }
+ else if constexpr (std::is_same_v<remove_cvref_t<T>, blender::StringRef>) {
+ BLI_STATIC_ASSERT(
+ (always_false<T>::value),
+ "Null-terminated string not present. Please use blender::StringRefNull instead.");
+ /* Another trick to cause a compile-time error: returning nothing to #std::printf. */
+ return;
+ }
+ else {
+ /* For int, float etc. */
+ return std::forward<T>(arg);
+ }
+ }
+
+ template<typename... T> constexpr void write_impl(const char *fmt, T &&...args) const
+ {
+ if constexpr (sizeof...(T) == 0) {
+ std::fputs(fmt, outfile_);
+ }
+ else {
+ std::fprintf(outfile_, fmt, convert_to_primitive(std::forward<T>(args))...);
+ }
+ }
+};
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
new file mode 100644
index 00000000000..c1b12ddd217
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -0,0 +1,468 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+/* Silence warnings from copying deprecated fields. Needed for an Object copy constructor use. */
+#define DNA_DEPRECATED_ALLOW
+
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_lib_id.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_map.hh"
+#include "BLI_math.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "obj_export_mesh.hh"
+
+namespace blender::io::obj {
+OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object)
+{
+ /* We need to copy the object because it may be in temporary space. */
+ Object *obj_eval = DEG_get_evaluated_object(depsgraph, mesh_object);
+ export_object_eval_ = *obj_eval;
+ export_mesh_eval_ = BKE_object_get_evaluated_mesh(&export_object_eval_);
+ mesh_eval_needs_free_ = false;
+
+ if (!export_mesh_eval_) {
+ /* Curves and NURBS surfaces need a new mesh when they're
+ * exported in the form of vertices and edges.
+ */
+ export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true);
+ /* Since a new mesh been allocated, it needs to be freed in the destructor. */
+ mesh_eval_needs_free_ = true;
+ }
+ if (export_params.export_triangulated_mesh && ELEM(export_object_eval_.type, OB_MESH, OB_SURF)) {
+ std::tie(export_mesh_eval_, mesh_eval_needs_free_) = triangulate_mesh_eval();
+ }
+ set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
+}
+
+/**
+ * Free new meshes allocated for triangulated meshes, or Curve converted to Mesh.
+ */
+OBJMesh::~OBJMesh()
+{
+ free_mesh_if_needed();
+ if (poly_smooth_groups_) {
+ MEM_freeN(poly_smooth_groups_);
+ }
+}
+
+void OBJMesh::free_mesh_if_needed()
+{
+ if (mesh_eval_needs_free_ && export_mesh_eval_) {
+ BKE_id_free(nullptr, export_mesh_eval_);
+ }
+}
+
+std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
+{
+ if (export_mesh_eval_->totpoly <= 0) {
+ return {export_mesh_eval_, false};
+ }
+ const struct BMeshCreateParams bm_create_params = {0u};
+ const struct BMeshFromMeshParams bm_convert_params = {1u, 0, 0, 0};
+ /* Lower threshold where triangulation of a polygon starts, i.e. a quadrilateral will be
+ * triangulated here. */
+ const int triangulate_min_verts = 4;
+
+ unique_bmesh_ptr bmesh(
+ BKE_mesh_to_bmesh_ex(export_mesh_eval_, &bm_create_params, &bm_convert_params));
+ BM_mesh_triangulate(bmesh.get(),
+ MOD_TRIANGULATE_NGON_BEAUTY,
+ MOD_TRIANGULATE_QUAD_SHORTEDGE,
+ triangulate_min_verts,
+ false,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain(
+ bmesh.get(), nullptr, export_mesh_eval_);
+ free_mesh_if_needed();
+ return {triangulated, true};
+}
+
+void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward,
+ const eTransformAxisUp up)
+{
+ float axes_transform[3][3];
+ unit_m3(axes_transform);
+ /* +Y-forward and +Z-up are the default Blender axis settings. */
+ mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform);
+ /* mat3_from_axis_conversion returns a transposed matrix! */
+ transpose_m3(axes_transform);
+ mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.obmat);
+ /* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */
+ mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_.obmat[3]);
+ world_and_axes_transform_[3][3] = export_object_eval_.obmat[3][3];
+}
+
+int OBJMesh::tot_vertices() const
+{
+ return export_mesh_eval_->totvert;
+}
+
+int OBJMesh::tot_polygons() const
+{
+ return export_mesh_eval_->totpoly;
+}
+
+int OBJMesh::tot_uv_vertices() const
+{
+ return tot_uv_vertices_;
+}
+
+int OBJMesh::tot_edges() const
+{
+ return export_mesh_eval_->totedge;
+}
+
+int16_t OBJMesh::tot_materials() const
+{
+ return export_mesh_eval_->totcol;
+}
+
+int OBJMesh::tot_normal_indices() const
+{
+ return tot_normal_indices_;
+}
+
+int OBJMesh::ith_smooth_group(const int poly_index) const
+{
+ /* Calculate smooth groups first: #OBJMesh::calc_smooth_groups. */
+ BLI_assert(tot_smooth_groups_ != -NEGATIVE_INIT);
+ BLI_assert(poly_smooth_groups_);
+ return poly_smooth_groups_[poly_index];
+}
+
+void OBJMesh::ensure_mesh_normals() const
+{
+ BKE_mesh_calc_normals_split(export_mesh_eval_);
+}
+
+void OBJMesh::ensure_mesh_edges() const
+{
+ BKE_mesh_calc_edges(export_mesh_eval_, true, false);
+ BKE_mesh_calc_edges_loose(export_mesh_eval_);
+}
+
+void OBJMesh::calc_smooth_groups(const bool use_bitflags)
+{
+ poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(export_mesh_eval_->medge,
+ export_mesh_eval_->totedge,
+ export_mesh_eval_->mpoly,
+ export_mesh_eval_->totpoly,
+ export_mesh_eval_->mloop,
+ export_mesh_eval_->totloop,
+ &tot_smooth_groups_,
+ use_bitflags);
+}
+
+const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
+{
+ /**
+ * The const_cast is safe here because BKE_object_material_get won't change the object
+ * but it is a big can of worms to fix the declaration of that function right now.
+ *
+ * The call uses "+ 1" as material getter needs one-based indices.
+ */
+ Object *obj = const_cast<Object *>(&export_object_eval_);
+ const Material *r_mat = BKE_object_material_get(obj, mat_nr + 1);
+#ifdef DEBUG
+ if (!r_mat) {
+ std::cerr << "Material not found for mat_nr = " << mat_nr << std::endl;
+ }
+#endif
+ return r_mat;
+}
+
+bool OBJMesh::is_ith_poly_smooth(const int poly_index) const
+{
+ return export_mesh_eval_->mpoly[poly_index].flag & ME_SMOOTH;
+}
+
+int16_t OBJMesh::ith_poly_matnr(const int poly_index) const
+{
+ BLI_assert(poly_index < export_mesh_eval_->totpoly);
+ const int16_t r_mat_nr = export_mesh_eval_->mpoly[poly_index].mat_nr;
+ return r_mat_nr >= 0 ? r_mat_nr : NOT_FOUND;
+}
+
+const char *OBJMesh::get_object_name() const
+{
+ return export_object_eval_.id.name + 2;
+}
+
+const char *OBJMesh::get_object_mesh_name() const
+{
+ return export_mesh_eval_->id.name + 2;
+}
+
+const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
+{
+ const Material *mat = get_object_material(mat_nr);
+ if (!mat) {
+ return nullptr;
+ }
+ return mat->id.name + 2;
+}
+
+float3 OBJMesh::calc_vertex_coords(const int vert_index, const float scaling_factor) const
+{
+ float3 r_coords;
+ copy_v3_v3(r_coords, export_mesh_eval_->mvert[vert_index].co);
+ mul_v3_fl(r_coords, scaling_factor);
+ mul_m4_v3(world_and_axes_transform_, r_coords);
+ return r_coords;
+}
+
+Vector<int> OBJMesh::calc_poly_vertex_indices(const int poly_index) const
+{
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart];
+ const int totloop = mpoly.totloop;
+ Vector<int> r_poly_vertex_indices(totloop);
+ for (int loop_index = 0; loop_index < totloop; loop_index++) {
+ r_poly_vertex_indices[loop_index] = mloop[loop_index].v;
+ }
+ return r_poly_vertex_indices;
+}
+
+void OBJMesh::store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coords)
+{
+ const MPoly *mpoly = export_mesh_eval_->mpoly;
+ const MLoop *mloop = export_mesh_eval_->mloop;
+ const int totpoly = export_mesh_eval_->totpoly;
+ const int totvert = export_mesh_eval_->totvert;
+ const MLoopUV *mloopuv = static_cast<MLoopUV *>(
+ CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV));
+ if (!mloopuv) {
+ tot_uv_vertices_ = 0;
+ return;
+ }
+ const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
+
+ UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(
+ mpoly, mloop, mloopuv, totpoly, totvert, limit, false, false);
+
+ uv_indices_.resize(totpoly);
+ /* At least total vertices of a mesh will be present in its texture map. So
+ * reserve minimum space early. */
+ r_uv_coords.reserve(totvert);
+
+ tot_uv_vertices_ = 0;
+ for (int vertex_index = 0; vertex_index < totvert; vertex_index++) {
+ const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index);
+ for (; uv_vert; uv_vert = uv_vert->next) {
+ if (uv_vert->separate) {
+ tot_uv_vertices_ += 1;
+ }
+ const int vertices_in_poly = mpoly[uv_vert->poly_index].totloop;
+
+ /* Store UV vertex coordinates. */
+ r_uv_coords.resize(tot_uv_vertices_);
+ const int loopstart = mpoly[uv_vert->poly_index].loopstart;
+ Span<float> vert_uv_coords(mloopuv[loopstart + uv_vert->loop_of_poly_index].uv, 2);
+ r_uv_coords[tot_uv_vertices_ - 1][0] = vert_uv_coords[0];
+ r_uv_coords[tot_uv_vertices_ - 1][1] = vert_uv_coords[1];
+
+ /* Store UV vertex indices. */
+ uv_indices_[uv_vert->poly_index].resize(vertices_in_poly);
+ /* Keep indices zero-based and let the writer handle the "+ 1" as per OBJ spec. */
+ uv_indices_[uv_vert->poly_index][uv_vert->loop_of_poly_index] = tot_uv_vertices_ - 1;
+ }
+ }
+ BKE_mesh_uv_vert_map_free(uv_vert_map);
+}
+
+Span<int> OBJMesh::calc_poly_uv_indices(const int poly_index) const
+{
+ if (uv_indices_.size() <= 0) {
+ return {};
+ }
+ BLI_assert(poly_index < export_mesh_eval_->totpoly);
+ BLI_assert(poly_index < uv_indices_.size());
+ return uv_indices_[poly_index];
+}
+
+float3 OBJMesh::calc_poly_normal(const int poly_index) const
+{
+ float3 r_poly_normal;
+ const MPoly &poly = export_mesh_eval_->mpoly[poly_index];
+ const MLoop &mloop = export_mesh_eval_->mloop[poly.loopstart];
+ const MVert &mvert = *(export_mesh_eval_->mvert);
+ BKE_mesh_calc_poly_normal(&poly, &mloop, &mvert, r_poly_normal);
+ mul_mat3_m4_v3(world_and_axes_transform_, r_poly_normal);
+ return r_poly_normal;
+}
+
+/** Round \a f to \a round_digits decimal digits. */
+static float round_float_to_n_digits(const float f, int round_digits)
+{
+ float scale = powf(10.0, round_digits);
+ return ceilf((scale * f - 0.49999999f)) / scale;
+}
+
+static float3 round_float3_to_n_digits(const float3 &v, int round_digits)
+{
+ float3 ans;
+ ans.x = round_float_to_n_digits(v.x, round_digits);
+ ans.y = round_float_to_n_digits(v.y, round_digits);
+ ans.z = round_float_to_n_digits(v.z, round_digits);
+ return ans;
+}
+
+void OBJMesh::store_normal_coords_and_indices(Vector<float3> &r_normal_coords)
+{
+ /* We'll round normal components to 4 digits.
+ * This will cover up some minor differences
+ * between floating point calculations on different platforms.
+ * Since normals are normalized, there will be no perceptible loss
+ * of precision when rounding to 4 digits. */
+ constexpr int round_digits = 4;
+ int cur_normal_index = 0;
+ Map<float3, int> normal_to_index;
+ /* We don't know how many unique normals there will be, but this is a guess. */
+ normal_to_index.reserve(export_mesh_eval_->totpoly);
+ loop_to_normal_index_.resize(export_mesh_eval_->totloop);
+ loop_to_normal_index_.fill(-1);
+ const float(
+ *lnors)[3] = (const float(*)[3])(CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL));
+ for (int poly_index = 0; poly_index < export_mesh_eval_->totpoly; ++poly_index) {
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ bool need_per_loop_normals = is_ith_poly_smooth(poly_index);
+ if (need_per_loop_normals) {
+ for (int loop_of_poly = 0; loop_of_poly < mpoly.totloop; ++loop_of_poly) {
+ float3 loop_normal;
+ int loop_index = mpoly.loopstart + loop_of_poly;
+ BLI_assert(loop_index < export_mesh_eval_->totloop);
+ copy_v3_v3(loop_normal, lnors[loop_index]);
+ mul_mat3_m4_v3(world_and_axes_transform_, loop_normal);
+ float3 rounded_loop_normal = round_float3_to_n_digits(loop_normal, round_digits);
+ int loop_norm_index = normal_to_index.lookup_default(rounded_loop_normal, -1);
+ if (loop_norm_index == -1) {
+ loop_norm_index = cur_normal_index++;
+ normal_to_index.add(rounded_loop_normal, loop_norm_index);
+ r_normal_coords.append(rounded_loop_normal);
+ }
+ loop_to_normal_index_[loop_index] = loop_norm_index;
+ }
+ }
+ else {
+ float3 poly_normal = calc_poly_normal(poly_index);
+ float3 rounded_poly_normal = round_float3_to_n_digits(poly_normal, round_digits);
+ int poly_norm_index = normal_to_index.lookup_default(rounded_poly_normal, -1);
+ if (poly_norm_index == -1) {
+ poly_norm_index = cur_normal_index++;
+ normal_to_index.add(rounded_poly_normal, poly_norm_index);
+ r_normal_coords.append(rounded_poly_normal);
+ }
+ for (int i = 0; i < mpoly.totloop; ++i) {
+ int loop_index = mpoly.loopstart + i;
+ BLI_assert(loop_index < export_mesh_eval_->totloop);
+ loop_to_normal_index_[loop_index] = poly_norm_index;
+ }
+ }
+ }
+ tot_normal_indices_ = cur_normal_index;
+}
+
+Vector<int> OBJMesh::calc_poly_normal_indices(const int poly_index) const
+{
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ const int totloop = mpoly.totloop;
+ Vector<int> r_poly_normal_indices(totloop);
+ for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) {
+ int loop_index = mpoly.loopstart + poly_loop_index;
+ r_poly_normal_indices[poly_loop_index] = loop_to_normal_index_[loop_index];
+ }
+ return r_poly_normal_indices;
+}
+
+int16_t OBJMesh::get_poly_deform_group_index(const int poly_index) const
+{
+ BLI_assert(poly_index < export_mesh_eval_->totpoly);
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart];
+ const Object *obj = &export_object_eval_;
+ const int tot_deform_groups = BKE_object_defgroup_count(obj);
+ /* Indices of the vector index into deform groups of an object; values are the]
+ * number of vertex members in one deform group. */
+ Vector<int16_t> deform_group_members(tot_deform_groups, 0);
+ /* Whether at least one vertex in the polygon belongs to any group. */
+ bool found_group = false;
+
+ const MDeformVert *dvert_orig = static_cast<MDeformVert *>(
+ CustomData_get_layer(&export_mesh_eval_->vdata, CD_MDEFORMVERT));
+ if (!dvert_orig) {
+ return NOT_FOUND;
+ }
+
+ const MDeformWeight *curr_weight = nullptr;
+ const MDeformVert *dvert = nullptr;
+ for (int loop_index = 0; loop_index < mpoly.totloop; loop_index++) {
+ dvert = &dvert_orig[(mloop + loop_index)->v];
+ curr_weight = dvert->dw;
+ if (curr_weight) {
+ bDeformGroup *vertex_group = static_cast<bDeformGroup *>(
+ BLI_findlink(BKE_object_defgroup_list(obj), curr_weight->def_nr));
+ if (vertex_group) {
+ deform_group_members[curr_weight->def_nr] += 1;
+ found_group = true;
+ }
+ }
+ }
+
+ if (!found_group) {
+ return NOT_FOUND;
+ }
+ /* Index of the group with maximum vertices. */
+ int16_t max_idx = std::max_element(deform_group_members.begin(), deform_group_members.end()) -
+ deform_group_members.begin();
+ return max_idx;
+}
+
+const char *OBJMesh::get_poly_deform_group_name(const int16_t def_group_index) const
+{
+ const bDeformGroup &vertex_group = *(static_cast<bDeformGroup *>(
+ BLI_findlink(BKE_object_defgroup_list(&export_object_eval_), def_group_index)));
+ return vertex_group.name;
+}
+
+std::optional<std::array<int, 2>> OBJMesh::calc_loose_edge_vert_indices(const int edge_index) const
+{
+ const MEdge &edge = export_mesh_eval_->medge[edge_index];
+ if (edge.flag & ME_LOOSEEDGE) {
+ return std::array<int, 2>{static_cast<int>(edge.v1), static_cast<int>(edge.v2)};
+ }
+ return std::nullopt;
+}
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
new file mode 100644
index 00000000000..f3ace140006
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -0,0 +1,226 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include <optional>
+
+#include "BLI_math_vec_types.hh"
+#include "BLI_utility_mixins.hh"
+#include "BLI_vector.hh"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "IO_wavefront_obj.h"
+
+namespace blender::io::obj {
+/** Denote absence for usually non-negative numbers. */
+const int NOT_FOUND = -1;
+/** Any negative number other than `NOT_FOUND` to initialize usually non-negative numbers. */
+const int NEGATIVE_INIT = -10;
+
+/**
+ * #std::unique_ptr than handles freeing #BMesh.
+ */
+struct CustomBMeshDeleter {
+ void operator()(BMesh *bmesh)
+ {
+ if (bmesh) {
+ BM_mesh_free(bmesh);
+ }
+ }
+};
+
+using unique_bmesh_ptr = std::unique_ptr<BMesh, CustomBMeshDeleter>;
+
+class OBJMesh : NonCopyable {
+ private:
+ /**
+ * We need to copy the entire Object structure here because the dependency graph iterator
+ * sometimes builds an Object in a temporary space that doesn't persist.
+ */
+ Object export_object_eval_;
+ Mesh *export_mesh_eval_;
+ /**
+ * For curves which are converted to mesh, and triangulated meshes, a new mesh is allocated.
+ */
+ bool mesh_eval_needs_free_ = false;
+ /**
+ * Final transform of an object obtained from export settings (up_axis, forward_axis) and the
+ * object's world transform matrix.
+ */
+ float world_and_axes_transform_[4][4];
+
+ /**
+ * Total UV vertices in a mesh's texture map.
+ */
+ int tot_uv_vertices_ = 0;
+ /**
+ * Per-polygon-per-vertex UV vertex indices.
+ */
+ Vector<Vector<int>> uv_indices_;
+ /**
+ * Per-loop normal index.
+ */
+ Vector<int> loop_to_normal_index_;
+ /*
+ * Total number of normal indices (maximum entry, plus 1, in
+ * the loop_to_norm_index_ vector).
+ */
+ int tot_normal_indices_ = 0;
+ /**
+ * Total smooth groups in an object.
+ */
+ int tot_smooth_groups_ = NEGATIVE_INIT;
+ /**
+ * Polygon aligned array of their smooth groups.
+ */
+ int *poly_smooth_groups_ = nullptr;
+
+ public:
+ /**
+ * Store evaluated Object and Mesh pointers. Conditionally triangulate a mesh, or
+ * create a new Mesh from a Curve.
+ */
+ OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object);
+ ~OBJMesh();
+
+ int tot_vertices() const;
+ int tot_polygons() const;
+ int tot_uv_vertices() const;
+ int tot_normal_indices() const;
+ int tot_edges() const;
+
+ /**
+ * \return Total materials in the object.
+ */
+ int16_t tot_materials() const;
+ /**
+ * Return mat_nr-th material of the object. The given index should be zero-based.
+ */
+ const Material *get_object_material(int16_t mat_nr) const;
+ /**
+ * Returns a zero-based index of a polygon's material indexing into
+ * the Object's material slots.
+ */
+ int16_t ith_poly_matnr(int poly_index) const;
+
+ void ensure_mesh_normals() const;
+ void ensure_mesh_edges() const;
+
+ /**
+ * Calculate smooth groups of a smooth-shaded object.
+ * \return A polygon aligned array of smooth group numbers.
+ */
+ void calc_smooth_groups(bool use_bitflags);
+ /**
+ * \return Smooth group of the polygon at the given index.
+ */
+ int ith_smooth_group(int poly_index) const;
+ bool is_ith_poly_smooth(int poly_index) const;
+
+ /**
+ * Get object name as it appears in the outliner.
+ */
+ const char *get_object_name() const;
+ /**
+ * Get Object's Mesh's name.
+ */
+ const char *get_object_mesh_name() const;
+ /**
+ * Get object's material (at the given index) name. The given index should be zero-based.
+ */
+ const char *get_object_material_name(int16_t mat_nr) const;
+
+ /**
+ * Calculate coordinates of the vertex at the given index.
+ */
+ float3 calc_vertex_coords(int vert_index, float scaling_factor) const;
+ /**
+ * Calculate vertex indices of all vertices of the polygon at the given index.
+ */
+ Vector<int> calc_poly_vertex_indices(int poly_index) const;
+ /**
+ * Calculate UV vertex coordinates of an Object.
+ *
+ * \note Also store the UV vertex indices in the member variable.
+ */
+ void store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coords);
+ Span<int> calc_poly_uv_indices(int poly_index) const;
+ /**
+ * Calculate polygon normal of a polygon at given index.
+ *
+ * Should be used for flat-shaded polygons.
+ */
+ float3 calc_poly_normal(int poly_index) const;
+ /**
+ * Find the unique normals of the mesh and return them in \a r_normal_coords.
+ * Store the indices into that vector with for each loop in this #OBJMesh.
+ */
+ void store_normal_coords_and_indices(Vector<float3> &r_normal_coords);
+ /**
+ * Calculate a polygon's polygon/loop normal indices.
+ * \param poly_index Index of the polygon to calculate indices for.
+ * \return Vector of normal indices, aligned with vertices of polygon.
+ */
+ Vector<int> calc_poly_normal_indices(int poly_index) const;
+ /**
+ * Find the index of the vertex group with the maximum number of vertices in a polygon.
+ * The index indices into the #Object.defbase.
+ *
+ * If two or more groups have the same number of vertices (maximum), group name depends on the
+ * implementation of #std::max_element.
+ */
+ int16_t get_poly_deform_group_index(int poly_index) const;
+ /**
+ * Find the name of the vertex deform group at the given index.
+ * The index indices into the #Object.defbase.
+ */
+ const char *get_poly_deform_group_name(int16_t def_group_index) const;
+
+ /**
+ * Calculate vertex indices of an edge's corners if it is a loose edge.
+ */
+ std::optional<std::array<int, 2>> calc_loose_edge_vert_indices(int edge_index) const;
+
+ private:
+ /**
+ * Free the mesh if _the exporter_ created it.
+ */
+ void free_mesh_if_needed();
+ /**
+ * Allocate a new Mesh with triangulated polygons.
+ *
+ * The returned mesh can be the same as the old one.
+ * \return Owning pointer to the new Mesh, and whether a new Mesh was created.
+ */
+ std::pair<Mesh *, bool> triangulate_mesh_eval();
+ /**
+ * Set the final transform after applying axes settings and an Object's world transform.
+ */
+ void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up);
+};
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
new file mode 100644
index 00000000000..48136dad5f7
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
@@ -0,0 +1,360 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include "BKE_image.h"
+#include "BKE_node.h"
+
+#include "BLI_map.hh"
+#include "BLI_math_vec_types.hh"
+#include "BLI_path_util.h"
+
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+
+#include "NOD_node_tree_ref.hh"
+
+#include "obj_export_mesh.hh"
+#include "obj_export_mtl.hh"
+
+namespace blender::io::obj {
+
+/**
+ * Copy a float property of the given type from the bNode to given buffer.
+ */
+static void copy_property_from_node(const eNodeSocketDatatype property_type,
+ const bNode *node,
+ const char *identifier,
+ MutableSpan<float> r_property)
+{
+ if (!node) {
+ return;
+ }
+ bNodeSocket *socket{nodeFindSocket(node, SOCK_IN, identifier)};
+ BLI_assert(socket && socket->type == property_type);
+ if (!socket) {
+ return;
+ }
+ switch (property_type) {
+ case SOCK_FLOAT: {
+ BLI_assert(r_property.size() == 1);
+ bNodeSocketValueFloat *socket_def_value = static_cast<bNodeSocketValueFloat *>(
+ socket->default_value);
+ r_property[0] = socket_def_value->value;
+ break;
+ }
+ case SOCK_RGBA: {
+ BLI_assert(r_property.size() == 3);
+ bNodeSocketValueRGBA *socket_def_value = static_cast<bNodeSocketValueRGBA *>(
+ socket->default_value);
+ copy_v3_v3(r_property.data(), socket_def_value->value);
+ break;
+ }
+ case SOCK_VECTOR: {
+ BLI_assert(r_property.size() == 3);
+ bNodeSocketValueVector *socket_def_value = static_cast<bNodeSocketValueVector *>(
+ socket->default_value);
+ copy_v3_v3(r_property.data(), socket_def_value->value);
+ break;
+ }
+ default: {
+ /* Other socket types are not handled here. */
+ BLI_assert(0);
+ break;
+ }
+ }
+}
+
+/**
+ * Collect all the source sockets linked to the destination socket in a destination node.
+ */
+static void linked_sockets_to_dest_id(const bNode *dest_node,
+ const nodes::NodeTreeRef &node_tree,
+ StringRefNull dest_socket_id,
+ Vector<const nodes::OutputSocketRef *> &r_linked_sockets)
+{
+ r_linked_sockets.clear();
+ if (!dest_node) {
+ return;
+ }
+ Span<const nodes::NodeRef *> object_dest_nodes = node_tree.nodes_by_type(dest_node->idname);
+ Span<const nodes::InputSocketRef *> dest_inputs = object_dest_nodes.first()->inputs();
+ const nodes::InputSocketRef *dest_socket = nullptr;
+ for (const nodes::InputSocketRef *curr_socket : dest_inputs) {
+ if (STREQ(curr_socket->bsocket()->identifier, dest_socket_id.c_str())) {
+ dest_socket = curr_socket;
+ break;
+ }
+ }
+ if (dest_socket) {
+ Span<const nodes::OutputSocketRef *> linked_sockets = dest_socket->directly_linked_sockets();
+ r_linked_sockets.resize(linked_sockets.size());
+ r_linked_sockets = linked_sockets;
+ }
+}
+
+/**
+ * From a list of sockets, get the parent node which is of the given node type.
+ */
+static const bNode *get_node_of_type(Span<const nodes::OutputSocketRef *> sockets_list,
+ const int node_type)
+{
+ for (const nodes::SocketRef *socket : sockets_list) {
+ const bNode *parent_node = socket->bnode();
+ if (parent_node->typeinfo->type == node_type) {
+ return parent_node;
+ }
+ }
+ return nullptr;
+}
+
+/**
+ * From a texture image shader node, get the image's filepath.
+ * Returned filepath is stripped of initial "//". If packed image is found,
+ * only the file "name" is returned.
+ */
+static const char *get_image_filepath(const bNode *tex_node)
+{
+ if (!tex_node) {
+ return nullptr;
+ }
+ Image *tex_image = reinterpret_cast<Image *>(tex_node->id);
+ if (!tex_image || !BKE_image_has_filepath(tex_image)) {
+ return nullptr;
+ }
+ const char *path = tex_image->filepath;
+ if (BKE_image_has_packedfile(tex_image)) {
+ /* Put image in the same directory as the .MTL file. */
+ path = BLI_path_slash_rfind(path) + 1;
+ fprintf(stderr,
+ "Packed image found:'%s'. Unpack and place the image in the same "
+ "directory as the .MTL file.\n",
+ path);
+ }
+ if (path[0] == '/' && path[1] == '/') {
+ path += 2;
+ }
+ return path;
+}
+
+/**
+ * Find the Principled-BSDF Node in nodetree.
+ * We only want one that feeds directly into a Material Output node
+ * (that is the behavior of the legacy Python exporter).
+ */
+static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree)
+{
+ if (!nodetree) {
+ return nullptr;
+ }
+ for (const nodes::NodeRef *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) {
+ const nodes::InputSocketRef *node_input_socket0 = node->inputs()[0];
+ for (const nodes::OutputSocketRef *out_sock : node_input_socket0->directly_linked_sockets()) {
+ const nodes::NodeRef &in_node = out_sock->node();
+ if (in_node.typeinfo()->type == SH_NODE_BSDF_PRINCIPLED) {
+ return &in_node;
+ }
+ }
+ }
+ return nullptr;
+}
+
+/**
+ * Store properties found either in bNode or material into r_mtl_mat.
+ */
+static void store_bsdf_properties(const nodes::NodeRef *bsdf_node,
+ const Material *material,
+ MTLMaterial &r_mtl_mat)
+{
+ const bNode *bnode = nullptr;
+ if (bsdf_node) {
+ bnode = bsdf_node->bnode();
+ }
+
+ /* If p-BSDF is not present, fallback to #Object.Material. */
+ float roughness = material->roughness;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Roughness", {&roughness, 1});
+ }
+ /* Empirical approximation. Importer should use the inverse of this method. */
+ float spec_exponent = (1.0f - roughness) * 30;
+ spec_exponent *= spec_exponent;
+
+ float specular = material->spec;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Specular", {&specular, 1});
+ }
+
+ float metallic = material->metallic;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Metallic", {&metallic, 1});
+ }
+
+ float refraction_index = 1.0f;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "IOR", {&refraction_index, 1});
+ }
+
+ float dissolved = material->a;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Alpha", {&dissolved, 1});
+ }
+ const bool transparent = dissolved != 1.0f;
+
+ float3 diffuse_col = {material->r, material->g, material->b};
+ if (bnode) {
+ copy_property_from_node(SOCK_RGBA, bnode, "Base Color", {diffuse_col, 3});
+ }
+
+ float3 emission_col{0.0f};
+ float emission_strength = 0.0f;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1});
+ copy_property_from_node(SOCK_RGBA, bnode, "Emission", {emission_col, 3});
+ }
+ mul_v3_fl(emission_col, emission_strength);
+
+ /* See https://wikipedia.org/wiki/Wavefront_.obj_file for all possible values of `illum`. */
+ /* Highlight on. */
+ int illum = 2;
+ if (specular == 0.0f) {
+ /* Color on and Ambient on. */
+ illum = 1;
+ }
+ else if (metallic > 0.0f) {
+ /* Metallic ~= Reflection. */
+ if (transparent) {
+ /* Transparency: Refraction on, Reflection: ~~Fresnel off and Ray trace~~ on. */
+ illum = 6;
+ }
+ else {
+ /* Reflection on and Ray trace on. */
+ illum = 3;
+ }
+ }
+ else if (transparent) {
+ /* Transparency: Glass on, Reflection: Ray trace off */
+ illum = 9;
+ }
+ r_mtl_mat.Ns = spec_exponent;
+ if (metallic != 0.0f) {
+ r_mtl_mat.Ka = {metallic, metallic, metallic};
+ }
+ else {
+ r_mtl_mat.Ka = {1.0f, 1.0f, 1.0f};
+ }
+ r_mtl_mat.Kd = diffuse_col;
+ r_mtl_mat.Ks = {specular, specular, specular};
+ r_mtl_mat.Ke = emission_col;
+ r_mtl_mat.Ni = refraction_index;
+ r_mtl_mat.d = dissolved;
+ r_mtl_mat.illum = illum;
+}
+
+/**
+ * Store image texture options and file-paths in `r_mtl_mat`.
+ */
+static void store_image_textures(const nodes::NodeRef *bsdf_node,
+ const nodes::NodeTreeRef *node_tree,
+ const Material *material,
+ MTLMaterial &r_mtl_mat)
+{
+ if (!material || !node_tree || !bsdf_node) {
+ /* No nodetree, no images, or no Principled BSDF node. */
+ return;
+ }
+ const bNode *bnode = bsdf_node->bnode();
+
+ /* Normal Map Texture has two extra tasks of:
+ * - finding a Normal Map node before finding a texture node.
+ * - finding "Strength" property of the node for `-bm` option.
+ */
+
+ for (Map<const eMTLSyntaxElement, tex_map_XX>::MutableItem texture_map :
+ r_mtl_mat.texture_maps.items()) {
+ Vector<const nodes::OutputSocketRef *> linked_sockets;
+ const bNode *normal_map_node{nullptr};
+
+ if (texture_map.key == eMTLSyntaxElement::map_Bump) {
+ /* Find sockets linked to destination "Normal" socket in P-BSDF node. */
+ linked_sockets_to_dest_id(bnode, *node_tree, "Normal", linked_sockets);
+ /* Among the linked sockets, find Normal Map shader node. */
+ normal_map_node = get_node_of_type(linked_sockets, SH_NODE_NORMAL_MAP);
+
+ /* Find sockets linked to "Color" socket in normal map node. */
+ linked_sockets_to_dest_id(normal_map_node, *node_tree, "Color", linked_sockets);
+ }
+ else if (texture_map.key == eMTLSyntaxElement::map_Ke) {
+ float emission_strength = 0.0f;
+ copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1});
+ if (emission_strength == 0.0f) {
+ continue;
+ }
+ }
+ else {
+ /* Find sockets linked to the destination socket of interest, in P-BSDF node. */
+ linked_sockets_to_dest_id(
+ bnode, *node_tree, texture_map.value.dest_socket_id, linked_sockets);
+ }
+
+ /* Among the linked sockets, find Image Texture shader node. */
+ const bNode *tex_node{get_node_of_type(linked_sockets, SH_NODE_TEX_IMAGE)};
+ if (!tex_node) {
+ continue;
+ }
+ const char *tex_image_filepath = get_image_filepath(tex_node);
+ if (!tex_image_filepath) {
+ continue;
+ }
+
+ /* Find "Mapping" node if connected to texture node. */
+ linked_sockets_to_dest_id(tex_node, *node_tree, "Vector", linked_sockets);
+ const bNode *mapping = get_node_of_type(linked_sockets, SH_NODE_MAPPING);
+
+ if (normal_map_node) {
+ copy_property_from_node(
+ SOCK_FLOAT, normal_map_node, "Strength", {&r_mtl_mat.map_Bump_strength, 1});
+ }
+ /* Texture transform options. Only translation (origin offset, "-o") and scale
+ * ("-o") are supported. */
+ copy_property_from_node(SOCK_VECTOR, mapping, "Location", {texture_map.value.translation, 3});
+ copy_property_from_node(SOCK_VECTOR, mapping, "Scale", {texture_map.value.scale, 3});
+
+ texture_map.value.image_path = tex_image_filepath;
+ }
+}
+
+MTLMaterial mtlmaterial_for_material(const Material *material)
+{
+ BLI_assert(material != nullptr);
+ MTLMaterial mtlmat;
+ mtlmat.name = std::string(material->id.name + 2);
+ std::replace(mtlmat.name.begin(), mtlmat.name.end(), ' ', '_');
+ const nodes::NodeTreeRef *nodetree = nullptr;
+ if (material->nodetree) {
+ nodetree = new nodes::NodeTreeRef(material->nodetree);
+ }
+ const nodes::NodeRef *bsdf_node = find_bsdf_node(nodetree);
+ store_bsdf_properties(bsdf_node, material, mtlmat);
+ store_image_textures(bsdf_node, nodetree, material, mtlmat);
+ delete nodetree;
+ return mtlmat;
+}
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh
new file mode 100644
index 00000000000..a84dcb80a48
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh
@@ -0,0 +1,104 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include "BLI_map.hh"
+#include "BLI_math_vec_types.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_node_types.h"
+#include "obj_export_io.hh"
+
+namespace blender {
+template<> struct DefaultHash<io::obj::eMTLSyntaxElement> {
+ uint64_t operator()(const io::obj::eMTLSyntaxElement value) const
+ {
+ return static_cast<uint64_t>(value);
+ }
+};
+
+} // namespace blender
+
+namespace blender::io::obj {
+class OBJMesh;
+
+/**
+ * Generic container for texture node properties.
+ */
+struct tex_map_XX {
+ tex_map_XX(StringRef to_socket_id) : dest_socket_id(to_socket_id){};
+
+ /** Target socket which this texture node connects to. */
+ const std::string dest_socket_id;
+ float3 translation{0.0f};
+ float3 scale{1.0f};
+ /* Only Flat and Smooth projections are supported. */
+ int projection_type = SHD_PROJ_FLAT;
+ std::string image_path;
+ std::string mtl_dir_path;
+};
+
+/**
+ * Container suited for storing Material data for/from a .MTL file.
+ */
+struct MTLMaterial {
+ MTLMaterial()
+ {
+ texture_maps.add(eMTLSyntaxElement::map_Kd, tex_map_XX("Base Color"));
+ texture_maps.add(eMTLSyntaxElement::map_Ks, tex_map_XX("Specular"));
+ texture_maps.add(eMTLSyntaxElement::map_Ns, tex_map_XX("Roughness"));
+ texture_maps.add(eMTLSyntaxElement::map_d, tex_map_XX("Alpha"));
+ texture_maps.add(eMTLSyntaxElement::map_refl, tex_map_XX("Metallic"));
+ texture_maps.add(eMTLSyntaxElement::map_Ke, tex_map_XX("Emission"));
+ texture_maps.add(eMTLSyntaxElement::map_Bump, tex_map_XX("Normal"));
+ }
+
+ /**
+ * Caller must ensure that the given lookup key exists in the Map.
+ * \return Texture map corresponding to the given ID.
+ */
+ tex_map_XX &tex_map_of_type(const eMTLSyntaxElement key)
+ {
+ {
+ BLI_assert(texture_maps.contains_as(key));
+ return texture_maps.lookup_as(key);
+ }
+ }
+
+ std::string name;
+ /* Always check for negative values while importing or exporting. Use defaults if
+ * any value is negative. */
+ float Ns{-1.0f};
+ float3 Ka{-1.0f};
+ float3 Kd{-1.0f};
+ float3 Ks{-1.0f};
+ float3 Ke{-1.0f};
+ float Ni{-1.0f};
+ float d{-1.0f};
+ int illum{-1};
+ Map<const eMTLSyntaxElement, tex_map_XX> texture_maps;
+ /** Only used for Normal Map node: "map_Bump". */
+ float map_Bump_strength{-1.0f};
+};
+
+MTLMaterial mtlmaterial_for_material(const Material *material);
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
new file mode 100644
index 00000000000..ec690115115
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
@@ -0,0 +1,105 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "IO_wavefront_obj.h"
+#include "obj_export_nurbs.hh"
+
+namespace blender::io::obj {
+OBJCurve::OBJCurve(const Depsgraph *depsgraph,
+ const OBJExportParams &export_params,
+ Object *curve_object)
+ : export_object_eval_(curve_object)
+{
+ export_object_eval_ = DEG_get_evaluated_object(depsgraph, curve_object);
+ export_curve_ = static_cast<Curve *>(export_object_eval_->data);
+ set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
+}
+
+void OBJCurve::set_world_axes_transform(const eTransformAxisForward forward,
+ const eTransformAxisUp up)
+{
+ float axes_transform[3][3];
+ unit_m3(axes_transform);
+ /* +Y-forward and +Z-up are the Blender's default axis settings. */
+ mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform);
+ /* mat3_from_axis_conversion returns a transposed matrix! */
+ transpose_m3(axes_transform);
+ mul_m4_m3m4(world_axes_transform_, axes_transform, export_object_eval_->obmat);
+ /* #mul_m4_m3m4 does not transform last row of #Object.obmat, i.e. location data. */
+ mul_v3_m3v3(world_axes_transform_[3], axes_transform, export_object_eval_->obmat[3]);
+ world_axes_transform_[3][3] = export_object_eval_->obmat[3][3];
+}
+
+const char *OBJCurve::get_curve_name() const
+{
+ return export_object_eval_->id.name + 2;
+}
+
+int OBJCurve::total_splines() const
+{
+ return BLI_listbase_count(&export_curve_->nurb);
+}
+
+int OBJCurve::total_spline_vertices(const int spline_index) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ return nurb->pntsu * nurb->pntsv;
+}
+
+float3 OBJCurve::vertex_coordinates(const int spline_index,
+ const int vertex_index,
+ const float scaling_factor) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ float3 r_coord;
+ const BPoint &bpoint = nurb->bp[vertex_index];
+ copy_v3_v3(r_coord, bpoint.vec);
+ mul_m4_v3(world_axes_transform_, r_coord);
+ mul_v3_fl(r_coord, scaling_factor);
+ return r_coord;
+}
+
+int OBJCurve::total_spline_control_points(const int spline_index) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ const int r_nurbs_degree = nurb->orderu - 1;
+ /* Total control points = Number of points in the curve (+ degree of the
+ * curve if it is cyclic). */
+ int r_tot_control_points = nurb->pntsv * nurb->pntsu;
+ if (nurb->flagu & CU_NURB_CYCLIC) {
+ r_tot_control_points += r_nurbs_degree;
+ }
+ return r_tot_control_points;
+}
+
+int OBJCurve::get_nurbs_degree(const int spline_index) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ return nurb->orderu - 1;
+}
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
new file mode 100644
index 00000000000..0c71c3cc09d
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
@@ -0,0 +1,72 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include "BLI_utility_mixins.hh"
+
+#include "DNA_curve_types.h"
+
+namespace blender::io::obj {
+
+/**
+ * Provides access to the a Curve Object's properties.
+ * Only #CU_NURBS type is supported.
+ *
+ * \note Used for Curves to be exported in parameter form, and not converted to meshes.
+ */
+class OBJCurve : NonCopyable {
+ private:
+ const Object *export_object_eval_;
+ const Curve *export_curve_;
+ float world_axes_transform_[4][4];
+
+ public:
+ OBJCurve(const Depsgraph *depsgraph, const OBJExportParams &export_params, Object *curve_object);
+
+ const char *get_curve_name() const;
+ int total_splines() const;
+ /**
+ * \param spline_index: Zero-based index of spline of interest.
+ * \return: Total vertices in a spline.
+ */
+ int total_spline_vertices(int spline_index) const;
+ /**
+ * Get coordinates of the vertex at the given index on the given spline.
+ */
+ float3 vertex_coordinates(int spline_index, int vertex_index, float scaling_factor) const;
+ /**
+ * Get total control points of the NURBS spline at the given index. This is different than total
+ * vertices of a spline.
+ */
+ int total_spline_control_points(int spline_index) const;
+ /**
+ * Get the degree of the NURBS spline at the given index.
+ */
+ int get_nurbs_degree(int spline_index) const;
+
+ private:
+ /**
+ * Set the final transform after applying axes settings and an Object's world transform.
+ */
+ void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up);
+};
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
new file mode 100644
index 00000000000..0c753ccdcac
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.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.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include <cstdio>
+#include <exception>
+#include <memory>
+
+#include "BKE_scene.h"
+
+#include "BLI_path_util.h"
+#include "BLI_vector.hh"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_scene_types.h"
+
+#include "ED_object.h"
+
+#include "obj_export_mesh.hh"
+#include "obj_export_nurbs.hh"
+#include "obj_exporter.hh"
+
+#include "obj_export_file_writer.hh"
+
+namespace blender::io::obj {
+
+OBJDepsgraph::OBJDepsgraph(const bContext *C, const eEvaluationMode eval_mode)
+{
+ Scene *scene = CTX_data_scene(C);
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ if (eval_mode == DAG_EVAL_RENDER) {
+ depsgraph_ = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
+ needs_free_ = true;
+ DEG_graph_build_for_all_objects(depsgraph_);
+ BKE_scene_graph_evaluated_ensure(depsgraph_, bmain);
+ }
+ else {
+ depsgraph_ = CTX_data_ensure_evaluated_depsgraph(C);
+ needs_free_ = false;
+ }
+}
+
+OBJDepsgraph::~OBJDepsgraph()
+{
+ if (needs_free_) {
+ DEG_graph_free(depsgraph_);
+ }
+}
+
+Depsgraph *OBJDepsgraph::get()
+{
+ return depsgraph_;
+}
+
+void OBJDepsgraph::update_for_newframe()
+{
+ BKE_scene_graph_update_for_newframe(depsgraph_);
+}
+
+static void print_exception_error(const std::system_error &ex)
+{
+ std::cerr << ex.code().category().name() << ": " << ex.what() << ": " << ex.code().message()
+ << std::endl;
+}
+
+/**
+ * Filter supported objects from the Scene.
+ *
+ * \note Curves are also stored with Meshes if export settings specify so.
+ */
+std::pair<Vector<std::unique_ptr<OBJMesh>>, Vector<std::unique_ptr<OBJCurve>>>
+filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_params)
+{
+ Vector<std::unique_ptr<OBJMesh>> r_exportable_meshes;
+ Vector<std::unique_ptr<OBJCurve>> r_exportable_nurbs;
+ const int deg_objects_visibility_flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI;
+ DEG_OBJECT_ITER_BEGIN (depsgraph, object, deg_objects_visibility_flags) {
+ if (export_params.export_selected_objects && !(object->base_flag & BASE_SELECTED)) {
+ continue;
+ }
+ switch (object->type) {
+ case OB_SURF:
+ /* Export in mesh form: vertices and polygons. */
+ ATTR_FALLTHROUGH;
+ case OB_MESH:
+ r_exportable_meshes.append(std::make_unique<OBJMesh>(depsgraph, export_params, object));
+ break;
+ case OB_CURVE: {
+ Curve *curve = static_cast<Curve *>(object->data);
+ Nurb *nurb{static_cast<Nurb *>(curve->nurb.first)};
+ if (!nurb) {
+ /* An empty curve. Not yet supported to export these as meshes. */
+ if (export_params.export_curves_as_nurbs) {
+ r_exportable_nurbs.append(
+ std::make_unique<OBJCurve>(depsgraph, export_params, object));
+ }
+ break;
+ }
+ switch (nurb->type) {
+ case CU_NURBS:
+ if (export_params.export_curves_as_nurbs) {
+ /* Export in parameter form: control points. */
+ r_exportable_nurbs.append(
+ std::make_unique<OBJCurve>(depsgraph, export_params, object));
+ }
+ else {
+ /* Export in mesh form: edges and vertices. */
+ r_exportable_meshes.append(
+ std::make_unique<OBJMesh>(depsgraph, export_params, object));
+ }
+ break;
+ case CU_BEZIER:
+ /* Always export in mesh form: edges and vertices. */
+ r_exportable_meshes.append(
+ std::make_unique<OBJMesh>(depsgraph, export_params, object));
+ break;
+ default:
+ /* Other curve types are not supported. */
+ break;
+ }
+ break;
+ }
+ default:
+ /* Other object types are not supported. */
+ break;
+ }
+ }
+ DEG_OBJECT_ITER_END;
+ return {std::move(r_exportable_meshes), std::move(r_exportable_nurbs)};
+}
+
+static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_mesh,
+ OBJWriter &obj_writer,
+ MTLWriter *mtl_writer,
+ const OBJExportParams &export_params)
+{
+ if (mtl_writer) {
+ obj_writer.write_mtllib_name(mtl_writer->mtl_file_path());
+ }
+
+ /* Smooth groups and UV vertex indices may make huge memory allocations, so they should be freed
+ * right after they're written, instead of waiting for #blender::Vector to clean them up after
+ * all the objects are exported. */
+ for (auto &obj_mesh : exportable_as_mesh) {
+ obj_writer.write_object_name(*obj_mesh);
+ obj_writer.write_vertex_coords(*obj_mesh);
+ Vector<int> obj_mtlindices;
+
+ if (obj_mesh->tot_polygons() > 0) {
+ if (export_params.export_smooth_groups) {
+ obj_mesh->calc_smooth_groups(export_params.smooth_groups_bitflags);
+ }
+ if (export_params.export_normals) {
+ obj_writer.write_poly_normals(*obj_mesh);
+ }
+ if (export_params.export_uv) {
+ obj_writer.write_uv_coords(*obj_mesh);
+ }
+ if (mtl_writer) {
+ obj_mtlindices = mtl_writer->add_materials(*obj_mesh);
+ }
+ /* This function takes a 0-indexed slot index for the obj_mesh object and
+ * returns the material name that we are using in the .obj file for it. */
+ std::function<const char *(int)> matname_fn = [&](int s) -> const char * {
+ if (!mtl_writer || s < 0 || s >= obj_mtlindices.size()) {
+ return nullptr;
+ }
+ return mtl_writer->mtlmaterial_name(obj_mtlindices[s]);
+ };
+ obj_writer.write_poly_elements(*obj_mesh, matname_fn);
+ }
+ obj_writer.write_edges_indices(*obj_mesh);
+
+ obj_writer.update_index_offsets(*obj_mesh);
+ }
+}
+
+/**
+ * Export NURBS Curves in parameter form, not as vertices and edges.
+ */
+static void write_nurbs_curve_objects(const Vector<std::unique_ptr<OBJCurve>> &exportable_as_nurbs,
+ const OBJWriter &obj_writer)
+{
+ /* #OBJCurve doesn't have any dynamically allocated memory, so it's fine
+ * to wait for #blender::Vector to clean the objects up. */
+ for (const std::unique_ptr<OBJCurve> &obj_curve : exportable_as_nurbs) {
+ obj_writer.write_nurbs_curve(*obj_curve);
+ }
+}
+
+void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, const char *filepath)
+{
+ std::unique_ptr<OBJWriter> frame_writer = nullptr;
+ try {
+ frame_writer = std::make_unique<OBJWriter>(filepath, export_params);
+ }
+ catch (const std::system_error &ex) {
+ print_exception_error(ex);
+ return;
+ }
+ if (!frame_writer) {
+ BLI_assert(!"File should be writable by now.");
+ return;
+ }
+ std::unique_ptr<MTLWriter> mtl_writer = nullptr;
+ if (export_params.export_materials) {
+ try {
+ mtl_writer = std::make_unique<MTLWriter>(export_params.filepath);
+ }
+ catch (const std::system_error &ex) {
+ print_exception_error(ex);
+ }
+ }
+
+ frame_writer->write_header();
+
+ auto [exportable_as_mesh, exportable_as_nurbs] = filter_supported_objects(depsgraph,
+ export_params);
+
+ write_mesh_objects(
+ std::move(exportable_as_mesh), *frame_writer, mtl_writer.get(), export_params);
+ if (mtl_writer) {
+ mtl_writer->write_header(export_params.blen_filepath);
+ mtl_writer->write_materials();
+ }
+ write_nurbs_curve_objects(std::move(exportable_as_nurbs), *frame_writer);
+}
+
+bool append_frame_to_filename(const char *filepath, const int frame, char *r_filepath_with_frames)
+{
+ BLI_strncpy(r_filepath_with_frames, filepath, FILE_MAX);
+ BLI_path_extension_replace(r_filepath_with_frames, FILE_MAX, "");
+ const int digits = frame == 0 ? 1 : integer_digits_i(abs(frame));
+ BLI_path_frame(r_filepath_with_frames, frame, digits);
+ return BLI_path_extension_replace(r_filepath_with_frames, FILE_MAX, ".obj");
+}
+
+void exporter_main(bContext *C, const OBJExportParams &export_params)
+{
+ ED_object_mode_set(C, OB_MODE_OBJECT);
+ OBJDepsgraph obj_depsgraph(C, export_params.export_eval_mode);
+ Scene *scene = DEG_get_input_scene(obj_depsgraph.get());
+ const char *filepath = export_params.filepath;
+
+ /* Single frame export, i.e. no animation. */
+ if (!export_params.export_animation) {
+ fprintf(stderr, "Writing to %s\n", filepath);
+ export_frame(obj_depsgraph.get(), export_params, filepath);
+ return;
+ }
+
+ char filepath_with_frames[FILE_MAX];
+ /* Used to reset the Scene to its original state. */
+ const int original_frame = CFRA;
+
+ for (int frame = export_params.start_frame; frame <= export_params.end_frame; frame++) {
+ const bool filepath_ok = append_frame_to_filename(filepath, frame, filepath_with_frames);
+ if (!filepath_ok) {
+ fprintf(stderr, "Error: File Path too long.\n%s\n", filepath_with_frames);
+ return;
+ }
+
+ CFRA = frame;
+ obj_depsgraph.update_for_newframe();
+ fprintf(stderr, "Writing to %s\n", filepath_with_frames);
+ export_frame(obj_depsgraph.get(), export_params, filepath_with_frames);
+ }
+ CFRA = original_frame;
+}
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.hh b/source/blender/io/wavefront_obj/exporter/obj_exporter.hh
new file mode 100644
index 00000000000..a06898a21cf
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.hh
@@ -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.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include "BLI_utility_mixins.hh"
+
+#include "BLI_vector.hh"
+
+#include "IO_wavefront_obj.h"
+
+namespace blender::io::obj {
+
+/**
+ * Behaves like `std::unique_ptr<Depsgraph, custom_deleter>`.
+ * Needed to free a new Depsgraph created for #DAG_EVAL_RENDER.
+ */
+class OBJDepsgraph : NonMovable, NonCopyable {
+ private:
+ Depsgraph *depsgraph_ = nullptr;
+ bool needs_free_ = false;
+
+ public:
+ OBJDepsgraph(const bContext *C, eEvaluationMode eval_mode);
+ ~OBJDepsgraph();
+
+ Depsgraph *get();
+ void update_for_newframe();
+};
+
+/**
+ * The main function for exporting a .obj file according to the given `export_parameters`.
+ * It uses the context `C` to get the dependency graph, and from that, the `Scene`.
+ * Depending on whether or not `export_params.export_animation` is set, it writes
+ * either one file per animation frame, or just one file.
+ */
+/**
+ * Central internal function to call Scene update & writer functions.
+ */
+void exporter_main(bContext *C, const OBJExportParams &export_params);
+
+class OBJMesh;
+class OBJCurve;
+
+/**
+ * Export a single frame of a .obj file, according to the given `export_parameters`.
+ * The frame state is given in `depsgraph`.
+ * The output file name is given by `filepath`.
+ * This function is normally called from `exporter_main`, but is exposed here for testing purposes.
+ */
+/**
+ * Export a single frame to a .OBJ file.
+ *
+ * Conditionally write a .MTL file also.
+ */
+void export_frame(Depsgraph *depsgraph,
+ const OBJExportParams &export_params,
+ const char *filepath);
+
+/**
+ * Find the objects to be exported in the `view_layer` of the dependency graph`depsgraph`,
+ * and return them in vectors `unique_ptr`s of `OBJMesh` and `OBJCurve`.
+ * If `export_params.export_selected_objects` is set, then only selected objects are to be
+ * exported, else all objects are to be exported. But only objects of type `OB_MESH`, `OB_CURVE`,
+ * and `OB_SURF` are supported; the rest will be ignored. If `export_params.export_curves_as_nurbs`
+ * is set, then curves of type `CU_NURBS` are exported in curve form in the .obj file, otherwise
+ * they are converted to mesh and returned in the `OBJMesh` vector. All other exportable types are
+ * always converted to mesh and returned in the `OBJMesh` vector.
+ */
+std::pair<Vector<std::unique_ptr<OBJMesh>>, Vector<std::unique_ptr<OBJCurve>>>
+filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_params);
+
+/**
+ * Makes `r_filepath_with_frames` (which should point at a character array of size `FILE_MAX`)
+ * be `filepath` with its "#" characters replaced by the number representing `frame`, and with
+ * a .obj extension.
+ */
+/**
+ * Append the current frame number in the .OBJ file name.
+ *
+ * \return Whether the filepath is in #FILE_MAX limits.
+ */
+bool append_frame_to_filename(const char *filepath, int frame, char *r_filepath_with_frames);
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
new file mode 100644
index 00000000000..89e1de49511
--- /dev/null
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -0,0 +1,430 @@
+/* Apache License, Version 2.0 */
+
+#include <gtest/gtest.h>
+#include <ios>
+#include <memory>
+#include <string>
+#include <system_error>
+
+#include "testing/testing.h"
+#include "tests/blendfile_loading_base_test.h"
+
+#include "BKE_appdir.h"
+#include "BKE_blender_version.h"
+
+#include "BLI_fileops.h"
+#include "BLI_index_range.hh"
+#include "BLI_string_utf8.h"
+#include "BLI_vector.hh"
+
+#include "DEG_depsgraph.h"
+
+#include "obj_export_file_writer.hh"
+#include "obj_export_mesh.hh"
+#include "obj_export_nurbs.hh"
+#include "obj_exporter.hh"
+
+#include "obj_exporter_tests.hh"
+
+namespace blender::io::obj {
+/* Set this true to keep comparison-failing test output in temp file directory. */
+constexpr bool save_failing_test_output = false;
+
+/* This is also the test name. */
+class obj_exporter_test : public BlendfileLoadingBaseTest {
+ public:
+ /**
+ * \param filepath: relative to "tests" directory.
+ */
+ bool load_file_and_depsgraph(const std::string &filepath,
+ const eEvaluationMode eval_mode = DAG_EVAL_VIEWPORT)
+ {
+ if (!blendfile_load(filepath.c_str())) {
+ return false;
+ }
+ depsgraph_create(eval_mode);
+ return true;
+ }
+};
+
+const std::string all_objects_file = "io_tests/blend_scene/all_objects.blend";
+const std::string all_curve_objects_file = "io_tests/blend_scene/all_curves.blend";
+
+TEST_F(obj_exporter_test, filter_objects_curves_as_mesh)
+{
+ OBJExportParamsDefault _export;
+ if (!load_file_and_depsgraph(all_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+ auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+ EXPECT_EQ(objmeshes.size(), 19);
+ EXPECT_EQ(objcurves.size(), 0);
+}
+
+TEST_F(obj_exporter_test, filter_objects_curves_as_nurbs)
+{
+ OBJExportParamsDefault _export;
+ if (!load_file_and_depsgraph(all_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+ EXPECT_EQ(objmeshes.size(), 18);
+ EXPECT_EQ(objcurves.size(), 2);
+}
+
+TEST_F(obj_exporter_test, filter_objects_selected)
+{
+ OBJExportParamsDefault _export;
+ if (!load_file_and_depsgraph(all_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+ _export.params.export_selected_objects = true;
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+ EXPECT_EQ(objmeshes.size(), 1);
+ EXPECT_EQ(objcurves.size(), 0);
+}
+
+TEST(obj_exporter_utils, append_negative_frame_to_filename)
+{
+ const char path_original[FILE_MAX] = "/my_file.obj";
+ const char path_truth[FILE_MAX] = "/my_file-123.obj";
+ const int frame = -123;
+ char path_with_frame[FILE_MAX] = {0};
+ const bool ok = append_frame_to_filename(path_original, frame, path_with_frame);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth));
+}
+
+TEST(obj_exporter_utils, append_positive_frame_to_filename)
+{
+ const char path_original[FILE_MAX] = "/my_file.obj";
+ const char path_truth[FILE_MAX] = "/my_file123.obj";
+ const int frame = 123;
+ char path_with_frame[FILE_MAX] = {0};
+ const bool ok = append_frame_to_filename(path_original, frame, path_with_frame);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth));
+}
+
+TEST_F(obj_exporter_test, curve_nurbs_points)
+{
+ if (!load_file_and_depsgraph(all_curve_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+
+ OBJExportParamsDefault _export;
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes_unused, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+
+ for (auto &objcurve : objcurves) {
+ if (all_nurbs_truth.count(objcurve->get_curve_name()) != 1) {
+ ADD_FAILURE();
+ return;
+ }
+ const NurbsObject *const nurbs_truth = all_nurbs_truth.at(objcurve->get_curve_name()).get();
+ EXPECT_EQ(objcurve->total_splines(), nurbs_truth->total_splines());
+ for (int spline_index : IndexRange(objcurve->total_splines())) {
+ EXPECT_EQ(objcurve->total_spline_vertices(spline_index),
+ nurbs_truth->total_spline_vertices(spline_index));
+ EXPECT_EQ(objcurve->get_nurbs_degree(spline_index),
+ nurbs_truth->get_nurbs_degree(spline_index));
+ EXPECT_EQ(objcurve->total_spline_control_points(spline_index),
+ nurbs_truth->total_spline_control_points(spline_index));
+ }
+ }
+}
+
+TEST_F(obj_exporter_test, curve_coordinates)
+{
+ if (!load_file_and_depsgraph(all_curve_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+
+ OBJExportParamsDefault _export;
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes_unused, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+
+ for (auto &objcurve : objcurves) {
+ if (all_nurbs_truth.count(objcurve->get_curve_name()) != 1) {
+ ADD_FAILURE();
+ return;
+ }
+ const NurbsObject *const nurbs_truth = all_nurbs_truth.at(objcurve->get_curve_name()).get();
+ EXPECT_EQ(objcurve->total_splines(), nurbs_truth->total_splines());
+ for (int spline_index : IndexRange(objcurve->total_splines())) {
+ for (int vertex_index : IndexRange(objcurve->total_spline_vertices(spline_index))) {
+ EXPECT_V3_NEAR(objcurve->vertex_coordinates(
+ spline_index, vertex_index, _export.params.scaling_factor),
+ nurbs_truth->vertex_coordinates(spline_index, vertex_index),
+ 0.000001f);
+ }
+ }
+ }
+}
+
+static std::unique_ptr<OBJWriter> init_writer(const OBJExportParams &params,
+ const std::string out_filepath)
+{
+ try {
+ auto writer = std::make_unique<OBJWriter>(out_filepath.c_str(), params);
+ return writer;
+ }
+ catch (const std::system_error &ex) {
+ std::cerr << ex.code().category().name() << ": " << ex.what() << ": " << ex.code().message()
+ << std::endl;
+ return nullptr;
+ }
+}
+
+/* The following is relative to BKE_tempdir_base.
+ * Use Latin Capital Letter A with Ogonek, Cyrillic Capital Letter Zhe
+ * at the end, to test I/O on non-English file names. */
+const char *const temp_file_path = "output\xc4\x84\xd0\x96.OBJ";
+
+static std::string read_temp_file_in_string(const std::string &file_path)
+{
+ std::string res;
+ size_t buffer_len;
+ void *buffer = BLI_file_read_text_as_mem(file_path.c_str(), 0, &buffer_len);
+ if (buffer != NULL) {
+ res.assign((const char *)buffer, buffer_len);
+ MEM_freeN(buffer);
+ }
+ return res;
+}
+
+TEST(obj_exporter_writer, header)
+{
+ /* Because testing doesn't fully initialize Blender, we need the following. */
+ BKE_tempdir_init(nullptr);
+ std::string out_file_path = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
+ {
+ OBJExportParamsDefault _export;
+ std::unique_ptr<OBJWriter> writer = init_writer(_export.params, out_file_path);
+ if (!writer) {
+ ADD_FAILURE();
+ return;
+ }
+ writer->write_header();
+ }
+ const std::string result = read_temp_file_in_string(out_file_path);
+ using namespace std::string_literals;
+ ASSERT_EQ(result, "# Blender "s + BKE_blender_version_string() + "\n" + "# www.blender.org\n");
+ BLI_delete(out_file_path.c_str(), false, false);
+}
+
+TEST(obj_exporter_writer, mtllib)
+{
+ std::string out_file_path = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
+ {
+ OBJExportParamsDefault _export;
+ std::unique_ptr<OBJWriter> writer = init_writer(_export.params, out_file_path);
+ if (!writer) {
+ ADD_FAILURE();
+ return;
+ }
+ writer->write_mtllib_name("/Users/blah.mtl");
+ writer->write_mtllib_name("\\C:\\blah.mtl");
+ }
+ const std::string result = read_temp_file_in_string(out_file_path);
+ ASSERT_EQ(result, "mtllib blah.mtl\nmtllib blah.mtl\n");
+ BLI_delete(out_file_path.c_str(), false, false);
+}
+
+/* Return true if string #a and string #b are equal after their first newline. */
+static bool strings_equal_after_first_lines(const std::string &a, const std::string &b)
+{
+ /* If `dbg_level` is true then a failing test will print context around the first mismatch. */
+ const bool dbg_level = false;
+ const size_t a_len = a.size();
+ const size_t b_len = b.size();
+ const size_t a_next = a.find_first_of('\n');
+ const size_t b_next = b.find_first_of('\n');
+ if (a_next == std::string::npos || b_next == std::string::npos) {
+ if (dbg_level) {
+ std::cout << "Couldn't find newline in one of args\n";
+ }
+ return false;
+ }
+ if (dbg_level) {
+ if (a.compare(a_next, a_len - a_next, b, b_next, b_len - b_next) != 0) {
+ for (int i = 0; i < a_len - a_next && i < b_len - b_next; ++i) {
+ if (a[a_next + i] != b[b_next + i]) {
+ std::cout << "Difference found at pos " << a_next + i << " of a\n";
+ std::cout << "a: " << a.substr(a_next + i, 100) << " ...\n";
+ std::cout << "b: " << b.substr(b_next + i, 100) << " ... \n";
+ return false;
+ }
+ }
+ }
+ else {
+ return true;
+ }
+ }
+ return a.compare(a_next, a_len - a_next, b, b_next, b_len - b_next) == 0;
+}
+
+/* From here on, tests are whole file tests, testing for golden output. */
+class obj_exporter_regression_test : public obj_exporter_test {
+ public:
+ /**
+ * Export the given blend file with the given parameters and
+ * test to see if it matches a golden file (ignoring any difference in Blender version number).
+ * \param blendfile: input, relative to "tests" directory.
+ * \param golden_obj: expected output, relative to "tests" directory.
+ * \param params: the parameters to be used for export.
+ */
+ void compare_obj_export_to_golden(const std::string &blendfile,
+ const std::string &golden_obj,
+ const std::string &golden_mtl,
+ OBJExportParams &params)
+ {
+ if (!load_file_and_depsgraph(blendfile)) {
+ return;
+ }
+ /* Because testing doesn't fully initialize Blender, we need the following. */
+ BKE_tempdir_init(nullptr);
+ std::string tempdir = std::string(BKE_tempdir_base());
+ std::string out_file_path = tempdir + BLI_path_basename(golden_obj.c_str());
+ strncpy(params.filepath, out_file_path.c_str(), FILE_MAX - 1);
+ params.blen_filepath = blendfile.c_str();
+ export_frame(depsgraph, params, out_file_path.c_str());
+ std::string output_str = read_temp_file_in_string(out_file_path);
+
+ std::string golden_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_obj;
+ std::string golden_str = read_temp_file_in_string(golden_file_path);
+ bool are_equal = strings_equal_after_first_lines(output_str, golden_str);
+ if (save_failing_test_output && !are_equal) {
+ printf("failing test output in %s\n", out_file_path.c_str());
+ }
+ ASSERT_TRUE(are_equal);
+ if (!save_failing_test_output || are_equal) {
+ BLI_delete(out_file_path.c_str(), false, false);
+ }
+ if (!golden_mtl.empty()) {
+ std::string out_mtl_file_path = tempdir + BLI_path_basename(golden_mtl.c_str());
+ std::string output_mtl_str = read_temp_file_in_string(out_mtl_file_path);
+ std::string golden_mtl_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_mtl;
+ std::string golden_mtl_str = read_temp_file_in_string(golden_mtl_file_path);
+ ASSERT_TRUE(strings_equal_after_first_lines(output_mtl_str, golden_mtl_str));
+ BLI_delete(out_mtl_file_path.c_str(), false, false);
+ }
+ }
+};
+
+TEST_F(obj_exporter_regression_test, all_tris)
+{
+ OBJExportParamsDefault _export;
+ compare_obj_export_to_golden("io_tests/blend_geometry/all_tris.blend",
+ "io_tests/obj/all_tris.obj",
+ "io_tests/obj/all_tris.mtl",
+ _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, all_quads)
+{
+ OBJExportParamsDefault _export;
+ _export.params.scaling_factor = 2.0f;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/all_quads.blend", "io_tests/obj/all_quads.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, fgons)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/fgons.blend", "io_tests/obj/fgons.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, edges)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/edges.blend", "io_tests/obj/edges.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, vertices)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/vertices.blend", "io_tests/obj/vertices.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, nurbs_as_nurbs)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_curves_as_nurbs = true;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/nurbs.blend", "io_tests/obj/nurbs.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, nurbs_as_mesh)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_curves_as_nurbs = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/nurbs.blend", "io_tests/obj/nurbs_mesh.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, cube_all_data_triangulated)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_triangulated_mesh = true;
+ compare_obj_export_to_golden("io_tests/blend_geometry/cube_all_data.blend",
+ "io_tests/obj/cube_all_data_triangulated.obj",
+ "",
+ _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, suzanne_all_data)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_smooth_groups = true;
+ compare_obj_export_to_golden("io_tests/blend_geometry/suzanne_all_data.blend",
+ "io_tests/obj/suzanne_all_data.obj",
+ "",
+ _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, all_objects)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_smooth_groups = true;
+ compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend",
+ "io_tests/obj/all_objects.obj",
+ "io_tests/obj/all_objects.mtl",
+ _export.params);
+}
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
new file mode 100644
index 00000000000..c101081ca54
--- /dev/null
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
@@ -0,0 +1,149 @@
+/* Apache License, Version 2.0 */
+
+/**
+ * This file contains default values for several items like
+ * vertex coordinates, export parameters, MTL values etc.
+ */
+
+#pragma once
+
+#include <array>
+#include <gtest/gtest.h>
+#include <string>
+#include <vector>
+
+#include "IO_wavefront_obj.h"
+
+namespace blender::io::obj {
+
+using array_float_3 = std::array<float, 3>;
+
+/**
+ * This matches #OBJCurve's member functions, except that all the numbers and names are known
+ * constants. Used to store expected values of NURBS curves objects.
+ */
+class NurbsObject {
+ private:
+ std::string nurbs_name_;
+ /* The indices in these vectors are spline indices. */
+ std::vector<std::vector<array_float_3>> coordinates_;
+ std::vector<int> degrees_;
+ std::vector<int> control_points_;
+
+ public:
+ NurbsObject(const std::string nurbs_name,
+ const std::vector<std::vector<array_float_3>> coordinates,
+ const std::vector<int> degrees,
+ const std::vector<int> control_points)
+ : nurbs_name_(nurbs_name),
+ coordinates_(coordinates),
+ degrees_(degrees),
+ control_points_(control_points)
+ {
+ }
+
+ int total_splines() const
+ {
+ return coordinates_.size();
+ }
+
+ int total_spline_vertices(const int spline_index) const
+ {
+ if (spline_index >= coordinates_.size()) {
+ ADD_FAILURE();
+ return 0;
+ }
+ return coordinates_[spline_index].size();
+ }
+
+ const float *vertex_coordinates(const int spline_index, const int vertex_index) const
+ {
+ return coordinates_[spline_index][vertex_index].data();
+ }
+
+ int get_nurbs_degree(const int spline_index) const
+ {
+ return degrees_[spline_index];
+ }
+
+ int total_spline_control_points(const int spline_index) const
+ {
+ return control_points_[spline_index];
+ }
+};
+
+struct OBJExportParamsDefault {
+ OBJExportParams params;
+ OBJExportParamsDefault()
+ {
+ params.filepath[0] = '\0';
+ params.blen_filepath = "";
+ params.export_animation = false;
+ params.start_frame = 0;
+ params.end_frame = 1;
+
+ params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD;
+ params.up_axis = OBJ_AXIS_Y_UP;
+ params.scaling_factor = 1.f;
+
+ params.export_eval_mode = DAG_EVAL_VIEWPORT;
+ params.export_selected_objects = false;
+ params.export_uv = true;
+ params.export_normals = true;
+ params.export_materials = true;
+ params.export_triangulated_mesh = false;
+ params.export_curves_as_nurbs = false;
+
+ params.export_object_groups = false;
+ params.export_material_groups = false;
+ params.export_vertex_groups = false;
+ params.export_smooth_groups = true;
+ params.smooth_groups_bitflags = false;
+ }
+};
+
+const std::vector<std::vector<array_float_3>> coordinates_NurbsCurve{
+ {{6.94742, 0.000000, 0.000000},
+ {7.44742, 0.000000, -1.000000},
+ {9.44742, 0.000000, -1.000000},
+ {9.94742, 0.000000, 0.000000}}};
+const std::vector<std::vector<array_float_3>> coordinates_NurbsCircle{
+ {{11.463165, 0.000000, 1.000000},
+ {10.463165, 0.000000, 1.000000},
+ {10.463165, 0.000000, 0.000000},
+ {10.463165, 0.000000, -1.000000},
+ {11.463165, 0.000000, -1.000000},
+ {12.463165, 0.000000, -1.000000},
+ {12.463165, 0.000000, 0.000000},
+ {12.463165, 0.000000, 1.000000}}};
+const std::vector<std::vector<array_float_3>> coordinates_NurbsPathCurve{
+ {{13.690557, 0.000000, 0.000000},
+ {14.690557, 0.000000, 0.000000},
+ {15.690557, 0.000000, 0.000000},
+ {16.690557, 0.000000, 0.000000},
+ {17.690557, 0.000000, 0.000000}},
+ {{14.192808, 0.000000, 0.000000},
+ {14.692808, 0.000000, -1.000000},
+ {16.692808, 0.000000, -1.000000},
+ {17.192808, 0.000000, 0.000000}}};
+
+const std::map<std::string, std::unique_ptr<NurbsObject>> all_nurbs_truth = []() {
+ std::map<std::string, std::unique_ptr<NurbsObject>> all_nurbs;
+ all_nurbs.emplace(
+ "NurbsCurve",
+ /* Name, coordinates, degrees of splines, control points of splines. */
+ std::make_unique<NurbsObject>(
+ "NurbsCurve", coordinates_NurbsCurve, std::vector<int>{3}, std::vector<int>{4}));
+ all_nurbs.emplace(
+ "NurbsCircle",
+ std::make_unique<NurbsObject>(
+ "NurbsCircle", coordinates_NurbsCircle, std::vector<int>{3}, std::vector<int>{11}));
+ /* This is actually an Object containing a NurbsPath and a NurbsCurve spline. */
+ all_nurbs.emplace("NurbsPathCurve",
+ std::make_unique<NurbsObject>("NurbsPathCurve",
+ coordinates_NurbsPathCurve,
+ std::vector<int>{3, 3},
+ std::vector<int>{5, 4}));
+ return all_nurbs;
+}();
+} // namespace blender::io::obj
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 6a478f9abb5..060b55ffe5c 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -147,17 +147,18 @@ typedef struct IDProperty {
#define DEFAULT_ALLOC_FOR_NULL_STRINGS 64
/*->type*/
-enum {
+typedef enum eIDPropertyType {
IDP_STRING = 0,
IDP_INT = 1,
IDP_FLOAT = 2,
+ /** Array containing int, floats, doubles or groups. */
IDP_ARRAY = 5,
IDP_GROUP = 6,
IDP_ID = 7,
IDP_DOUBLE = 8,
IDP_IDPARRAY = 9,
- IDP_NUMTYPES = 10,
-};
+} eIDPropertyType;
+#define IDP_NUMTYPES 10
/** Used by some IDP utils, keep values in sync with type enum above. */
enum {
@@ -315,8 +316,22 @@ typedef struct IDOverrideLibrary {
struct ID *storage;
IDOverrideLibraryRuntime *runtime;
+
+ void *_pad_0;
+
+ unsigned int flag;
+ char _pad_1[4];
} IDOverrideLibrary;
+/* IDOverrideLibrary->flag */
+enum {
+ /**
+ * The override data-block should not be considered as part of an override hierarchy (generally
+ * because it was created as an single override, outside of any hierarchy consideration).
+ */
+ IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY = 1 << 0,
+};
+
/* watch it: Sequence has identical beginning. */
/**
* ID is the first thing included in all serializable types. It
@@ -431,12 +446,21 @@ typedef struct Library {
struct PackedFile *packedfile;
+ ushort tag;
+ char _pad_0[6];
+
/* Temp data needed by read/write code, and liboverride recursive resync. */
int temp_index;
/** See BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION, needed for do_versions. */
short versionfile, subversionfile;
} Library;
+/* Library.tag */
+enum eLibrary_Tag {
+ /* Automatic recursive resync was needed when linking/loading data from that library. */
+ LIBRARY_TAG_RESYNC_REQUIRED = 1 << 0,
+};
+
/**
* A weak library/ID reference for local data that has been appended, to allow re-using that local
* data instead of creating a new copy of it in future appends.
@@ -802,6 +826,9 @@ typedef enum IDRecalcFlag {
*/
ID_RECALC_TAG_FOR_UNDO = (1 << 24),
+ /* The node tree has changed in a way that affects its output nodes. */
+ ID_RECALC_NTREE_OUTPUT = (1 << 25),
+
/***************************************************************************
* Pseudonyms, to have more semantic meaning in the actual code without
* using too much low-level and implementation specific tags. */
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 8e7551e1703..82b20483902 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -468,7 +468,7 @@ typedef enum eRotationModes {
typedef struct bPose {
/** List of pose channels, PoseBones in RNA. */
ListBase chanbase;
- /** Ghash for quicker string lookups. */
+ /** Use a hash-table for quicker string lookups. */
struct GHash *chanhash;
/* Flat array of pose channels. It references pointers from
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 5dbed6b4d24..bd9f9d8ec3d 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -348,7 +348,7 @@ typedef enum eDriverTarget_Flag {
/** idtype can only be 'Object' */
DTAR_FLAG_ID_OB_ONLY = (1 << 1),
- /* "localspace" flags */
+ /* "local-space" flags. */
/** base flag - basically "pre parent+constraints" */
DTAR_FLAG_LOCALSPACE = (1 << 2),
/** include constraints transformed to space including parents */
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 3b65378f9eb..566ffd19669 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -124,11 +124,11 @@ typedef struct bArmature {
ListBase bonebase;
- /** Ghash for quicker lookups of bones by name. */
+ /** Use a hash-table for quicker lookups of bones by name. */
struct GHash *bonehash;
void *_pad1;
- /** Editbone listbase, we use pointer so we can check state. */
+ /** #EditBone list (use an allocated pointer so the state can be checked). */
ListBase *edbo;
/* active bones should work like active object where possible
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index 72b2db89cef..2f41389f2c6 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -522,7 +522,7 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_SLIDE_RELAX, \
SCULPT_TOOL_MASK) == 0)
-/* ImagePaintSettings.tool */
+/** #ImagePaintSettings.tool */
typedef enum eBrushImagePaintTool {
PAINT_TOOL_DRAW = 0,
PAINT_TOOL_SOFTEN = 1,
@@ -532,6 +532,9 @@ typedef enum eBrushImagePaintTool {
PAINT_TOOL_MASK = 5,
} eBrushImagePaintTool;
+/* The enums here should be kept in sync with the weight paint tool.
+ * This is because #smooth_brush_toggle_on and #smooth_brush_toggle_off
+ * assumes that the blur brush has the same enum value. */
typedef enum eBrushVertexPaintTool {
VPAINT_TOOL_DRAW = 0,
VPAINT_TOOL_BLUR = 1,
@@ -539,6 +542,7 @@ typedef enum eBrushVertexPaintTool {
VPAINT_TOOL_SMEAR = 3,
} eBrushVertexPaintTool;
+/* See #eBrushVertexPaintTool when changing this definition. */
typedef enum eBrushWeightPaintTool {
WPAINT_TOOL_DRAW = 0,
WPAINT_TOOL_BLUR = 1,
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 634ebdff253..4976168a890 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -123,7 +123,7 @@ typedef struct BrushGpencilSettings {
int sculpt_mode_flag;
/** Preset type (used to reset brushes - internal). */
short preset_type;
- /** Brush preselected mode (Active/Material/Vertexcolor). */
+ /** Brush preselected mode (Active/Material/Vertex-color). */
short brush_draw_mode;
/** Randomness for Hue. */
diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h
index 0f4c53a6e7e..65e1dd6c096 100644
--- a/source/blender/makesdna/DNA_cachefile_types.h
+++ b/source/blender/makesdna/DNA_cachefile_types.h
@@ -59,6 +59,18 @@ typedef struct CacheObjectPath {
char path[4096];
} CacheObjectPath;
+/* CacheFileLayer::flag */
+enum { CACHEFILE_LAYER_HIDDEN = (1 << 0) };
+
+typedef struct CacheFileLayer {
+ struct CacheFileLayer *next, *prev;
+
+ /** 1024 = FILE_MAX. */
+ char filepath[1024];
+ int flag;
+ int _pad;
+} CacheFileLayer;
+
/* CacheFile::velocity_unit
* Determines what temporal unit is used to interpret velocity vectors for motion blur effects. */
enum {
@@ -73,6 +85,8 @@ typedef struct CacheFile {
/** Paths of the objects inside of the archive referenced by this CacheFile. */
ListBase object_paths;
+ ListBase layers;
+
/** 1024 = FILE_MAX. */
char filepath[1024];
@@ -109,7 +123,10 @@ typedef struct CacheFile {
/** Size in megabytes for the prefetch cache used by the Cycles Procedural. */
int prefetch_cache_size;
- char _pad2[7];
+ /** Index of the currently selected layer in the UI, starts at 1. */
+ int active_layer;
+
+ char _pad2[3];
char velocity_unit;
/* Name of the velocity property in the archive. */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 36bdd4915ff..629a5e88de7 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -134,17 +134,21 @@ typedef enum CustomDataType {
CD_CLOTH_ORCO = 23,
/* CD_RECAST = 24, */ /* UNUSED */
- /* BMESH ONLY START */
CD_MPOLY = 25,
CD_MLOOP = 26,
CD_SHAPE_KEYINDEX = 27,
CD_SHAPEKEY = 28,
CD_BWEIGHT = 29,
+ /**
+ * Usage of #CD_CREASE depends on where on the Mesh the layer is added:
+ * - For vertex creasing, this is persistent data across all modes and is stored in the file.
+ * - For edge creasing, it is runtime data which is only used in edit-mode before being copied
+ * to #MEdge when exiting edit-mode.
+ */
CD_CREASE = 30,
CD_ORIGSPACE_MLOOP = 31,
CD_PREVIEW_MLOOPCOL = 32,
CD_BM_ELEM_PYPTR = 33,
- /* BMESH ONLY END */
CD_PAINT_MASK = 34,
CD_GRID_PAINT_MASK = 35,
@@ -164,7 +168,6 @@ typedef enum CustomDataType {
CD_PROP_COLOR = 47,
CD_PROP_FLOAT3 = 48,
CD_PROP_FLOAT2 = 49,
-
CD_PROP_BOOL = 50,
CD_HAIRLENGTH = 51,
@@ -197,7 +200,6 @@ typedef enum CustomDataType {
#define CD_MASK_CLOTH_ORCO (1 << CD_CLOTH_ORCO)
// #define CD_MASK_RECAST (1 << CD_RECAST) /* DEPRECATED */
-/* BMESH ONLY START */
#define CD_MASK_MPOLY (1 << CD_MPOLY)
#define CD_MASK_MLOOP (1 << CD_MLOOP)
#define CD_MASK_SHAPE_KEYINDEX (1 << CD_SHAPE_KEYINDEX)
@@ -207,7 +209,6 @@ typedef enum CustomDataType {
#define CD_MASK_ORIGSPACE_MLOOP (1LL << CD_ORIGSPACE_MLOOP)
#define CD_MASK_PREVIEW_MLOOPCOL (1LL << CD_PREVIEW_MLOOPCOL)
#define CD_MASK_BM_ELEM_PYPTR (1LL << CD_BM_ELEM_PYPTR)
-/* BMESH ONLY END */
#define CD_MASK_PAINT_MASK (1LL << CD_PAINT_MASK)
#define CD_MASK_GRID_PAINT_MASK (1LL << CD_GRID_PAINT_MASK)
diff --git a/source/blender/makesdna/DNA_defaults.h b/source/blender/makesdna/DNA_defaults.h
index 6e986129143..ef7f573e7a8 100644
--- a/source/blender/makesdna/DNA_defaults.h
+++ b/source/blender/makesdna/DNA_defaults.h
@@ -48,7 +48,9 @@ uint8_t *_DNA_struct_default_alloc_impl(const uint8_t *data_src,
#define DNA_struct_default_alloc(struct_name) \
(struct_name *)_DNA_struct_default_alloc_impl( \
- DNA_default_table[SDNA_TYPE_FROM_STRUCT(struct_name)], sizeof(struct_name), __func__)
+ (const uint8_t *)DNA_default_table[SDNA_TYPE_FROM_STRUCT(struct_name)], \
+ sizeof(struct_name), \
+ __func__)
#ifdef __cplusplus
}
diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h
index 5e0cff9fd83..dd118658003 100644
--- a/source/blender/makesdna/DNA_genfile.h
+++ b/source/blender/makesdna/DNA_genfile.h
@@ -87,7 +87,7 @@ enum eSDNA_StructCompare {
* 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,
+ int data_len,
bool do_endian_swap,
bool data_alloc,
const char **r_error_message);
@@ -163,7 +163,7 @@ bool DNA_struct_elem_find(const struct SDNA *sdna,
/**
* Returns the size in bytes of a primitive type.
*/
-int DNA_elem_type_size(const eSDNA_Type elem_nr);
+int DNA_elem_type_size(eSDNA_Type elem_nr);
/**
* Rename a struct
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index 88eb164c2b4..c51a615bfb6 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -315,7 +315,8 @@
.opacity = 1.0f, \
.flags = LRT_GPENCIL_MATCH_OUTPUT_VGROUP, \
.crease_threshold = DEG2RAD(140.0f), \
- .calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES | LRT_USE_CREASE_ON_SHARP_EDGES, \
+ .calculation_flags = LRT_ALLOW_DUPLI_OBJECTS | LRT_ALLOW_CLIPPING_BOUNDARIES | \
+ LRT_USE_CREASE_ON_SHARP_EDGES | LRT_FILTER_FACE_MARK_KEEP_CONTOUR, \
.angle_splitting_threshold = DEG2RAD(60.0f), \
.chaining_image_threshold = 0.001f, \
.chain_smooth_tolerance = 0.2f,\
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index 0f69a256f56..b361372ff8b 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -989,6 +989,7 @@ typedef enum eLineArtGPencilModifierFlags {
LRT_GPENCIL_IS_BAKED = (1 << 3),
LRT_GPENCIL_USE_CACHE = (1 << 4),
LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA = (1 << 5),
+ LRT_GPENCIL_INVERT_COLLECTION = (1 << 6),
} eLineArtGPencilModifierFlags;
typedef enum eLineartGpencilMaskSwitches {
diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h
index d4440592a00..3e77d566d27 100644
--- a/source/blender/makesdna/DNA_lineart_types.h
+++ b/source/blender/makesdna/DNA_lineart_types.h
@@ -50,7 +50,10 @@ typedef enum eLineartMainFlags {
LRT_USE_CREASE_ON_SMOOTH_SURFACES = (1 << 15),
LRT_USE_CREASE_ON_SHARP_EDGES = (1 << 16),
LRT_USE_CUSTOM_CAMERA = (1 << 17),
+ LRT_FILTER_FACE_MARK_KEEP_CONTOUR = (1 << 18),
+ LRT_USE_BACK_FACE_CULLING = (1 << 19),
LRT_USE_IMAGE_BOUNDARY_TRIMMING = (1 << 20),
+ LRT_CHAIN_PRESERVE_DETAILS = (1 << 22),
} eLineartMainFlags;
typedef enum eLineartEdgeFlag {
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 67cd68afb8a..5d682d963ab 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -293,7 +293,7 @@ typedef struct Material {
/* #define TEXCO_STRESS (1 << 14) */ /* deprecated */
/* #define TEXCO_SPEED (1 << 15) */ /* deprecated */
-/* mapto */
+/** #MTex.mapto */
#define MAP_COL (1 << 0)
#define MAP_ALPHA (1 << 7)
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 77cb553c7c7..bf50100b302 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -74,7 +74,7 @@ struct MLoopTri_Store {
int len_alloc;
};
-/* Runtime data, not saved in files. */
+/** Runtime data, not saved in files. */
typedef struct Mesh_Runtime {
/* Evaluated mesh for objects which do not have effective modifiers.
* This mesh is used as a result of modifier stack evaluation.
@@ -82,6 +82,10 @@ typedef struct Mesh_Runtime {
struct Mesh *mesh_eval;
void *eval_mutex;
+ /* A separate mutex is needed for normal calculation, because sometimes
+ * the normals are needed while #eval_mutex is already locked. */
+ void *normals_mutex;
+
/** Needed to ensure some thread-safety during render data pre-processing. */
void *render_mutex;
@@ -129,6 +133,17 @@ typedef struct Mesh_Runtime {
char wrapper_type_finalize;
/**
+ * Settings for lazily evaluating the subdivision on the CPU if needed. These are
+ * set in the modifier when GPU subdivision can be performed.
+ */
+ char subsurf_apply_render;
+ char subsurf_use_optimal_display;
+ char _pad[2];
+ int subsurf_resolution;
+
+ void *_pad2;
+
+ /**
* Used to mark when derived data needs to be recalculated for a certain layer.
* Currently only normals.
*/
@@ -356,16 +371,17 @@ typedef enum eMeshWrapperType {
ME_WRAPPER_TYPE_MDATA = 0,
/** Use edit-mesh data (#Mesh.edit_mesh, #Mesh_Runtime.edit_data). */
ME_WRAPPER_TYPE_BMESH = 1,
- /* ME_WRAPPER_TYPE_SUBD = 2, */ /* TODO */
+ /** Use subdivision mesh data (#Mesh_Runtime.mesh_eval). */
+ ME_WRAPPER_TYPE_SUBD = 2,
} eMeshWrapperType;
-/* texflag */
+/** #Mesh.texflag */
enum {
ME_AUTOSPACE = 1,
ME_AUTOSPACE_EVALUATED = 2,
};
-/* me->editflag */
+/** #Mesh.editflag */
enum {
ME_EDIT_MIRROR_VERTEX_GROUPS = 1 << 0,
ME_EDIT_MIRROR_Y = 1 << 1, /* unused so far */
@@ -387,7 +403,7 @@ enum {
((_me)->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : \
0)
-/* me->flag */
+/** #Mesh.flag */
enum {
ME_FLAG_UNUSED_0 = 1 << 0, /* cleared */
ME_FLAG_UNUSED_1 = 1 << 1, /* cleared */
@@ -407,26 +423,27 @@ enum {
ME_REMESH_REPROJECT_SCULPT_FACE_SETS = 1 << 15,
};
-/* me->cd_flag */
+/** #Mesh.cd_flag */
enum {
ME_CDFLAG_VERT_BWEIGHT = 1 << 0,
ME_CDFLAG_EDGE_BWEIGHT = 1 << 1,
ME_CDFLAG_EDGE_CREASE = 1 << 2,
+ ME_CDFLAG_VERT_CREASE = 1 << 3,
};
-/* me->remesh_mode */
+/** #Mesh.remesh_mode */
enum {
REMESH_VOXEL = 0,
REMESH_QUAD = 1,
};
-/* Subsurf Type */
+/** #SubsurfModifierData.subdivType */
enum {
ME_CC_SUBSURF = 0,
ME_SIMPLE_SUBSURF = 1,
};
-/* me->symmetry */
+/** #Mesh.symmetry */
typedef enum eMeshSymmetryType {
ME_SYMMETRY_X = 1 << 0,
ME_SYMMETRY_Y = 1 << 1,
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index d32470c0dcc..22c523901c0 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -41,12 +41,8 @@ extern "C" {
*/
typedef struct MVert {
float co[3];
- /**
- * Cache the normal, can always be recalculated from surrounding faces.
- * See #CD_CUSTOMLOOPNORMAL for custom normals.
- */
- short no[3];
char flag, bweight;
+ char _pad[2];
} MVert;
/** #MVert.flag */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index f7a468264c3..1d0796bda8b 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -121,28 +121,28 @@ typedef struct ModifierData {
int type, mode;
char _pad0[4];
short flag;
- /* An "expand" bit for each of the modifier's (sub)panels (uiPanelDataExpansion). */
+ /** An "expand" bit for each of the modifier's (sub)panels (#uiPanelDataExpansion). */
short ui_expand_flag;
/** MAX_NAME. */
char name[64];
char *error;
- /* Pointer to a ModifierData in the original domain. */
+ /** Pointer to a #ModifierData in the original domain. */
struct ModifierData *orig_modifier_data;
- /* Runtime field which contains unique identifier of the modifier. */
+ /** Runtime field which contains unique identifier of the modifier. */
SessionUUID session_uuid;
- /* Runtime field which contains runtime data which is specific to a modifier type. */
+ /** Runtime field which contains runtime data which is specific to a modifier type. */
void *runtime;
void *_pad1;
} ModifierData;
typedef enum {
- /* This modifier has been inserted in local override, and hence can be fully edited. */
+ /** This modifier has been inserted in local override, and hence can be fully edited. */
eModifierFlag_OverrideLibrary_Local = (1 << 0),
- /* This modifier does not own its caches, but instead shares them with another modifier. */
+ /** This modifier does not own its caches, but instead shares them with another modifier. */
eModifierFlag_SharedCaches = (1 << 1),
/**
* This modifier is the object's active modifier. Used for context in the node editor.
@@ -151,7 +151,9 @@ typedef enum {
eModifierFlag_Active = (1 << 2),
} ModifierFlag;
-/* not a real modifier */
+/**
+ * \note Not a real modifier.
+ */
typedef struct MappingInfoModifierData {
ModifierData modifier;
@@ -194,6 +196,13 @@ typedef enum {
SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS = 1,
} eSubsurfBoundarySmooth;
+typedef struct SubsurfRuntimeData {
+ /* Cached subdivision surface descriptor, with topology and settings. */
+ struct Subdiv *subdiv;
+ char set_by_draw_code;
+ char _pad[7];
+} SubsurfRuntimeData;
+
typedef struct SubsurfModifierData {
ModifierData modifier;
@@ -219,7 +228,7 @@ typedef struct LatticeModifierData {
void *_pad1;
} LatticeModifierData;
-/* Lattice modifier flags. */
+/** #LatticeModifierData.flag */
enum {
MOD_LATTICE_INVERT_VGROUP = (1 << 0),
};
@@ -237,12 +246,12 @@ typedef struct CurveModifierData {
void *_pad1;
} CurveModifierData;
-/* Curve modifier flags */
+/** #CurveModifierData.flag */
enum {
MOD_CURVE_INVERT_VGROUP = (1 << 0),
};
-/* CurveModifierData->defaxis */
+/** #CurveModifierData.defaxis */
enum {
MOD_CURVE_POSX = 1,
MOD_CURVE_POSY = 2,
@@ -264,7 +273,7 @@ typedef struct BuildModifierData {
int seed;
} BuildModifierData;
-/* Build Modifier -> flag */
+/** #BuildModifierData.flag */
enum {
/** order of vertices is randomized */
MOD_BUILD_FLAG_RANDOMIZE = (1 << 0),
@@ -272,7 +281,7 @@ enum {
MOD_BUILD_FLAG_REVERSE = (1 << 1),
};
-/* Mask Modifier */
+/** Mask Modifier. */
typedef struct MaskModifierData {
ModifierData modifier;
@@ -289,13 +298,13 @@ typedef struct MaskModifierData {
void *_pad1;
} MaskModifierData;
-/* Mask Modifier -> mode */
+/** #MaskModifierData.mode */
enum {
MOD_MASK_MODE_VGROUP = 0,
MOD_MASK_MODE_ARM = 1,
};
-/* Mask Modifier -> flag */
+/** #MaskModifierData.flag */
enum {
MOD_MASK_INV = (1 << 0),
MOD_MASK_SMOOTH = (1 << 1),
@@ -304,63 +313,68 @@ enum {
typedef struct ArrayModifierData {
ModifierData modifier;
- /* the object with which to cap the start of the array. */
+ /** The object with which to cap the start of the array. */
struct Object *start_cap;
- /* the object with which to cap the end of the array. */
+ /** The object with which to cap the end of the array. */
struct Object *end_cap;
- /* the curve object to use for MOD_ARR_FITCURVE. */
+ /** The curve object to use for #MOD_ARR_FITCURVE. */
struct Object *curve_ob;
- /* the object to use for object offset. */
+ /** The object to use for object offset. */
struct Object *offset_ob;
- /* a constant duplicate offset;
- * 1 means the duplicates are 1 unit apart
+ /**
+ * A constant duplicate offset;
+ * 1 means the duplicates are 1 unit apart.
*/
float offset[3];
- /* a scaled factor for duplicate offsets;
- * 1 means the duplicates are 1 object-width apart
+ /**
+ * A scaled factor for duplicate offsets;
+ * 1 means the duplicates are 1 object-width apart.
*/
float scale[3];
- /* the length over which to distribute the duplicates */
+ /** The length over which to distribute the duplicates. */
float length;
- /* the limit below which to merge vertices in adjacent duplicates */
+ /** The limit below which to merge vertices in adjacent duplicates. */
float merge_dist;
- /* determines how duplicate count is calculated; one of:
- * - MOD_ARR_FIXEDCOUNT -> fixed
- * - MOD_ARR_FITLENGTH -> calculated to fit a set length
- * - MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object
+ /**
+ * Determines how duplicate count is calculated; one of:
+ * - #MOD_ARR_FIXEDCOUNT -> fixed.
+ * - #MOD_ARR_FITLENGTH -> calculated to fit a set length.
+ * - #MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object.
*/
int fit_type;
- /* flags specifying how total offset is calculated; binary OR of:
- * - MOD_ARR_OFF_CONST -> total offset += offset
- * - MOD_ARR_OFF_RELATIVE -> total offset += relative * object width
- * - MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix
- * total offset is the sum of the individual enabled offsets
+ /**
+ * Flags specifying how total offset is calculated; binary OR of:
+ * - #MOD_ARR_OFF_CONST -> total offset += offset.
+ * - #MOD_ARR_OFF_RELATIVE -> total offset += relative * object width.
+ * - #MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix.
+ * Total offset is the sum of the individual enabled offsets.
*/
int offset_type;
- /* general flags:
- * MOD_ARR_MERGE -> merge vertices in adjacent duplicates
+ /**
+ * General flags:
+ * #MOD_ARR_MERGE -> merge vertices in adjacent duplicates.
*/
int flags;
- /* the number of duplicates to generate for MOD_ARR_FIXEDCOUNT */
+ /** The number of duplicates to generate for #MOD_ARR_FIXEDCOUNT. */
int count;
float uv_offset[2];
} ArrayModifierData;
-/* ArrayModifierData->fit_type */
+/** #ArrayModifierData.fit_type */
enum {
MOD_ARR_FIXEDCOUNT = 0,
MOD_ARR_FITLENGTH = 1,
MOD_ARR_FITCURVE = 2,
};
-/* ArrayModifierData->offset_type */
+/** #ArrayModifierData.offset_type */
enum {
MOD_ARR_OFF_CONST = (1 << 0),
MOD_ARR_OFF_RELATIVE = (1 << 1),
MOD_ARR_OFF_OBJ = (1 << 2),
};
-/* ArrayModifierData->flags */
+/** #ArrayModifierData.flags */
enum {
MOD_ARR_MERGE = (1 << 0),
MOD_ARR_MERGEFINAL = (1 << 1),
@@ -389,7 +403,7 @@ typedef struct MirrorModifierData {
void *_pad1;
} MirrorModifierData;
-/* MirrorModifierData->flag */
+/** #MirrorModifierData.flag */
enum {
MOD_MIR_CLIPPING = (1 << 0),
MOD_MIR_MIRROR_U = (1 << 1),
@@ -416,7 +430,7 @@ typedef struct EdgeSplitModifierData {
int flags;
} EdgeSplitModifierData;
-/* EdgeSplitModifierData->flags */
+/** #EdgeSplitModifierData.flags */
enum {
MOD_EDGESPLIT_FROMANGLE = (1 << 1),
MOD_EDGESPLIT_FROMFLAG = (1 << 2),
@@ -468,7 +482,7 @@ typedef struct BevelModifierData {
void *_pad2;
} BevelModifierData;
-/* BevelModifierData->flags and BevelModifierData->lim_flags */
+/** #BevelModifierData.flags and BevelModifierData.lim_flags */
enum {
#ifdef DNA_DEPRECATED_ALLOW
MOD_BEVEL_VERT_DEPRECATED = (1 << 1),
@@ -491,7 +505,7 @@ enum {
MOD_BEVEL_HARDEN_NORMALS = (1 << 15),
};
-/* BevelModifierData->val_flags (not used as flags any more) */
+/** #BevelModifierData.val_flags (not used as flags any more) */
enum {
MOD_BEVEL_AMT_OFFSET = 0,
MOD_BEVEL_AMT_WIDTH = 1,
@@ -500,19 +514,19 @@ enum {
MOD_BEVEL_AMT_ABSOLUTE = 4,
};
-/* BevelModifierData->profile_type */
+/** #BevelModifierData.profile_type */
enum {
MOD_BEVEL_PROFILE_SUPERELLIPSE = 0,
MOD_BEVEL_PROFILE_CUSTOM = 1,
};
-/* BevelModifierData->edge_flags */
+/** #BevelModifierData.edge_flags */
enum {
MOD_BEVEL_MARK_SEAM = (1 << 0),
MOD_BEVEL_MARK_SHARP = (1 << 1),
};
-/* BevelModifierData->face_str_mode */
+/** #BevelModifierData.face_str_mode */
enum {
MOD_BEVEL_FACE_STRENGTH_NONE = 0,
MOD_BEVEL_FACE_STRENGTH_NEW = 1,
@@ -520,20 +534,20 @@ enum {
MOD_BEVEL_FACE_STRENGTH_ALL = 3,
};
-/* BevelModifier->miter_inner and ->miter_outer */
+/** #BevelModifier.miter_inner & #BevelModifier.miter_outer */
enum {
MOD_BEVEL_MITER_SHARP = 0,
MOD_BEVEL_MITER_PATCH = 1,
MOD_BEVEL_MITER_ARC = 2,
};
-/* BevelModifier->vmesh_method */
+/** #BevelModifier.vmesh_method */
enum {
MOD_BEVEL_VMESH_ADJ = 0,
MOD_BEVEL_VMESH_CUTOFF = 1,
};
-/* BevelModifier->affect_type */
+/** #BevelModifier.affect_type */
enum {
MOD_BEVEL_AFFECT_VERTICES = 0,
MOD_BEVEL_AFFECT_EDGES = 1,
@@ -553,7 +567,7 @@ typedef struct FluidModifierData {
void *_pad1;
} FluidModifierData;
-/* Fluid modifier flags */
+/** #FluidModifierData.type */
enum {
MOD_FLUID_TYPE_DOMAIN = (1 << 0),
MOD_FLUID_TYPE_FLOW = (1 << 1),
@@ -563,7 +577,8 @@ enum {
typedef struct DisplaceModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -583,12 +598,12 @@ typedef struct DisplaceModifierData {
char _pad[6];
} DisplaceModifierData;
-/* DisplaceModifierData->flag */
+/** #DisplaceModifierData.flag */
enum {
MOD_DISP_INVERT_VGROUP = (1 << 0),
};
-/* DisplaceModifierData->direction */
+/** #DisplaceModifierData.direction */
enum {
MOD_DISP_DIR_X = 0,
MOD_DISP_DIR_Y = 1,
@@ -598,7 +613,7 @@ enum {
MOD_DISP_DIR_CLNOR = 5,
};
-/* DisplaceModifierData->texmapping */
+/** #DisplaceModifierData.texmapping */
enum {
MOD_DISP_MAP_LOCAL = 0,
MOD_DISP_MAP_GLOBAL = 1,
@@ -606,7 +621,7 @@ enum {
MOD_DISP_MAP_UV = 3,
};
-/* DisplaceModifierData->space */
+/** #DisplaceModifierData.space */
enum {
MOD_DISP_SPACE_LOCAL = 0,
MOD_DISP_SPACE_GLOBAL = 1,
@@ -614,9 +629,10 @@ enum {
typedef struct UVProjectModifierData {
ModifierData modifier;
-
- /* the objects which do the projecting */
- /** MOD_UVPROJECT_MAXPROJECTORS. */
+ /**
+ * The objects which do the projecting.
+ * \note 10=MOD_UVPROJECT_MAXPROJECTORS.
+ */
struct Object *projectors[10];
char _pad2[4];
int num_projectors;
@@ -649,7 +665,7 @@ typedef struct DecimateModifierData {
float defgrp_factor;
short flag, mode;
- /* runtime only */
+ /** runtime only. */
int face_count;
} DecimateModifierData;
@@ -678,7 +694,7 @@ typedef struct SmoothModifierData {
} SmoothModifierData;
-/* Smooth modifier flags */
+/** #SmoothModifierData.flag */
enum {
MOD_SMOOTH_INVERT_VGROUP = (1 << 0),
MOD_SMOOTH_X = (1 << 1),
@@ -695,11 +711,13 @@ typedef struct CastModifierData {
float size;
/** MAX_VGROUP_NAME. */
char defgrp_name[64];
- short flag, type;
+ short flag;
+ /** Cast modifier projection type. */
+ short type;
void *_pad1;
} CastModifierData;
-/* Cast modifier flags */
+/** #CastModifierData.flag */
enum {
/* And what bout (1 << 0) flag? ;) */
MOD_CAST_INVERT_VGROUP = (1 << 0),
@@ -710,7 +728,7 @@ enum {
MOD_CAST_SIZE_FROM_RADIUS = (1 << 5),
};
-/* Cast modifier projection types */
+/** #CastModifierData.type */
enum {
MOD_CAST_TYPE_SPHERE = 0,
MOD_CAST_TYPE_CYLINDER = 1,
@@ -720,7 +738,8 @@ enum {
typedef struct WaveModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -728,7 +747,7 @@ typedef struct WaveModifierData {
char uvlayer_name[64];
int uvlayer_tmp;
int texmapping;
- /* end MappingInfoModifierData */
+ /* End MappingInfoModifierData. */
struct Object *objectcenter;
/** MAX_VGROUP_NAME. */
@@ -745,7 +764,7 @@ typedef struct WaveModifierData {
void *_pad2;
} WaveModifierData;
-/* WaveModifierData.flag */
+/** #WaveModifierData.flag */
enum {
MOD_WAVE_INVERT_VGROUP = (1 << 0),
MOD_WAVE_X = (1 << 1),
@@ -775,7 +794,7 @@ enum {
MOD_HOOK_INVERT_VGROUP = (1 << 1),
};
-/* same as WarpModifierFalloff */
+/** \note same as #WarpModifierFalloff */
typedef enum {
eHook_Falloff_None = 0,
eHook_Falloff_Curve = 1,
@@ -832,15 +851,17 @@ typedef struct ClothModifierData {
/** Definition is in DNA_cloth_types.h. */
struct ClothCollSettings *coll_parms;
- /* PointCache can be shared with other instances of ClothModifierData.
- * Inspect (modifier.flag & eModifierFlag_SharedCaches) to find out. */
+ /**
+ * PointCache can be shared with other instances of #ClothModifierData.
+ * Inspect `modifier.flag & eModifierFlag_SharedCaches` to find out.
+ */
/** Definition is in DNA_object_force_types.h. */
struct PointCache *point_cache;
struct ListBase ptcaches;
- /* XXX nasty hack, remove once hair can be separated from cloth modifier data */
+ /** XXX: nasty hack, remove once hair can be separated from cloth modifier data. */
struct ClothHairData *hairdata;
- /* grid geometry values of hair continuum */
+ /** Grid geometry values of hair continuum. */
float hair_grid_min[3];
float hair_grid_max[3];
int hair_grid_res[3];
@@ -907,20 +928,20 @@ typedef struct BooleanModifierData {
char bm_flag;
} BooleanModifierData;
-/* BooleanModifierData->operation */
+/** #BooleanModifierData.operation */
typedef enum {
eBooleanModifierOp_Intersect = 0,
eBooleanModifierOp_Union = 1,
eBooleanModifierOp_Difference = 2,
} BooleanModifierOp;
-/* BooleanModifierData->solver */
+/** #BooleanModifierData.solver */
typedef enum {
eBooleanModifierSolver_Fast = 0,
eBooleanModifierSolver_Exact = 1,
} BooleanModifierSolver;
-/* BooleanModifierData->flag */
+/** #BooleanModifierData.flag */
enum {
eBooleanModifierFlag_Self = (1 << 0),
eBooleanModifierFlag_Object = (1 << 1),
@@ -928,7 +949,7 @@ enum {
eBooleanModifierFlag_HoleTolerant = (1 << 3),
};
-/* bm_flag only used when G_DEBUG. */
+/** #BooleanModifierData.bm_flag (only used when #G_DEBUG is set). */
enum {
eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 0),
eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 1),
@@ -1102,7 +1123,7 @@ typedef enum {
eMultiresModifierFlag_UseSculptBaseMesh = (1 << 4),
} MultiresModifierFlag;
-/* DEPRECATED, only used for versioning. */
+/** DEPRECATED: only used for versioning. */
typedef struct FluidsimModifierData {
ModifierData modifier;
@@ -1111,7 +1132,7 @@ typedef struct FluidsimModifierData {
void *_pad1;
} FluidsimModifierData;
-/* DEPRECATED, only used for versioning. */
+/** DEPRECATED: only used for versioning. */
typedef struct SmokeModifierData {
ModifierData modifier;
@@ -1150,7 +1171,7 @@ typedef struct ShrinkwrapModifierData {
char _pad[2];
} ShrinkwrapModifierData;
-/* Shrinkwrap->shrinkType */
+/** #ShrinkwrapModifierData.shrinkType */
enum {
MOD_SHRINKWRAP_NEAREST_SURFACE = 0,
MOD_SHRINKWRAP_PROJECT = 1,
@@ -1158,7 +1179,7 @@ enum {
MOD_SHRINKWRAP_TARGET_PROJECT = 3,
};
-/* Shrinkwrap->shrinkMode */
+/** #ShrinkwrapModifierData.shrinkMode */
enum {
/** Move vertex to the surface of the target object (keepDist towards original position) */
MOD_SHRINKWRAP_ON_SURFACE = 0,
@@ -1172,7 +1193,7 @@ enum {
MOD_SHRINKWRAP_ABOVE_SURFACE = 4,
};
-/* Shrinkwrap->shrinkOpts */
+/** #ShrinkwrapModifierData.shrinkOpts */
enum {
/** allow shrinkwrap to move the vertex in the positive direction of axis */
MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR = (1 << 0),
@@ -1196,7 +1217,7 @@ enum {
#define MOD_SHRINKWRAP_CULL_TARGET_MASK \
(MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)
-/* Shrinkwrap->projAxis */
+/** #ShrinkwrapModifierData.projAxis */
enum {
/** projection over normal is used if no axis is selected */
MOD_SHRINKWRAP_PROJECT_OVER_NORMAL = 0,
@@ -1228,7 +1249,7 @@ typedef struct SimpleDeformModifierData {
void *_pad1;
} SimpleDeformModifierData;
-/* SimpleDeform->flag */
+/** #SimpleDeformModifierData.flag */
enum {
MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP = (1 << 0),
};
@@ -1434,7 +1455,9 @@ enum {
typedef struct WarpModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -1442,7 +1465,7 @@ typedef struct WarpModifierData {
char uvlayer_name[64];
int uvlayer_tmp;
int texmapping;
- /* end MappingInfoModifierData */
+ /* End #MappingInfoModifierData. */
struct Object *object_from;
struct Object *object_to;
@@ -1462,12 +1485,13 @@ typedef struct WarpModifierData {
void *_pad1;
} WarpModifierData;
-/* WarpModifierData->flag */
+/** #WarpModifierData.flag */
enum {
MOD_WARP_VOLUME_PRESERVE = (1 << 0),
MOD_WARP_INVERT_VGROUP = (1 << 1),
};
+/** \note same as #HookModifierFalloff. */
typedef enum {
eWarp_Falloff_None = 0,
eWarp_Falloff_Curve = 1,
@@ -1508,7 +1532,7 @@ typedef struct WeightVGEditModifierData {
char mask_defgrp_name[64];
/* Texture masking. */
- /** Which channel to use as weightf. */
+ /** Which channel to use as weight/mask. */
int mask_tex_use_channel;
/** The texture. */
struct Tex *mask_texture;
@@ -1526,7 +1550,7 @@ typedef struct WeightVGEditModifierData {
void *_pad1;
} WeightVGEditModifierData;
-/* WeightVGEdit flags. */
+/** #WeightVGEdit.edit_flags */
enum {
MOD_WVG_EDIT_WEIGHTS_NORMALIZE = (1 << 0),
MOD_WVG_INVERT_FALLOFF = (1 << 1),
@@ -1581,7 +1605,7 @@ typedef struct WeightVGMixModifierData {
char _pad1[3];
} WeightVGMixModifierData;
-/* How second vgroup's weights affect first ones. */
+/** #WeightVGMixModifierData.mix_mode (how second vgroup's weights affect first ones). */
enum {
/** Second weights replace weights. */
MOD_WVG_MIX_SET = 1,
@@ -1599,7 +1623,7 @@ enum {
MOD_WVG_MIX_AVG = 7,
};
-/* What vertices to affect. */
+/** #WeightVGMixModifierData.mix_set (what vertices to affect). */
enum {
/** Affect all vertices. */
MOD_WVG_SET_ALL = 1,
@@ -1613,7 +1637,7 @@ enum {
MOD_WVG_SET_AND = 5,
};
-/* WeightVGMix->flag */
+/** #WeightVGMixModifierData.flag */
enum {
MOD_WVG_MIX_INVERT_VGROUP_MASK = (1 << 0),
MOD_WVG_MIX_WEIGHTS_NORMALIZE = (1 << 1),
@@ -1631,8 +1655,9 @@ typedef struct WeightVGProximityModifierData {
/** The custom mapping curve. */
struct CurveMapping *cmap_curve;
- /* Proximity modes. */
+ /** Modes of proximity weighting. */
int proximity_mode;
+ /** Options for proximity weighting. */
int proximity_flags;
/* Target object from which to calculate vertices distances. */
@@ -1662,20 +1687,21 @@ typedef struct WeightVGProximityModifierData {
float min_dist, max_dist;
/* Put here to avoid breaking existing struct... */
- /** Using MOD_WVG_MAPPING_* enums. */
+ /**
+ * Mapping modes (using MOD_WVG_MAPPING_* enums). */
short falloff_type;
/* Padding... */
char _pad0[2];
} WeightVGProximityModifierData;
-/* Modes of proximity weighting. */
+/** #WeightVGProximityModifierData.proximity_mode */
enum {
MOD_WVG_PROXIMITY_OBJECT = 1, /* source vertex to other location */
MOD_WVG_PROXIMITY_GEOMETRY = 2, /* source vertex to other geometry */
};
-/* Flags options for proximity weighting. */
+/** #WeightVGProximityModifierData.proximity_flags */
enum {
/* Use nearest vertices of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */
MOD_WVG_PROXIMITY_GEOM_VERTS = (1 << 0),
@@ -1689,7 +1715,8 @@ enum {
};
/* Defines common to all WeightVG modifiers. */
-/* Mapping modes. */
+
+/** #WeightVGProximityModifierData.falloff_type */
enum {
MOD_WVG_MAPPING_NONE = 0,
MOD_WVG_MAPPING_CURVE = 1,
@@ -1703,7 +1730,7 @@ enum {
MOD_WVG_MAPPING_STEP = 9, /* Median Step. */
};
-/* Tex channel to be used as mask. */
+/** #WeightVGProximityModifierData.mask_tex_use_channel */
enum {
MOD_WVG_MASK_TEX_USE_INT = 1,
MOD_WVG_MASK_TEX_USE_RED = 2,
@@ -1725,13 +1752,13 @@ typedef struct DynamicPaintModifierData {
char _pad[4];
} DynamicPaintModifierData;
-/* Dynamic paint modifier flags */
+/** #DynamicPaintModifierData.type */
enum {
MOD_DYNAMICPAINT_TYPE_CANVAS = (1 << 0),
MOD_DYNAMICPAINT_TYPE_BRUSH = (1 << 1),
};
-/* Remesh modifier */
+/** Remesh modifier. */
typedef enum eRemeshModifierFlags {
MOD_REMESH_FLOOD_FILL = (1 << 0),
MOD_REMESH_SMOOTH_SHADING = (1 << 1),
@@ -1770,7 +1797,7 @@ typedef struct RemeshModifierData {
float adaptivity;
} RemeshModifierData;
-/* Skin modifier */
+/** Skin modifier. */
typedef struct SkinModifierData {
ModifierData modifier;
@@ -1783,19 +1810,19 @@ typedef struct SkinModifierData {
char _pad[2];
} SkinModifierData;
-/* SkinModifierData.symmetry_axes */
+/** #SkinModifierData.symmetry_axes */
enum {
MOD_SKIN_SYMM_X = (1 << 0),
MOD_SKIN_SYMM_Y = (1 << 1),
MOD_SKIN_SYMM_Z = (1 << 2),
};
-/* SkinModifierData.flag */
+/** #SkinModifierData.flag */
enum {
MOD_SKIN_SMOOTH_SHADING = 1,
};
-/* Triangulate modifier */
+/** Triangulate modifier. */
typedef struct TriangulateModifierData {
ModifierData modifier;
@@ -1805,7 +1832,7 @@ typedef struct TriangulateModifierData {
int min_vertices;
} TriangulateModifierData;
-/* TriangulateModifierData.flag */
+/** #TriangulateModifierData.flag */
enum {
#ifdef DNA_DEPRECATED_ALLOW
MOD_TRIANGULATE_BEAUTY = (1 << 0), /* deprecated */
@@ -1813,18 +1840,19 @@ enum {
MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS = 1 << 1,
};
-/* Triangulate methods - NGons */
+/** #TriangulateModifierData.ngon_method triangulate method (N-gons). */
enum {
MOD_TRIANGULATE_NGON_BEAUTY = 0,
MOD_TRIANGULATE_NGON_EARCLIP = 1,
};
-/* Triangulate methods - Quads */
+/** #TriangulateModifierData.quad_method triangulate method (quads). */
enum {
MOD_TRIANGULATE_QUAD_BEAUTY = 0,
MOD_TRIANGULATE_QUAD_FIXED = 1,
MOD_TRIANGULATE_QUAD_ALTERNATE = 2,
MOD_TRIANGULATE_QUAD_SHORTEDGE = 3,
+ MOD_TRIANGULATE_QUAD_LONGEDGE = 4,
};
typedef struct LaplacianSmoothModifierData {
@@ -1837,7 +1865,7 @@ typedef struct LaplacianSmoothModifierData {
short flag, repeat;
} LaplacianSmoothModifierData;
-/* Smooth modifier flags */
+/** #LaplacianSmoothModifierData.flag */
enum {
MOD_LAPLACIANSMOOTH_X = (1 << 1),
MOD_LAPLACIANSMOOTH_Y = (1 << 2),
@@ -1892,7 +1920,7 @@ enum {
MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND = 1,
};
-/* Corrective Smooth modifier flags */
+/** #CorrectiveSmoothModifierData.flag */
enum {
MOD_CORRECTIVESMOOTH_INVERT_VGROUP = (1 << 0),
MOD_CORRECTIVESMOOTH_ONLY_SMOOTH = (1 << 1),
@@ -1926,12 +1954,12 @@ typedef struct UVWarpModifierData {
char uvlayer_name[64];
} UVWarpModifierData;
-/* UVWarp modifier flags */
+/** #UVWarpModifierData.flag */
enum {
MOD_UVWARP_INVERT_VGROUP = 1 << 0,
};
-/* cache modifier */
+/** Mesh cache modifier. */
typedef struct MeshCacheModifierData {
ModifierData modifier;
@@ -1967,7 +1995,7 @@ typedef struct MeshCacheModifierData {
char filepath[1024];
} MeshCacheModifierData;
-/* MeshCache modifier flags. */
+/** #MeshCacheModifierData.flag */
enum {
MOD_MESHCACHE_INVERT_VERTEX_GROUP = 1 << 0,
};
@@ -2012,13 +2040,15 @@ typedef struct LaplacianDeformModifierData {
} LaplacianDeformModifierData;
-/* Laplacian Deform modifier flags */
+/** #LaplacianDeformModifierData.flag */
enum {
MOD_LAPLACIANDEFORM_BIND = 1 << 0,
MOD_LAPLACIANDEFORM_INVERT_VGROUP = 1 << 1,
};
-/* many of these options match 'solidify' */
+/**
+ * \note many of these options match 'solidify'.
+ */
typedef struct WireframeModifierData {
ModifierData modifier;
/** MAX_VGROUP_NAME. */
@@ -2053,13 +2083,13 @@ typedef struct WeldModifierData {
char _pad[2];
} WeldModifierData;
-/* WeldModifierData->flag */
+/** #WeldModifierData.flag */
enum {
MOD_WELD_INVERT_VGROUP = (1 << 0),
MOD_WELD_LOOSE_EDGES = (1 << 1),
};
-/* #WeldModifierData.mode */
+/** #WeldModifierData.mode */
enum {
MOD_WELD_MODE_ALL = 0,
MOD_WELD_MODE_CONNECTED = 1,
@@ -2100,7 +2130,7 @@ typedef struct DataTransferModifierData {
void *_pad2;
} DataTransferModifierData;
-/* DataTransferModifierData.flags */
+/** #DataTransferModifierData.flags */
enum {
MOD_DATATRANSFER_OBSRC_TRANSFORM = 1 << 0,
MOD_DATATRANSFER_MAP_MAXDIST = 1 << 1,
@@ -2113,7 +2143,7 @@ enum {
MOD_DATATRANSFER_USE_POLY = 1u << 31,
};
-/* Set Split Normals modifier */
+/** Set Split Normals modifier. */
typedef struct NormalEditModifierData {
ModifierData modifier;
/** MAX_VGROUP_NAME. */
@@ -2131,20 +2161,20 @@ typedef struct NormalEditModifierData {
void *_pad1;
} NormalEditModifierData;
-/* NormalEditModifierData.mode */
+/** #NormalEditModifierData.mode */
enum {
MOD_NORMALEDIT_MODE_RADIAL = 0,
MOD_NORMALEDIT_MODE_DIRECTIONAL = 1,
};
-/* NormalEditModifierData.flags */
+/** #NormalEditModifierData.flags */
enum {
MOD_NORMALEDIT_INVERT_VGROUP = (1 << 0),
MOD_NORMALEDIT_USE_DIRECTION_PARALLEL = (1 << 1),
MOD_NORMALEDIT_NO_POLYNORS_FIX = (1 << 2),
};
-/* NormalEditModifierData.mix_mode */
+/** #NormalEditModifierData.mix_mode */
enum {
MOD_NORMALEDIT_MIX_COPY = 0,
MOD_NORMALEDIT_MIX_ADD = 1,
@@ -2169,7 +2199,7 @@ typedef struct MeshSeqCacheModifierData {
char reader_object_path[1024];
} MeshSeqCacheModifierData;
-/* MeshSeqCacheModifierData.read_flag */
+/** #MeshSeqCacheModifierData.read_flag */
enum {
MOD_MESHSEQ_READ_VERT = (1 << 0),
MOD_MESHSEQ_READ_POLY = (1 << 1),
@@ -2214,7 +2244,7 @@ typedef struct SurfaceDeformModifierData {
void *_pad1;
} SurfaceDeformModifierData;
-/* Surface Deform modifier flags */
+/** Surface Deform modifier flags. */
enum {
/* This indicates "do bind on next modifier evaluation" as well as "is bound". */
MOD_SDEF_BIND = (1 << 0),
@@ -2223,7 +2253,7 @@ enum {
MOD_SDEF_SPARSE_BIND = (1 << 2),
};
-/* Surface Deform vertex bind modes */
+/** Surface Deform vertex bind modes. */
enum {
MOD_SDEF_MODE_LOOPTRI = 0,
MOD_SDEF_MODE_NGON = 1,
@@ -2243,14 +2273,14 @@ typedef struct WeightedNormalModifierData {
/* Name/id of the generic PROP_INT cdlayer storing face weights. */
#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID "__mod_weightednormals_faceweight"
-/* WeightedNormalModifierData.mode */
+/** #WeightedNormalModifierData.mode */
enum {
MOD_WEIGHTEDNORMAL_MODE_FACE = 0,
MOD_WEIGHTEDNORMAL_MODE_ANGLE = 1,
MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE = 2,
};
-/* WeightedNormalModifierData.flag */
+/** #WeightedNormalModifierData.flag */
enum {
MOD_WEIGHTEDNORMAL_KEEP_SHARP = (1 << 0),
MOD_WEIGHTEDNORMAL_INVERT_VGROUP = (1 << 1),
@@ -2270,8 +2300,10 @@ typedef struct NodesModifierData {
struct bNodeTree *node_group;
struct NodesModifierSettings settings;
- /* Contains logged information from the last evaluation. This can be used to help the user to
- * debug a node tree. */
+ /**
+ * Contains logged information from the last evaluation.
+ * This can be used to help the user to debug a node tree.
+ */
void *runtime_eval_log;
void *_pad1;
} NodesModifierData;
@@ -2304,7 +2336,7 @@ typedef struct MeshToVolumeModifierData {
void *_pad3;
} MeshToVolumeModifierData;
-/* MeshToVolumeModifierData->resolution_mode */
+/** #MeshToVolumeModifierData.resolution_mode */
typedef enum MeshToVolumeModifierResolutionMode {
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT = 0,
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE = 1,
@@ -2322,7 +2354,7 @@ typedef struct VolumeDisplaceModifierData {
float texture_sample_radius;
} VolumeDisplaceModifierData;
-/* VolumeDisplaceModifierData->texture_map_mode */
+/** #VolumeDisplaceModifierData.texture_map_mode */
enum {
MOD_VOLUME_DISPLACE_MAP_LOCAL = 0,
MOD_VOLUME_DISPLACE_MAP_GLOBAL = 1,
diff --git a/source/blender/makesdna/DNA_movieclip_defaults.h b/source/blender/makesdna/DNA_movieclip_defaults.h
index 753147eb072..441c2231009 100644
--- a/source/blender/makesdna/DNA_movieclip_defaults.h
+++ b/source/blender/makesdna/DNA_movieclip_defaults.h
@@ -45,6 +45,34 @@
.frame_offset = 0, \
}
+#define _DNA_DEFAULT_MovieClipUser \
+ { \
+ .framenr = 1, \
+ .render_size = MCLIP_PROXY_RENDER_SIZE_FULL, \
+ .render_flag = 0, \
+ }
+
+#define _DNA_DEFAULT_MovieClipScopes \
+ { \
+ .ok = 0, \
+ .use_track_mask = 0, \
+ .track_preview_height = 120, \
+ .frame_width = 0, \
+ .frame_height = 0, \
+ .undist_marker = _DNA_DEFAULT_MovieTrackingMarker, \
+ .track_pos = {0, 0}, \
+ .track_disabled = 0, \
+ .track_locked = 0, \
+ .scene_framenr = 0, \
+ .slide_scale = {0.0f, 0.0f}, \
+ }
+
+/* initialize as all zeros. */
+#define _DNA_DEFAULT_MovieTrackingMarker \
+ { \
+ .pos = {0.0f, 0.0f}, \
+ }
+
/** \} */
/* clang-format on */
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index 8e01a9e1f1f..08064e6242b 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -160,7 +160,7 @@ typedef struct MovieClipScopes {
float slide_scale[2];
} MovieClipScopes;
-/* MovieClipProxy->build_size_flag */
+/** #MovieClipProxy.build_size_flag */
enum {
MCLIP_PROXY_SIZE_25 = (1 << 0),
MCLIP_PROXY_SIZE_50 = (1 << 1),
@@ -172,13 +172,13 @@ enum {
MCLIP_PROXY_UNDISTORTED_SIZE_100 = (1 << 7),
};
-/* MovieClip->source */
+/** #MovieClip.source */
enum {
MCLIP_SRC_SEQUENCE = 1,
MCLIP_SRC_MOVIE = 2,
};
-/* MovieClip->flag */
+/** #MovieClip.flag */
enum {
MCLIP_USE_PROXY = (1 << 0),
MCLIP_USE_PROXY_CUSTOM_DIR = (1 << 1),
@@ -188,7 +188,7 @@ enum {
MCLIP_TIMECODE_FLAGS = (MCLIP_USE_PROXY | MCLIP_USE_PROXY_CUSTOM_DIR),
};
-/* MovieClip->render_size */
+/** #MovieClip.render_size */
enum {
MCLIP_PROXY_RENDER_SIZE_FULL = 0,
MCLIP_PROXY_RENDER_SIZE_25 = 1,
@@ -197,7 +197,7 @@ enum {
MCLIP_PROXY_RENDER_SIZE_100 = 4,
};
-/* MovieClip->render_flag */
+/** #MovieClip.render_flag */
enum {
MCLIP_PROXY_RENDER_UNDISTORT = 1,
/** Use original, if proxy is not found. */
diff --git a/source/blender/makesdna/DNA_nla_types.h b/source/blender/makesdna/DNA_nla_types.h
index 7808dd68384..82edc0e1816 100644
--- a/source/blender/makesdna/DNA_nla_types.h
+++ b/source/blender/makesdna/DNA_nla_types.h
@@ -33,7 +33,7 @@ struct Ipo;
struct Object;
struct bAction;
-/* simple uniform modifier structure, assumed it can hold all type info */
+/** Simple uniform modifier structure, assumed it can hold all type info. */
typedef struct bActionModifier {
struct bActionModifier *next, *prev;
short type, flag;
@@ -95,7 +95,7 @@ typedef struct bActionStrip {
#define ACTSTRIPMODE_BLEND 0
#define ACTSTRIPMODE_ADD 1
-/* strip->flag */
+/** #bActionStrip.flag */
typedef enum eActStrip_Flag {
ACTSTRIP_SELECT = (1 << 0),
ACTSTRIP_USESTRIDE = (1 << 1),
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index dc5acb9d5b2..2bfd2e71eb7 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -38,6 +38,7 @@ struct ID;
struct Image;
struct ListBase;
struct Material;
+struct PreviewImage;
struct Tex;
struct bGPdata;
struct bNodeInstanceHash;
@@ -46,7 +47,6 @@ struct bNodePreview;
struct bNodeTreeExec;
struct bNodeType;
struct uiBlock;
-struct PreviewImage;
#define NODE_MAXSTR 64
@@ -95,7 +95,7 @@ typedef struct SocketDeclarationHandle SocketDeclarationHandle;
#endif
typedef struct bNodeSocket {
- struct bNodeSocket *next, *prev, *new_sock;
+ struct bNodeSocket *next, *prev;
/** User-defined properties. */
IDProperty *prop;
@@ -106,15 +106,21 @@ typedef struct bNodeSocket {
/** MAX_NAME. */
char name[64];
- /* XXX deprecated, only used for the Image and OutputFile nodes,
- * should be removed at some point.
- */
- /** Custom storage. */
+ /** Only used for the Image and OutputFile nodes, should be removed at some point. */
void *storage;
- short type, flag;
- /** Max. number of links. Read via nodeSocketLinkLimit,
- * because the limit might be defined on the socket type. */
+ /**
+ * The socket's data type. #eNodeSocketDatatype.
+ */
+ short type;
+ /** #eNodeSocketFlag */
+ short flag;
+ /**
+ * Maximum number of links that can connect to the socket. Read via #nodeSocketLinkLimit, because
+ * the limit might be defined on the socket type, in which case this value does not have any
+ * effect. It is necessary to store this in the socket because it is exposed as an RNA property
+ * for custom nodes.
+ */
short limit;
/** Input/output type. */
short in_out;
@@ -123,6 +129,10 @@ typedef struct bNodeSocket {
/** Runtime type identifier. */
char idname[64];
+ /**
+ * The location of the sockets, in the view-space of the node editor.
+ * \note These are runtime data-- only calculated when drawing, and could be removed from DNA.
+ */
float locx, locy;
/** Default input value used for unlinked sockets. */
@@ -159,7 +169,7 @@ typedef struct bNodeSocket {
* restores pointer from matching own_index. */
struct bNodeSocket *groupsock DNA_DEPRECATED;
- /** A link pointer, set in ntreeUpdateTree. */
+ /** A link pointer, set in #BKE_ntree_update_main. */
struct bNodeLink *link;
/* XXX deprecated, socket input values are stored in default_value now.
@@ -172,9 +182,13 @@ typedef struct bNodeSocket {
* data. It has to be updated when the node declaration changes.
*/
const SocketDeclarationHandle *declaration;
+
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag;
+ char _pad[4];
} bNodeSocket;
-/* sock->type */
+/** #bNodeSocket.type & #bNodeSocketType.type */
typedef enum eNodeSocketDatatype {
SOCK_CUSTOM = -1, /* socket has no integer type */
SOCK_FLOAT = 0,
@@ -193,7 +207,7 @@ typedef enum eNodeSocketDatatype {
SOCK_MATERIAL = 13,
} eNodeSocketDatatype;
-/* Socket shape. */
+/** Socket shape. */
typedef enum eNodeSocketDisplayShape {
SOCK_DISPLAY_SHAPE_CIRCLE = 0,
SOCK_DISPLAY_SHAPE_SQUARE = 1,
@@ -203,13 +217,13 @@ typedef enum eNodeSocketDisplayShape {
SOCK_DISPLAY_SHAPE_DIAMOND_DOT = 5,
} eNodeSocketDisplayShape;
-/* Socket side (input/output). */
+/** Socket side (input/output). */
typedef enum eNodeSocketInOut {
SOCK_IN = 1 << 0,
SOCK_OUT = 1 << 1,
} eNodeSocketInOut;
-/* #bNodeSocket.flag, first bit is selection. */
+/** #bNodeSocket.flag, first bit is selection. */
typedef enum eNodeSocketFlag {
/** Hidden is user defined, to hide unused sockets. */
SOCK_HIDDEN = (1 << 1),
@@ -239,9 +253,9 @@ typedef enum eNodeSocketFlag {
SOCK_HIDE_LABEL = (1 << 12),
} eNodeSocketFlag;
-/* TODO: Limit data in bNode to what we want to see saved. */
+/** TODO: Limit data in #bNode to what we want to see saved. */
typedef struct bNode {
- struct bNode *next, *prev, *new_node;
+ struct bNode *next, *prev;
/** User-defined properties. */
IDProperty *prop;
@@ -260,8 +274,9 @@ typedef struct bNode {
/** Used as a boolean for execution. */
uint8_t need_exec;
-
- char _pad[1];
+ char _pad2[5];
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag;
/** Custom user-defined color. */
float color[3];
@@ -302,7 +317,7 @@ typedef struct bNode {
char _pad1[4];
- /** Entire boundbox (world-space). */
+ /** Entire bound-box (world-space). */
rctf totr;
/** Optional preview area. */
rctf prvr;
@@ -362,7 +377,7 @@ typedef struct bNode {
#define NODE_PREVIEW 4
#define NODE_HIDDEN 8
#define NODE_ACTIVE 16
-#define NODE_ACTIVE_ID 32
+// #define NODE_ACTIVE_ID 32 /* deprecated */
/* Used to indicate which group output node is used and which viewer node is active. */
#define NODE_DO_OUTPUT 64
#define __NODE_GROUP_EDIT 128 /* DEPRECATED */
@@ -400,10 +415,6 @@ typedef struct bNode {
#define __NODE_ACTIVE_PREVIEW (1 << 18) /* deprecated */
/* node->update */
-/* XXX NODE_UPDATE is a generic update flag. More fine-grained updates
- * might be used in the future, but currently all work the same way.
- */
-#define NODE_UPDATE 0xFFFF /* generic update flag (includes all others) */
#define NODE_UPDATE_ID 1 /* associated id data block has changed */
#define NODE_UPDATE_OPERATOR 2 /* node update triggered from update operator */
@@ -511,8 +522,12 @@ typedef struct bNodeTree {
*/
int cur_index;
int flag;
- /** Update flags. */
- int update;
+ /**
+ * Keeps track of what changed in the node tree until the next update.
+ * Should not be changed directly, instead use the functions in `BKE_node_tree_update.h`.
+ * #eNodeTreeChangedFlag.
+ */
+ uint32_t changed_flag;
/** Flag to prevent re-entrant update calls. */
short is_updating;
/** Generic temporary flag for recursion check (DFS/BFS). */
@@ -546,7 +561,11 @@ typedef struct bNodeTree {
* in case multiple different editors are used and make context ambiguous.
*/
bNodeInstanceKey active_viewer_key;
- char _pad[4];
+ /**
+ * A hash of the topology of the node tree leading up to the outputs. This is used to determine
+ * of the node tree changed in a way that requires updating geometry nodes or shaders.
+ */
+ uint32_t output_topology_hash;
/** Execution data.
*
@@ -571,7 +590,7 @@ typedef struct bNodeTree {
struct PreviewImage *preview;
} bNodeTree;
-/* ntree->type, index */
+/** #NodeTree.type, index */
#define NTREE_UNDEFINED -2 /* Represents #NodeTreeTypeUndefined type. */
#define NTREE_CUSTOM -1 /* for dynamically registered custom types */
@@ -580,10 +599,10 @@ typedef struct bNodeTree {
#define NTREE_TEXTURE 2
#define NTREE_GEOMETRY 3
-/* ntree->init, flag */
+/** #NodeTree.init, flag */
#define NTREE_TYPE_INIT 1
-/* ntree->flag */
+/** #NodeTree.flag */
#define NTREE_DS_EXPAND (1 << 0) /* for animation editors */
#define NTREE_COM_OPENCL (1 << 1) /* use opencl */
#define NTREE_TWO_PASS (1 << 2) /* two pass */
@@ -594,20 +613,6 @@ typedef struct bNodeTree {
/* tree is localized copy, free when deleting node groups */
/* #define NTREE_IS_LOCALIZED (1 << 5) */
-/* ntree->update */
-typedef enum eNodeTreeUpdate {
- NTREE_UPDATE = 0xFFFF, /* generic update flag (includes all others) */
- NTREE_UPDATE_LINKS = (1 << 0), /* links have been added or removed */
- NTREE_UPDATE_NODES = (1 << 1), /* nodes or sockets have been added or removed */
- NTREE_UPDATE_GROUP_IN = (1 << 4), /* group inputs have changed */
- NTREE_UPDATE_GROUP_OUT = (1 << 5), /* group outputs have changed */
- /* The field interface has changed. So e.g. an output that was always a field before is not
- * anymore. This implies that the field type inferencing has to be done again. */
- NTREE_UPDATE_FIELD_INFERENCING = (1 << 6),
- /* group has changed (generic flag including all other group flags) */
- NTREE_UPDATE_GROUP = (NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_GROUP_OUT),
-} eNodeTreeUpdate;
-
/* tree->execution_mode */
typedef enum eNodeTreeExecutionMode {
NTREE_EXECUTION_MODE_TILED = 0,
@@ -674,7 +679,8 @@ typedef struct bNodeSocketValueMaterial {
struct Material *value;
} bNodeSocketValueMaterial;
-/* Data structs, for node->storage. */
+/* Data structs, for `node->storage`. */
+
enum {
CMP_NODE_MASKTYPE_ADD = 0,
CMP_NODE_MASKTYPE_SUBTRACT = 1,
@@ -713,7 +719,7 @@ typedef struct NodeFrame {
short label_size;
} NodeFrame;
-/* This one has been replaced with ImageUser, keep it for do_versions(). */
+/** \note This one has been replaced with #ImageUser, keep it for do_versions(). */
typedef struct NodeImageAnim {
int frames DNA_DEPRECATED;
int sfra DNA_DEPRECATED;
@@ -767,7 +773,7 @@ typedef struct NodeEllipseMask {
char _pad[4];
} NodeEllipseMask;
-/* Layer info for image node outputs. */
+/** Layer info for image node outputs. */
typedef struct NodeImageLayer {
/* index in the Image->layers->passes lists */
int pass_index DNA_DEPRECATED;
@@ -805,7 +811,7 @@ typedef struct NodeAntiAliasingData {
float corner_rounding;
} NodeAntiAliasingData;
-/* NOTE: Only for do-version code. */
+/** \note Only for do-version code. */
typedef struct NodeHueSat {
float hue, sat, val;
} NodeHueSat;
@@ -817,7 +823,9 @@ typedef struct NodeImageFile {
int sfra, efra;
} NodeImageFile;
-/* XXX first struct fields should match NodeImageFile to ensure forward compatibility */
+/**
+ * XXX: first struct fields should match #NodeImageFile to ensure forward compatibility.
+ */
typedef struct NodeImageMultiFile {
/** 1024 = FILE_MAX. */
char base_path[1024];
@@ -925,6 +933,11 @@ typedef struct NodeColorspill {
float uspillr, uspillg, uspillb;
} NodeColorspill;
+typedef struct NodeConvertColorSpace {
+ char from_color_space[64];
+ char to_color_space[64];
+} NodeConvertColorSpace;
+
typedef struct NodeDilateErode {
char falloff;
} NodeDilateErode;
@@ -1066,7 +1079,7 @@ typedef struct NodeShaderPrincipled {
char _pad[3];
} NodeShaderPrincipled;
-/* TEX_output */
+/** TEX_output. */
typedef struct TexNodeOutput {
char name[64];
} TexNodeOutput;
@@ -1266,6 +1279,13 @@ typedef struct NodeRandomValue {
uint8_t data_type;
} NodeRandomValue;
+typedef struct NodeAccumulateField {
+ /* CustomDataType. */
+ uint8_t data_type;
+ /* AttributeDomain. */
+ uint8_t domain;
+} NodeAccumulateField;
+
typedef struct NodeAttributeRandomize {
/* CustomDataType. */
uint8_t data_type;
@@ -1365,6 +1385,11 @@ typedef struct NodeGeometryPointTranslate {
uint8_t input_type;
} NodeGeometryPointTranslate;
+typedef struct NodeGeometryExtrudeMesh {
+ /* GeometryNodeExtrudeMeshMode */
+ uint8_t mode;
+} NodeGeometryExtrudeMesh;
+
typedef struct NodeGeometryObjectInfo {
/* GeometryNodeTransformSpace. */
uint8_t transform_space;
@@ -1483,6 +1508,11 @@ typedef struct NodeGeometryCurveSelectHandles {
uint8_t mode;
} NodeGeometryCurveSelectHandles;
+typedef struct NodeGeometryCurvePrimitiveArc {
+ /* GeometryNodeCurvePrimitiveArcMode. */
+ uint8_t mode;
+} NodeGeometryCurvePrimitiveArc;
+
typedef struct NodeGeometryCurvePrimitiveLine {
/* GeometryNodeCurvePrimitiveLineMode. */
uint8_t mode;
@@ -1586,7 +1616,8 @@ typedef struct NodeGeometryStringToCurves {
uint8_t align_x;
/* GeometryNodeStringToCurvesAlignYMode */
uint8_t align_y;
- char _pad[1];
+ /* GeometryNodeStringToCurvesPivotMode */
+ uint8_t pivot_mode;
} NodeGeometryStringToCurves;
typedef struct NodeGeometryDeleteGeometry {
@@ -1632,14 +1663,17 @@ typedef struct NodeFunctionCompare {
#define NODE_IES_INTERNAL 0
#define NODE_IES_EXTERNAL 1
-/* frame node flags */
+/* Frame node flags. */
+
#define NODE_FRAME_SHRINK 1 /* keep the bounding box minimal */
#define NODE_FRAME_RESIZEABLE 2 /* test flag, if frame can be resized by user */
-/* proxy node flags */
+/* Proxy node flags. */
+
#define NODE_PROXY_AUTOTYPE 1 /* automatically change output type based on link */
-/* comp channel matte */
+/* Comp channel matte. */
+
#define CMP_NODE_CHANNEL_MATTE_CS_RGB 1
#define CMP_NODE_CHANNEL_MATTE_CS_HSV 2
#define CMP_NODE_CHANNEL_MATTE_CS_YUV 3
@@ -1661,7 +1695,7 @@ typedef struct NodeFunctionCompare {
#define SHD_VECT_TRANSFORM_SPACE_OBJECT 1
#define SHD_VECT_TRANSFORM_SPACE_CAMERA 2
-/* attribute */
+/** #NodeShaderAttribute.type */
enum {
SHD_ATTRIBUTE_GEOMETRY = 0,
SHD_ATTRIBUTE_OBJECT = 1,
@@ -1795,7 +1829,7 @@ enum {
#define SHD_AO_INSIDE 1
#define SHD_AO_LOCAL 2
-/* Mapping node vector types. */
+/** Mapping node vector types. */
enum {
NODE_MAPPING_TYPE_POINT = 0,
NODE_MAPPING_TYPE_TEXTURE = 1,
@@ -1803,7 +1837,7 @@ enum {
NODE_MAPPING_TYPE_NORMAL = 3,
};
-/* Rotation node vector types. */
+/** Rotation node vector types. */
enum {
NODE_VECTOR_ROTATE_TYPE_AXIS = 0,
NODE_VECTOR_ROTATE_TYPE_AXIS_X = 1,
@@ -1815,7 +1849,6 @@ enum {
/* math node clamp */
#define SHD_MATH_CLAMP 1
-/* Math node operations. */
typedef enum NodeMathOperation {
NODE_MATH_ADD = 0,
NODE_MATH_SUBTRACT = 1,
@@ -1859,7 +1892,6 @@ typedef enum NodeMathOperation {
NODE_MATH_SMOOTH_MAX = 39,
} NodeMathOperation;
-/* Vector Math node operations. */
typedef enum NodeVectorMathOperation {
NODE_VECTOR_MATH_ADD = 0,
NODE_VECTOR_MATH_SUBTRACT = 1,
@@ -1893,14 +1925,20 @@ typedef enum NodeVectorMathOperation {
NODE_VECTOR_MATH_MULTIPLY_ADD = 26,
} NodeVectorMathOperation;
-/* Boolean math node operations. */
-enum {
+typedef enum NodeBooleanMathOperation {
NODE_BOOLEAN_MATH_AND = 0,
NODE_BOOLEAN_MATH_OR = 1,
NODE_BOOLEAN_MATH_NOT = 2,
-};
-/* Float compare node operations. */
+ NODE_BOOLEAN_MATH_NAND = 3,
+ NODE_BOOLEAN_MATH_NOR = 4,
+ NODE_BOOLEAN_MATH_XNOR = 5,
+ NODE_BOOLEAN_MATH_XOR = 6,
+
+ NODE_BOOLEAN_MATH_IMPLY = 7,
+ NODE_BOOLEAN_MATH_NIMPLY = 8,
+} NodeBooleanMathOperation;
+
typedef enum NodeCompareMode {
NODE_COMPARE_MODE_ELEMENT = 0,
NODE_COMPARE_MODE_LENGTH = 1,
@@ -1918,10 +1956,8 @@ typedef enum NodeCompareOperation {
NODE_COMPARE_NOT_EQUAL = 5,
NODE_COMPARE_COLOR_BRIGHTER = 6,
NODE_COMPARE_COLOR_DARKER = 7,
-
} NodeCompareOperation;
-/* Float to Int node operations. */
typedef enum FloatToIntRoundingMode {
FN_NODE_FLOAT_TO_INT_ROUND = 0,
FN_NODE_FLOAT_TO_INT_FLOOR = 1,
@@ -1929,13 +1965,13 @@ typedef enum FloatToIntRoundingMode {
FN_NODE_FLOAT_TO_INT_TRUNCATE = 3,
} FloatToIntRoundingMode;
-/* Clamp node types. */
+/** Clamp node types. */
enum {
NODE_CLAMP_MINMAX = 0,
NODE_CLAMP_RANGE = 1,
};
-/* Map range node types. */
+/** Map range node types. */
enum {
NODE_MAP_RANGE_LINEAR = 0,
NODE_MAP_RANGE_STEPPED = 1,
@@ -1947,7 +1983,8 @@ enum {
#define SHD_MIXRGB_USE_ALPHA 1
#define SHD_MIXRGB_CLAMP 2
-/* subsurface */
+/* Subsurface. */
+
enum {
#ifdef DNA_DEPRECATED_ALLOW
SHD_SUBSURFACE_COMPATIBLE = 0, /* Deprecated */
@@ -1978,25 +2015,29 @@ enum {
/* viewer and composite output. */
#define CMP_NODE_OUTPUT_IGNORE_ALPHA 1
-/* Plane track deform node */
+/* Plane track deform node. */
+
enum {
CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR = 1,
};
-/* Stabilization node */
+/* Stabilization node. */
+
enum {
CMP_NODEFLAG_STABILIZE_INVERSE = 1,
};
/* Set Alpha Node. */
-/* `NodeSetAlpha.mode` */
+
+/** #NodeSetAlpha.mode */
typedef enum CMPNodeSetAlphaMode {
CMP_NODE_SETALPHA_MODE_APPLY = 0,
CMP_NODE_SETALPHA_MODE_REPLACE_ALPHA = 1,
} CMPNodeSetAlphaMode;
/* Denoise Node. */
-/* `NodeDenoise.prefilter` */
+
+/** #NodeDenoise.prefilter */
typedef enum CMPNodeDenoisePrefilter {
CMP_NODE_DENOISE_PREFILTER_FAST = 0,
CMP_NODE_DENOISE_PREFILTER_NONE = 1,
@@ -2090,6 +2131,7 @@ typedef enum GeometryNodeTriangulateQuads {
GEO_NODE_TRIANGULATE_QUAD_FIXED = 1,
GEO_NODE_TRIANGULATE_QUAD_ALTERNATE = 2,
GEO_NODE_TRIANGULATE_QUAD_SHORTEDGE = 3,
+ GEO_NODE_TRIANGULATE_QUAD_LONGEDGE = 4,
} GeometryNodeTriangulateQuads;
typedef enum GeometryNodePointInstanceType {
@@ -2121,6 +2163,12 @@ typedef enum GeometryNodeDistributePointsOnFacesMode {
GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON = 1,
} GeometryNodeDistributePointsOnFacesMode;
+typedef enum GeometryNodeExtrudeMeshMode {
+ GEO_NODE_EXTRUDE_MESH_VERTICES = 0,
+ GEO_NODE_EXTRUDE_MESH_EDGES = 1,
+ GEO_NODE_EXTRUDE_MESH_FACES = 2,
+} GeometryNodeExtrudeMeshMode;
+
typedef enum GeometryNodeRotatePointsType {
GEO_NODE_POINT_ROTATE_TYPE_EULER = 0,
GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE = 1,
@@ -2208,6 +2256,11 @@ typedef enum GeometryNodeMeshLineCountMode {
GEO_NODE_MESH_LINE_COUNT_RESOLUTION = 1,
} GeometryNodeMeshLineCountMode;
+typedef enum GeometryNodeCurvePrimitiveArcMode {
+ GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS = 0,
+ GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS = 1,
+} GeometryNodeCurvePrimitiveArcMode;
+
typedef enum GeometryNodeCurvePrimitiveLineMode {
GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS = 0,
GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION = 1
@@ -2292,6 +2345,16 @@ typedef enum GeometryNodeStringToCurvesAlignYMode {
GEO_NODE_STRING_TO_CURVES_ALIGN_Y_BOTTOM = 4,
} GeometryNodeStringToCurvesAlignYMode;
+typedef enum GeometryNodeStringToCurvesPivotMode {
+ GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_MIDPOINT = 0,
+ GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_LEFT = 1,
+ GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_CENTER = 2,
+ GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_RIGHT = 3,
+ GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_LEFT = 4,
+ GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_CENTER = 5,
+ GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_RIGHT = 6,
+} GeometryNodeStringToCurvesPivotMode;
+
typedef enum GeometryNodeDeleteGeometryMode {
GEO_NODE_DELETE_GEOMETRY_MODE_ALL = 0,
GEO_NODE_DELETE_GEOMETRY_MODE_EDGE_FACE = 1,
@@ -2302,6 +2365,11 @@ typedef enum GeometryNodeRealizeInstancesFlag {
GEO_NODE_REALIZE_INSTANCES_LEGACY_BEHAVIOR = (1 << 0),
} GeometryNodeRealizeInstancesFlag;
+typedef enum GeometryNodeScaleElementsMode {
+ GEO_NODE_SCALE_ELEMENTS_UNIFORM = 0,
+ GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS = 1,
+} GeometryNodeScaleElementsMode;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h
index 0aa4a171511..7d0d4c0d460 100644
--- a/source/blender/makesdna/DNA_object_force_types.h
+++ b/source/blender/makesdna/DNA_object_force_types.h
@@ -32,7 +32,7 @@ extern "C" {
struct BodySpring;
-/* pd->forcefield: Effector Fields types */
+/** #PartDeflect.forcefield: Effector Fields types. */
typedef enum ePFieldType {
/** (this is used for general effector weight). */
PFIELD_NULL = 0,
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 57c8ef200ae..602f968634e 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -57,7 +57,7 @@ struct SculptSession;
struct SoftBody;
struct bGPdata;
-/* Vertex Groups - Name Info */
+/** Vertex Groups - Name Info */
typedef struct bDeformGroup {
struct bDeformGroup *next, *prev;
/** MAX_VGROUP_NAME. */
@@ -66,7 +66,7 @@ typedef struct bDeformGroup {
char flag, _pad0[7];
} bDeformGroup;
-/* Face Maps. */
+/** Face Maps. */
typedef struct bFaceMap {
struct bFaceMap *next, *prev;
/** MAX_VGROUP_NAME. */
@@ -107,7 +107,7 @@ typedef struct BoundBox {
char _pad0[4];
} BoundBox;
-/* boundbox flag */
+/** #BoundBox.flag */
enum {
BOUNDBOX_DISABLED = (1 << 0),
BOUNDBOX_DIRTY = (1 << 1),
@@ -115,7 +115,7 @@ enum {
struct CustomData_MeshMasks;
-/* Not saved in file! */
+/** Not saved in file! */
typedef struct Object_Runtime {
/**
* The custom data layer mask that was last used
@@ -126,7 +126,12 @@ typedef struct Object_Runtime {
/** Did last modifier stack generation need mapping support? */
char last_need_mapping;
- char _pad0[3];
+ /** Opaque data reserved for management of objects in collection context.
+ * E.g. used currently to check for potential duplicates of objects in a collection, after
+ * remapping process. */
+ char collection_management;
+
+ char _pad0[2];
/** Only used for drawing the parent/child help-line. */
float parent_display_origin[3];
@@ -147,7 +152,7 @@ typedef struct Object_Runtime {
/** Start time of the mode transfer overlay animation. */
double overlay_mode_transfer_start_time;
- /** Axis aligned boundbox (in localspace). */
+ /** Axis aligned bound-box (in local-space). */
struct BoundBox *bb;
/**
@@ -176,6 +181,12 @@ typedef struct Object_Runtime {
*/
struct Mesh *mesh_deform_eval;
+ /* Evaluated mesh cage in edit mode. */
+ struct Mesh *editmesh_eval_cage;
+
+ /** Cached cage bounding box of `editmesh_eval_cage` for selection. */
+ struct BoundBox *editmesh_bb_cage;
+
/**
* Original grease pencil bGPdata pointer, before object->data was changed to point
* to gpd_eval.
@@ -205,6 +216,12 @@ typedef struct Object_Runtime {
unsigned short local_collections_bits;
short _pad2[3];
+
+ float (*crazyspace_deform_imats)[3][3];
+ float (*crazyspace_deform_cos)[3];
+ int crazyspace_num_verts;
+
+ int _pad3[3];
} Object_Runtime;
typedef struct ObjectLineArt {
@@ -246,7 +263,7 @@ typedef struct Object {
/** String describing subobject info, MAX_ID_NAME-2. */
char parsubstr[64];
struct Object *parent, *track;
- /* if ob->proxy (or proxy_group), this object is proxy for object ob->proxy */
+ /* If `ob->proxy` (or proxy_group), this object is proxy for object `ob->proxy`. */
/* proxy_from is set in target back to the proxy. */
struct Object *proxy, *proxy_group, *proxy_from;
/** Old animation system, deprecated for 2.5. */
@@ -322,8 +339,7 @@ typedef struct Object {
* Inverse matrix of 'obmat' for any other use than rendering!
*
* \note this isn't assured to be valid as with 'obmat',
- * before using this value you should do...
- * invert_m4_m4(ob->imat, ob->obmat);
+ * before using this value you should do: `invert_m4_m4(ob->imat, ob->obmat)`
*/
float imat[4][4];
@@ -436,7 +452,7 @@ typedef struct Object {
Object_Runtime runtime;
} Object;
-/* Warning, this is not used anymore because hooks are now modifiers */
+/** DEPRECATED: this is not used anymore because hooks are now modifiers. */
typedef struct ObHook {
struct ObHook *next, *prev;
@@ -466,7 +482,7 @@ typedef struct ObHook {
/* used many places, should be specialized. */
#define SELECT 1
-/* type */
+/** #Object.type */
enum {
OB_EMPTY = 0,
OB_MESH = 1,
@@ -544,7 +560,7 @@ enum {
case ID_PT: \
case ID_VO
-/* partype: first 4 bits: type */
+/** #Object.partype: first 4 bits: type. */
enum {
PARTYPE = (1 << 4) - 1,
PAROBJECT = 0,
@@ -555,7 +571,7 @@ enum {
};
-/* (short) transflag */
+/** #Object.transflag (short) */
enum {
OB_TRANSFORM_ADJUST_ROOT_PARENT_FOR_VIEW_LOCK = 1 << 0,
OB_TRANSFLAG_UNUSED_1 = 1 << 1, /* cleared */
@@ -577,7 +593,7 @@ enum {
OB_DUPLI = OB_DUPLIVERTS | OB_DUPLICOLLECTION | OB_DUPLIFACES | OB_DUPLIPARTS,
};
-/* (short) trackflag / upflag */
+/** #Object.trackflag / #Object.upflag (short) */
enum {
OB_POSX = 0,
OB_POSY = 1,
@@ -587,7 +603,7 @@ enum {
OB_NEGZ = 5,
};
-/* dtx: flags (short) */
+/** #Object.dtx draw type extra flags (short) */
enum {
OB_DRAWBOUNDOX = 1 << 0,
OB_AXIS = 1 << 1,
@@ -606,7 +622,7 @@ enum {
OB_USE_GPENCIL_LIGHTS = 1 << 10,
};
-/* empty_drawtype: no flags */
+/** #Object.empty_drawtype: no flags */
enum {
OB_ARROWS = 1,
OB_PLAINAXES = 2,
@@ -618,7 +634,10 @@ enum {
OB_EMPTY_IMAGE = 8,
};
-/* gpencil add types */
+/**
+ * Grease-pencil add types.
+ * TODO: doesn't need to be DNA, local to `OBJECT_OT_gpencil_add`.
+ */
enum {
GP_EMPTY = 0,
GP_STROKE = 1,
@@ -628,7 +647,7 @@ enum {
GP_LRT_COLLECTION = 5,
};
-/* boundtype */
+/** #Object.boundtype */
enum {
OB_BOUND_BOX = 0,
OB_BOUND_SPHERE = 1,
@@ -642,7 +661,7 @@ enum {
/* **************** BASE ********************* */
-/* base->flag_legacy */
+/** #Base.flag_legacy */
enum {
BA_WAS_SEL = (1 << 1),
/* NOTE: BA_HAS_RECALC_DATA can be re-used later if freed in readfile.c. */
@@ -671,7 +690,7 @@ enum {
# define OB_FLAG_UNUSED_12 (1 << 12) /* cleared */
#endif
-/* ob->visibility_flag */
+/** #Object.visibility_flag */
enum {
OB_HIDE_VIEWPORT = 1 << 0,
OB_HIDE_SELECT = 1 << 1,
@@ -686,7 +705,7 @@ enum {
OB_SHADOW_CATCHER = 1 << 10
};
-/* ob->shapeflag */
+/** #Object.shapeflag */
enum {
OB_SHAPE_LOCK = 1 << 0,
#ifdef DNA_DEPRECATED_ALLOW
@@ -695,7 +714,7 @@ enum {
OB_SHAPE_EDIT_MODE = 1 << 2,
};
-/* ob->nlaflag */
+/** #Object.nlaflag */
enum {
OB_ADS_UNUSED_1 = 1 << 0, /* cleared */
OB_ADS_UNUSED_2 = 1 << 1, /* cleared */
@@ -711,7 +730,7 @@ enum {
/* OB_ADS_SHOWPARTS = 1 << 14, */ /* UNUSED */
};
-/* ob->protectflag */
+/** #Object.protectflag */
enum {
OB_LOCK_LOCX = 1 << 0,
OB_LOCK_LOCY = 1 << 1,
@@ -729,13 +748,13 @@ enum {
OB_LOCK_ROT4D = 1 << 10,
};
-/* ob->duplicator_visibility_flag */
+/** #Object.duplicator_visibility_flag */
enum {
OB_DUPLI_FLAG_VIEWPORT = 1 << 0,
OB_DUPLI_FLAG_RENDER = 1 << 1,
};
-/* ob->empty_image_depth */
+/** #Object.empty_image_depth */
#define OB_EMPTY_IMAGE_DEPTH_DEFAULT 0
#define OB_EMPTY_IMAGE_DEPTH_FRONT 1
#define OB_EMPTY_IMAGE_DEPTH_BACK 2
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index a51c532dfb3..5add664f624 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -72,7 +72,7 @@ typedef struct ParticleSpring {
unsigned int particle_index[2], delete_flag;
} ParticleSpring;
-/* Child particles are created around or between parent particles */
+/** Child particles are created around or between parent particles. */
typedef struct ChildParticle {
/** Face index on the final derived mesh. */
int num;
@@ -364,8 +364,7 @@ typedef struct ParticleSystem {
int flag, totpart, totunexist, totchild, totcached, totchildcache;
/* NOTE: Recalc is one of ID_RECALC_PSYS_ALL flags.
*
- * TODO(sergey): Use part->id.recalc instead of this duplicated flag
- * somehow. */
+ * TODO(sergey): Use #ParticleSettings.id.recalc instead of this duplicated flag somehow. */
int recalc;
short target_psys, totkeyed, bakespace;
char _pad1[6];
@@ -438,9 +437,11 @@ typedef enum eParticleDrawFlag {
PART_DRAW_HAIR_GRID = (1 << 18),
} eParticleDrawFlag;
-/* part->type
+/**
+ * #ParticleSettings.type
* Hair is always baked static in object/geometry space.
- * Other types (normal particles) are in global space and not static baked. */
+ * Other types (normal particles) are in global space and not static baked.
+ */
enum {
PART_EMITTER = 0,
/* REACTOR type currently unused */
@@ -458,7 +459,7 @@ enum {
PART_FLUID_SPRAYFOAMBUBBLE = 12,
};
-/* Mirroring Mantaflow particle types from particle.h (Mantaflow header). */
+/** Mirroring Mantaflow particle types from particle.h (Mantaflow header). */
enum {
/* PARTICLE_TYPE_NONE = (0 << 0), */ /* UNUSED */
/* PARTICLE_TYPE_NEW = (1 << 0), */ /* UNUSED */
@@ -470,7 +471,7 @@ enum {
/* PARTICLE_TYPE_INVALID = (1 << 30), */ /* UNUSED */
};
-/* part->flag */
+/** #ParticleSettings.flag */
#define PART_REACT_STA_END 1
#define PART_REACT_MULTIPLE 2
@@ -514,26 +515,26 @@ enum {
#define PART_SELF_EFFECT (1 << 22)
-/* part->from */
+/** #ParticleSettings.from */
#define PART_FROM_VERT 0
#define PART_FROM_FACE 1
#define PART_FROM_VOLUME 2
/* #define PART_FROM_PARTICLE 3 deprecated! */
#define PART_FROM_CHILD 4
-/* part->distr */
+/** #ParticleSettings.distr */
#define PART_DISTR_JIT 0
#define PART_DISTR_RAND 1
#define PART_DISTR_GRID 2
-/* part->phystype */
+/** #ParticleSettings.phystype */
#define PART_PHYS_NO 0
#define PART_PHYS_NEWTON 1
#define PART_PHYS_KEYED 2
#define PART_PHYS_BOIDS 3
#define PART_PHYS_FLUID 4
-/* part->kink */
+/** #ParticleSettings.kink */
typedef enum eParticleKink {
PART_KINK_NO = 0,
PART_KINK_CURL = 1,
@@ -543,7 +544,7 @@ typedef enum eParticleKink {
PART_KINK_SPIRAL = 5,
} eParticleKink;
-/* part->child_flag */
+/** #ParticleSettings.child_flag */
typedef enum eParticleChildFlag {
PART_CHILD_USE_CLUMP_NOISE = (1 << 0),
PART_CHILD_USE_CLUMP_CURVE = (1 << 1),
@@ -551,22 +552,22 @@ typedef enum eParticleChildFlag {
PART_CHILD_USE_TWIST_CURVE = (1 << 3),
} eParticleChildFlag;
-/* part->shape_flag */
+/** #ParticleSettings.shape_flag */
typedef enum eParticleShapeFlag {
PART_SHAPE_CLOSE_TIP = (1 << 0),
} eParticleShapeFlag;
-/* part->draw_col */
+/* #ParticleSettings.draw_col */
#define PART_DRAW_COL_NONE 0
#define PART_DRAW_COL_MAT 1
#define PART_DRAW_COL_VEL 2
#define PART_DRAW_COL_ACC 3
-/* part->time_flag */
+/* #ParticleSettings.time_flag */
#define PART_TIME_AUTOSF 1 /* Automatic subframes */
-/* part->draw_as */
-/* part->ren_as */
+/* #ParticleSettings.draw_as */
+/* #ParticleSettings.ren_as */
#define PART_DRAW_NOT 0
#define PART_DRAW_DOT 1
#define PART_DRAW_HALO 1
@@ -580,13 +581,13 @@ typedef enum eParticleShapeFlag {
#define PART_DRAW_BB 9 /* deprecated */
#define PART_DRAW_REND 10
-/* part->integrator */
+/* #ParticleSettings.integrator */
#define PART_INT_EULER 0
#define PART_INT_MIDPOINT 1
#define PART_INT_RK4 2
#define PART_INT_VERLET 3
-/* part->rotmode */
+/* #ParticleSettings.rotmode */
#define PART_ROT_NOR 1
#define PART_ROT_VEL 2
#define PART_ROT_GLOB_X 3
@@ -597,7 +598,7 @@ typedef enum eParticleShapeFlag {
#define PART_ROT_OB_Z 8
#define PART_ROT_NOR_TAN 9
-/* part->avemode */
+/* #ParticleSettings.avemode */
#define PART_AVE_VELOCITY 1
#define PART_AVE_RAND 2
#define PART_AVE_HORIZONTAL 3
@@ -606,12 +607,12 @@ typedef enum eParticleShapeFlag {
#define PART_AVE_GLOBAL_Y 6
#define PART_AVE_GLOBAL_Z 7
-/* part->reactevent */
+/* #ParticleSettings.reactevent */
#define PART_EVENT_DEATH 0
#define PART_EVENT_COLLIDE 1
#define PART_EVENT_NEAR 2
-/* part->childtype */
+/* #ParticleSettings.childtype */
#define PART_CHILD_PARTICLES 1
#define PART_CHILD_FACES 2
@@ -675,7 +676,7 @@ typedef enum eParticleShapeFlag {
#define PTARGET_MODE_FRIEND 1
#define PTARGET_MODE_ENEMY 2
-/* mapto */
+/** #MTex.mapto */
typedef enum eParticleTextureInfluence {
/* init */
PAMAP_TIME = (1 << 0), /* emission time */
diff --git a/source/blender/makesdna/DNA_pointcloud_types.h b/source/blender/makesdna/DNA_pointcloud_types.h
index 26f1db3324b..53fda29a33a 100644
--- a/source/blender/makesdna/DNA_pointcloud_types.h
+++ b/source/blender/makesdna/DNA_pointcloud_types.h
@@ -54,7 +54,7 @@ typedef struct PointCloud {
void *batch_cache;
} PointCloud;
-/* PointCloud.flag */
+/** #PointCloud.flag */
enum {
PT_DS_EXPAND = (1 << 0),
};
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index aa11e74e89d..f653905e169 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -38,7 +38,7 @@ struct EffectorWeights;
/* ******************************** */
/* RigidBody World */
-/* Container for data shared by original and evaluated copies of RigidBodyWorld */
+/** Container for data shared by original and evaluated copies of #RigidBodyWorld. */
typedef struct RigidBodyWorld_Shared {
/* cache */
struct PointCache *pointcache;
@@ -90,7 +90,7 @@ typedef struct RigidBodyWorld {
float time_scale;
} RigidBodyWorld;
-/* Flags for RigidBodyWorld */
+/** RigidBodyWorld.flag */
typedef enum eRigidBodyWorld_Flag {
/* should sim world be skipped when evaluating (user setting) */
RBW_FLAG_MUTED = (1 << 0),
@@ -170,7 +170,7 @@ typedef struct RigidBodyOb {
struct RigidBodyOb_Shared *shared;
} RigidBodyOb;
-/* Participation types for RigidBodyOb */
+/** #RigidBodyOb.type */
typedef enum eRigidBodyOb_Type {
/* active geometry participant in simulation. is directly controlled by sim */
RBO_TYPE_ACTIVE = 0,
@@ -178,7 +178,7 @@ typedef enum eRigidBodyOb_Type {
RBO_TYPE_PASSIVE = 1,
} eRigidBodyOb_Type;
-/* Flags for RigidBodyOb */
+/** #RigidBodyOb.flag */
typedef enum eRigidBodyOb_Flag {
/* rigidbody is kinematic (controlled by the animation system) */
RBO_FLAG_KINEMATIC = (1 << 0),
@@ -198,7 +198,7 @@ typedef enum eRigidBodyOb_Flag {
RBO_FLAG_USE_DEFORM = (1 << 7),
} eRigidBodyOb_Flag;
-/* RigidBody Collision Shape */
+/** Rigid Body Collision Shape. */
typedef enum eRigidBody_Shape {
/** Simple box (i.e. bounding box). */
RB_SHAPE_BOX = 0,
@@ -304,7 +304,7 @@ typedef struct RigidBodyCon {
void *physics_constraint;
} RigidBodyCon;
-/* Participation types for RigidBodyOb */
+/** Participation types for #RigidBodyOb.type */
typedef enum eRigidBodyCon_Type {
/** lets bodies rotate around a specified point */
RBC_TYPE_POINT = 0,
@@ -333,13 +333,13 @@ typedef enum eRigidBodyCon_Type {
RBC_TYPE_MOTOR = 11,
} eRigidBodyCon_Type;
-/* Spring implementation type for RigidBodyOb */
+/** Spring implementation type for RigidBodyOb. */
typedef enum eRigidBodyCon_SpringType {
RBC_SPRING_TYPE1 = 0, /* btGeneric6DofSpringConstraint */
RBC_SPRING_TYPE2 = 1, /* btGeneric6DofSpring2Constraint */
} eRigidBodyCon_SpringType;
-/* Flags for RigidBodyCon */
+/** #RigidBodyCon.flag */
typedef enum eRigidBodyCon_Flag {
/* constraint influences rigid body motion */
RBC_FLAG_ENABLED = (1 << 0),
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
index d2c4f22bc23..7ba054e3133 100644
--- a/source/blender/makesdna/DNA_scene_defaults.h
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -47,6 +47,7 @@
.width = 512, \
.height = 512, \
.margin = 16, \
+ .margin_type = R_BAKE_ADJACENT_FACES, \
.normal_space = R_BAKE_SPACE_TANGENT, \
.normal_swizzle = {R_BAKE_POSX, R_BAKE_POSY, R_BAKE_POSZ}, \
}
@@ -102,7 +103,8 @@
.dither_intensity = 1.0f, \
\
.bake_mode = 0, \
- .bake_filter = 16, \
+ .bake_margin = 16, \
+ .bake_margin_type = R_BAKE_ADJACENT_FACES, \
.bake_flag = R_BAKE_CLEAR, \
.bake_samples = 256, \
.bake_biasdist = 0.001f, \
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index c66ac3a6211..864358e040c 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -195,7 +195,7 @@ typedef struct AudioData {
/* *************************************************************** */
/* Render Layers */
-/* Render Layer */
+/** Render Layer. */
typedef struct SceneRenderLayer {
struct SceneRenderLayer *next, *prev;
@@ -323,7 +323,7 @@ typedef enum eScenePassType {
#define RE_PASSNAME_BLOOM "BloomCol"
#define RE_PASSNAME_VOLUME_LIGHT "VolumeDir"
-/* View - MultiView */
+/** View - MultiView. */
typedef struct SceneRenderView {
struct SceneRenderView *next, *prev;
@@ -563,11 +563,18 @@ typedef struct BakeData {
char target;
char save_mode;
- char _pad[6];
+ char margin_type;
+ char _pad[5];
struct Object *cage_object;
} BakeData;
+/** #BakeData.margin_type (char) */
+typedef enum eBakeMarginType {
+ R_BAKE_ADJACENT_FACES = 0,
+ R_BAKE_EXTEND = 1,
+} eBakeMarginType;
+
/** #BakeData.normal_swizzle (char) */
typedef enum eBakeNormalSwizzle {
R_BAKE_POSX = 0,
@@ -715,7 +722,9 @@ typedef struct RenderData {
/* Bake Render options */
short bake_mode, bake_flag;
- short bake_filter, bake_samples;
+ short bake_margin, bake_samples;
+ short bake_margin_type;
+ char _pad9[6];
float bake_biasdist, bake_user_scale;
/* path to render output */
@@ -785,12 +794,12 @@ typedef struct RenderData {
struct CurveMapping mblur_shutter_curve;
} RenderData;
-/* RenderData.quality_flag */
+/** #RenderData.quality_flag */
typedef enum eQualityOption {
SCE_PERF_HQ_NORMALS = (1 << 0),
} eQualityOption;
-/* RenderData.hair_type */
+/** #RenderData.hair_type */
typedef enum eHairType {
SCE_HAIR_SHAPE_STRAND = 0,
SCE_HAIR_SHAPE_STRIP = 1,
@@ -799,7 +808,7 @@ typedef enum eHairType {
/* *************************************************************** */
/* Render Conversion/Simplification Settings */
-/* control render convert and shading engine */
+/** Control render convert and shading engine. */
typedef struct RenderProfile {
struct RenderProfile *next, *prev;
char name[32];
@@ -829,7 +838,7 @@ typedef struct RenderProfile {
#define STEREO_RIGHT_SUFFIX "_R"
#define STEREO_LEFT_SUFFIX "_L"
-/* View3D.stereo3d_camera / View3D.multiview_eye / ImageUser.multiview_eye */
+/** #View3D.stereo3d_camera / #View3D.multiview_eye / #ImageUser.multiview_eye */
typedef enum eStereoViews {
STEREO_LEFT_ID = 0,
STEREO_RIGHT_ID = 1,
@@ -861,12 +870,12 @@ typedef struct Paint_Runtime {
char _pad[2];
} Paint_Runtime;
-/* We might want to store other things here. */
+/** We might want to store other things here. */
typedef struct PaintToolSlot {
struct Brush *brush;
} PaintToolSlot;
-/* Paint Tool Base */
+/** Paint Tool Base. */
typedef struct Paint {
struct Brush *brush;
@@ -903,7 +912,7 @@ typedef struct Paint {
/* ------------------------------------------- */
/* Image Paint */
-/* Texture/Image Editor */
+/** Texture/Image Editor. */
typedef struct ImagePaintSettings {
Paint paint;
@@ -934,7 +943,7 @@ typedef struct ImagePaintSettings {
/* ------------------------------------------- */
/* Particle Edit */
-/* Settings for a Particle Editing Brush */
+/** Settings for a Particle Editing Brush. */
typedef struct ParticleBrushData {
/** Common setting. */
short size;
@@ -944,7 +953,7 @@ typedef struct ParticleBrushData {
float strength;
} ParticleBrushData;
-/* Particle Edit Mode Settings */
+/** Particle Edit Mode Settings. */
typedef struct ParticleEditSettings {
short flag;
short totrekey;
@@ -971,7 +980,7 @@ typedef struct ParticleEditSettings {
/* ------------------------------------------- */
/* Sculpt */
-/* Sculpt */
+/** Sculpt. */
typedef struct Sculpt {
Paint paint;
@@ -1006,7 +1015,7 @@ typedef struct UvSculpt {
Paint paint;
} UvSculpt;
-/* grease pencil drawing brushes */
+/** Grease pencil drawing brushes. */
typedef struct GpPaint {
Paint paint;
int flag;
@@ -1020,21 +1029,21 @@ enum {
GPPAINT_FLAG_USE_VERTEXCOLOR = 1,
};
-/* Grease pencil vertex paint. */
+/** Grease pencil vertex paint. */
typedef struct GpVertexPaint {
Paint paint;
int flag;
char _pad[4];
} GpVertexPaint;
-/* Grease pencil sculpt paint. */
+/** Grease pencil sculpt paint. */
typedef struct GpSculptPaint {
Paint paint;
int flag;
char _pad[4];
} GpSculptPaint;
-/* Grease pencil weight paint. */
+/** Grease pencil weight paint. */
typedef struct GpWeightPaint {
Paint paint;
int flag;
@@ -1044,7 +1053,7 @@ typedef struct GpWeightPaint {
/* ------------------------------------------- */
/* Vertex Paint */
-/* Vertex Paint */
+/** Vertex Paint. */
typedef struct VPaint {
Paint paint;
char flag;
@@ -1062,7 +1071,7 @@ enum {
/* ------------------------------------------- */
/* GPencil Stroke Sculpting */
-/* GP_Sculpt_Settings.lock_axis */
+/** #GP_Sculpt_Settings.lock_axis */
typedef enum eGP_Lockaxis_Types {
GP_LOCKAXIS_VIEW = 0,
GP_LOCKAXIS_X = 1,
@@ -1071,7 +1080,7 @@ typedef enum eGP_Lockaxis_Types {
GP_LOCKAXIS_CURSOR = 4,
} eGP_Lockaxis_Types;
-/* Settings for a GPencil Speed Guide */
+/** Settings for a GPencil Speed Guide. */
typedef struct GP_Sculpt_Guide {
char use_guide;
char use_snapping;
@@ -1085,7 +1094,7 @@ typedef struct GP_Sculpt_Guide {
struct Object *reference_object;
} GP_Sculpt_Guide;
-/* GPencil Stroke Sculpting Settings */
+/** GPencil Stroke Sculpting Settings. */
typedef struct GP_Sculpt_Settings {
/** Runtime. */
void *paintcursor;
@@ -1134,7 +1143,7 @@ typedef enum eGP_vertex_SelectMaskFlag {
GP_VERTEX_MASK_SELECTMODE_SEGMENT = (1 << 2),
} eGP_Vertex_SelectMaskFlag;
-/* Settings for GP Interpolation Operators */
+/** Settings for GP Interpolation Operators. */
typedef struct GP_Interpolate_Settings {
/** Custom interpolation curve (for use with GP_IPO_CURVEMAP). */
struct CurveMapping *custom_ipo;
@@ -1255,7 +1264,7 @@ typedef struct UnifiedPaintSettings {
struct ColorSpace *colorspace;
} UnifiedPaintSettings;
-/* UnifiedPaintSettings.flag */
+/** #UnifiedPaintSettings.flag */
typedef enum {
UNIFIED_PAINT_SIZE = (1 << 0),
UNIFIED_PAINT_ALPHA = (1 << 1),
@@ -1313,7 +1322,7 @@ enum {
/* *************************************************************** */
/* Stats */
-/* Stats for Meshes */
+/** Stats for Meshes. */
typedef struct MeshStatVis {
char type;
char _pad1[2];
@@ -1341,8 +1350,10 @@ typedef struct SequencerToolSettings {
short snap_flag;
/* eSeqOverlapMode */
int overlap_mode;
- /** When there are many snap points, 0-1 range corresponds to resolution from boundbox to all
- * possible snap points. */
+ /**
+ * When there are many snap points,
+ * 0-1 range corresponds to resolution from bound-box to all possible snap points.
+ */
int snap_distance;
int pivot_point;
} SequencerToolSettings;
@@ -1570,8 +1581,8 @@ typedef struct PhysicsSettings {
char _pad0[4];
} PhysicsSettings;
-/* ------------------------------------------- */
-/* Safe Area options used in Camera View & Sequencer
+/**
+ * Safe Area options used in Camera View & Sequencer.
*/
typedef struct DisplaySafeAreas {
/* each value represents the (x,y) margins as a multiplier.
@@ -1587,8 +1598,9 @@ typedef struct DisplaySafeAreas {
float action_center[2];
} DisplaySafeAreas;
-/* ------------------------------------------- */
-/* Scene Display - used for store scene specific display settings for the 3d view */
+/**
+ * Scene Display - used for store scene specific display settings for the 3d view.
+ */
typedef struct SceneDisplay {
/** Light direction for shadows/highlight. */
float light_direction[3];
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index a4c254d6e5a..1a1d7cba7af 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -244,7 +244,7 @@ typedef struct PanelCategoryDyn {
rcti rect;
} PanelCategoryDyn;
-/* region stack of active tabs */
+/** Region stack of active tabs. */
typedef struct PanelCategoryStack {
struct PanelCategoryStack *next, *prev;
char idname[64];
@@ -654,8 +654,10 @@ enum {
#define UILST_FLT_SORT_MASK (((unsigned int)(UILST_FLT_SORT_REVERSE | UILST_FLT_SORT_LOCK)) - 1)
-/* regiontype, first two are the default set */
-/* Do NOT change order, append on end. Types are hardcoded needed */
+/**
+ * regiontype, first two are the default set.
+ * \warning Do NOT change order, append on end. Types are hard-coded needed.
+ */
typedef enum eRegion_Type {
RGN_TYPE_WINDOW = 0,
RGN_TYPE_HEADER = 1,
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index e1bba60396a..5fe67a34dae 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -47,6 +47,10 @@ struct SequenceLookup;
struct VFont;
struct bSound;
+/* -------------------------------------------------------------------- */
+/** \name Sequence & Editing Structs
+ * \{ */
+
/* strlens; 256= FILE_MAXFILE, 768= FILE_MAXDIR */
typedef struct StripAnim {
@@ -311,7 +315,12 @@ typedef struct Editing {
void *_pad1;
} Editing;
-/* ************* Effect Variable Structs ********* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Effect Variable Structs
+ * \{ */
+
typedef struct WipeVars {
float edgeWidth, angle;
short forward, wipetype;
@@ -360,7 +369,7 @@ typedef struct SpeedControlVars {
float speed_fader_frame_number;
} SpeedControlVars;
-/* SpeedControlVars.speed_control_type */
+/** #SpeedControlVars.speed_control_type */
enum {
SEQ_SPEED_STRETCH = 0,
SEQ_SPEED_MULTIPLY = 1,
@@ -387,7 +396,7 @@ typedef struct TextVars {
char _pad[5];
} TextVars;
-/* TextVars.flag */
+/** #TextVars.flag */
enum {
SEQ_TEXT_SHADOW = (1 << 0),
SEQ_TEXT_BOX = (1 << 1),
@@ -395,14 +404,14 @@ enum {
SEQ_TEXT_ITALIC = (1 << 3),
};
-/* TextVars.align */
+/** #TextVars.align */
enum {
SEQ_TEXT_ALIGN_X_LEFT = 0,
SEQ_TEXT_ALIGN_X_CENTER = 1,
SEQ_TEXT_ALIGN_X_RIGHT = 2,
};
-/* TextVars.align_y */
+/** #TextVars.align_y */
enum {
SEQ_TEXT_ALIGN_Y_TOP = 0,
SEQ_TEXT_ALIGN_Y_CENTER = 1,
@@ -418,7 +427,11 @@ typedef struct ColorMixVars {
float factor;
} ColorMixVars;
-/* ***************** Sequence modifiers ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sequence Modifiers
+ * \{ */
typedef struct SequenceModifierData {
struct SequenceModifierData *next, *prev;
@@ -489,7 +502,11 @@ enum {
SEQ_TONEMAP_RD_PHOTORECEPTOR = 1,
};
-/* ***************** Scopes ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scopes
+ * \{ */
typedef struct SequencerScopes {
struct ImBuf *reference_ibuf;
@@ -522,10 +539,15 @@ typedef struct SequencerScopes {
#define SEQ_SPEED_UNUSED_3 (1 << 2) /* cleared */
#define SEQ_SPEED_USE_INTERPOLATION (1 << 3)
-/* ***************** SEQUENCE ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flags & Types
+ * \{ */
+
#define SEQ_NAME_MAXSTR 64
-/* seq->flag */
+/** #Sequence.flag */
enum {
/* SELECT */
SEQ_LEFTSEL = (1 << 1),
@@ -568,7 +590,7 @@ enum {
SEQ_INVALID_EFFECT = (1u << 31),
};
-/* StripProxy->storage */
+/** #StripProxy.storage */
enum {
SEQ_STORAGE_PROXY_CUSTOM_FILE = (1 << 1), /* store proxy in custom directory */
SEQ_STORAGE_PROXY_CUSTOM_DIR = (1 << 2), /* store proxy in custom file */
@@ -601,18 +623,22 @@ enum {
#define SEQ_PROXY_TC_RECORD_RUN_NO_GAPS 8
#define SEQ_PROXY_TC_ALL 15
-/* SeqProxy->build_flags */
+/** SeqProxy.build_flags */
enum {
SEQ_PROXY_SKIP_EXISTING = 1,
};
-/* seq->alpha_mode */
+/** #Sequence.alpha_mode */
enum {
SEQ_ALPHA_STRAIGHT = 0,
SEQ_ALPHA_PREMUL = 1,
};
-/* seq->type WATCH IT: SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip!!! */
+/**
+ * #Sequence.type
+ *
+ * \warning #SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip!
+ */
enum {
SEQ_TYPE_IMAGE = 0,
SEQ_TYPE_META = 1,
@@ -681,7 +707,7 @@ enum {
/* modifiers */
-/* SequenceModifierData->type */
+/** #SequenceModifierData.type */
enum {
seqModifierType_ColorBalance = 1,
seqModifierType_Curves = 2,
@@ -694,7 +720,7 @@ enum {
NUM_SEQUENCE_MODIFIER_TYPES,
};
-/* SequenceModifierData->flag */
+/** #SequenceModifierData.flag */
enum {
SEQUENCE_MODIFIER_MUTE = (1 << 0),
SEQUENCE_MODIFIER_EXPANDED = (1 << 1),
@@ -712,13 +738,14 @@ enum {
SEQUENCE_MASK_TIME_ABSOLUTE = 1,
};
-/* Sequence->cache_flag
- * SEQ_CACHE_STORE_RAW
- * SEQ_CACHE_STORE_PREPROCESSED
- * SEQ_CACHE_STORE_COMPOSITE
- * FINAL_OUT is ignored
+/**
+ * #Sequence.cache_flag
+ * - #SEQ_CACHE_STORE_RAW
+ * - #SEQ_CACHE_STORE_PREPROCESSED
+ * - #SEQ_CACHE_STORE_COMPOSITE
+ * - #FINAL_OUT is ignored
*
- * Editing->cache_flag
+ * #Editing.cache_flag
* all entries
*/
enum {
@@ -745,7 +772,7 @@ enum {
SEQ_CACHE_STORE_THUMBNAIL = (1 << 12),
};
-/* Sequence->color_tag. */
+/** #Sequence.color_tag. */
typedef enum SequenceColorTag {
SEQUENCE_COLOR_NONE = -1,
SEQUENCE_COLOR_01,
diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h
index 01e3b3a5230..be787c1760f 100644
--- a/source/blender/makesdna/DNA_shader_fx_types.h
+++ b/source/blender/makesdna/DNA_shader_fx_types.h
@@ -77,7 +77,7 @@ typedef struct ShaderFxData {
char *error;
} ShaderFxData;
-/* Runtime temp data */
+/** Runtime temp data. */
typedef struct ShaderFxData_Runtime {
float loc[3];
char _pad[4];
diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h
index a700c9fe2f8..b14301ed32d 100644
--- a/source/blender/makesdna/DNA_simulation_types.h
+++ b/source/blender/makesdna/DNA_simulation_types.h
@@ -38,7 +38,7 @@ typedef struct Simulation {
char _pad[4];
} Simulation;
-/* Simulation.flag */
+/** #Simulation.flag */
enum {
SIM_DS_EXPAND = (1 << 0),
};
diff --git a/source/blender/makesdna/DNA_space_defaults.h b/source/blender/makesdna/DNA_space_defaults.h
new file mode 100644
index 00000000000..785abb39cc9
--- /dev/null
+++ b/source/blender/makesdna/DNA_space_defaults.h
@@ -0,0 +1,67 @@
+/*
+ * 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 DNA
+ */
+
+#pragma once
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name SpaceClip Struct
+ * \{ */
+
+#define _DNA_DEFAULT_MaskSpaceInfo \
+ { \
+ .draw_flag = 0, \
+ .draw_type = MASK_DT_OUTLINE, \
+ .overlay_mode = MASK_OVERLAY_ALPHACHANNEL, \
+ }
+
+#define _DNA_DEFAULT_SpaceClip \
+ { \
+ .spacetype = SPACE_CLIP, \
+ .link_flag = 0, \
+ .xof = 0, \
+ .yof = 0, \
+ .xlockof = 0, \
+ .ylockof = 0, \
+ .zoom = 1.0f, \
+ .user = _DNA_DEFAULT_MovieClipUser, \
+ .scopes = _DNA_DEFAULT_MovieClipScopes, \
+ .flag = SC_SHOW_MARKER_PATTERN | SC_SHOW_TRACK_PATH | SC_SHOW_GRAPH_TRACKS_MOTION | \
+ SC_SHOW_GRAPH_FRAMES | SC_SHOW_ANNOTATION, \
+ .mode = SC_MODE_TRACKING, \
+ .view = SC_VIEW_CLIP, \
+ .path_length = 20, \
+ .loc = {0, 0}, \
+ .scale = 0, \
+ .angle = 0, \
+ .stabmat = _DNA_DEFAULT_UNIT_M4, \
+ .unistabmat = _DNA_DEFAULT_UNIT_M4, \
+ .postproc_flag = 0, \
+ .gpencil_src = SC_GPENCIL_SRC_CLIP, \
+ .around = V3D_AROUND_CENTER_MEDIAN, \
+ .cursor = {0, 0}, \
+ .mask_info = _DNA_DEFAULT_MaskSpaceInfo, \
+ }
+
+/** \} */
+
+/* clang-format on */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 3ae7b3b68b8..4e12f135242 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -61,16 +61,23 @@ struct bNodeTree;
struct wmOperator;
struct wmTimer;
-/* Defined in `buttons_intern.h`. */
+/** Defined in `buttons_intern.h`. */
typedef struct SpaceProperties_Runtime SpaceProperties_Runtime;
-/* Defined in `node_intern.hh`. */
+/** Defined in `node_intern.hh`. */
+#ifdef __cplusplus
+namespace blender::ed::space_node {
+struct SpaceNode_Runtime;
+} // namespace blender::ed::space_node
+using SpaceNode_Runtime = blender::ed::space_node::SpaceNode_Runtime;
+#else
typedef struct SpaceNode_Runtime SpaceNode_Runtime;
+#endif
-/* Defined in `file_intern.h`. */
+/** Defined in `file_intern.h`. */
typedef struct SpaceFile_Runtime SpaceFile_Runtime;
-/* Defined in `spreadsheet_intern.hh`. */
+/** Defined in `spreadsheet_intern.hh`. */
typedef struct SpaceSpreadsheet_Runtime SpaceSpreadsheet_Runtime;
/* -------------------------------------------------------------------- */
@@ -91,7 +98,7 @@ typedef struct SpaceLink {
char _pad0[6];
} SpaceLink;
-/* SpaceLink.link_flag */
+/** #SpaceLink.link_flag */
enum {
/**
* The space is not a regular one opened through the editor menu (for example) but spawned by an
@@ -113,7 +120,7 @@ enum {
/** \name Space Info
* \{ */
-/* Info Header */
+/** Info Header. */
typedef struct SpaceInfo {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -127,7 +134,7 @@ typedef struct SpaceInfo {
char _pad[7];
} SpaceInfo;
-/* SpaceInfo.rpt_mask */
+/** #SpaceInfo.rpt_mask */
typedef enum eSpaceInfo_RptMask {
INFO_RPT_DEBUG = (1 << 0),
INFO_RPT_INFO = (1 << 1),
@@ -142,7 +149,7 @@ typedef enum eSpaceInfo_RptMask {
/** \name Properties Editor
* \{ */
-/* Properties Editor */
+/** Properties Editor. */
typedef struct SpaceProperties {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -210,7 +217,7 @@ typedef struct SpaceProperties {
// #define BUTS_EFFECTS 14
#endif /* DNA_DEPRECATED_ALLOW */
-/* SpaceProperties.mainb new */
+/** #SpaceProperties.mainb new */
typedef enum eSpaceButtons_Context {
BCONTEXT_RENDER = 0,
BCONTEXT_SCENE = 1,
@@ -235,7 +242,7 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_TOT,
} eSpaceButtons_Context;
-/* SpaceProperties.flag */
+/** #SpaceProperties.flag */
typedef enum eSpaceButtons_Flag {
/* SB_PRV_OSA = (1 << 0), */ /* UNUSED */
SB_PIN_CONTEXT = (1 << 1),
@@ -246,7 +253,7 @@ typedef enum eSpaceButtons_Flag {
SB_SHADING_CONTEXT = (1 << 4),
} eSpaceButtons_Flag;
-/* SpaceProperties.outliner_sync */
+/** #SpaceProperties.outliner_sync */
typedef enum eSpaceButtons_OutlinerSync {
PROPERTIES_SYNC_AUTO = 0,
PROPERTIES_SYNC_NEVER = 1,
@@ -259,10 +266,10 @@ typedef enum eSpaceButtons_OutlinerSync {
/** \name Outliner
* \{ */
-/* Defined in `outliner_intern.h`. */
+/** Defined in `outliner_intern.hh`. */
typedef struct SpaceOutliner_Runtime SpaceOutliner_Runtime;
-/* Outliner */
+/** Outliner */
typedef struct SpaceOutliner {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -303,7 +310,7 @@ typedef struct SpaceOutliner {
SpaceOutliner_Runtime *runtime;
} SpaceOutliner;
-/* SpaceOutliner.flag */
+/** #SpaceOutliner.flag */
typedef enum eSpaceOutliner_Flag {
/* SO_TESTBLOCKS = (1 << 0), */ /* UNUSED */
/* SO_NEWSELECTED = (1 << 1), */ /* UNUSED */
@@ -314,7 +321,7 @@ typedef enum eSpaceOutliner_Flag {
SO_MODE_COLUMN = (1 << 6),
} eSpaceOutliner_Flag;
-/* SpaceOutliner.filter */
+/** #SpaceOutliner.filter */
typedef enum eSpaceOutliner_Filter {
SO_FILTER_SEARCH = (1 << 0), /* Run-time flag. */
SO_FILTER_CLEARED_1 = (1 << 1),
@@ -356,7 +363,7 @@ typedef enum eSpaceOutliner_Filter {
(SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | \
SO_FILTER_NO_COLLECTION | SO_FILTER_NO_VIEW_LAYERS | SO_FILTER_NO_LIB_OVERRIDE)
-/* SpaceOutliner.filter_state */
+/** #SpaceOutliner.filter_state */
typedef enum eSpaceOutliner_StateFilter {
SO_FILTER_OB_ALL = 0,
SO_FILTER_OB_VISIBLE = 1,
@@ -366,7 +373,7 @@ typedef enum eSpaceOutliner_StateFilter {
SO_FILTER_OB_SELECTABLE = 5,
} eSpaceOutliner_StateFilter;
-/* SpaceOutliner.show_restrict_flags */
+/** #SpaceOutliner.show_restrict_flags */
typedef enum eSpaceOutliner_ShowRestrictFlag {
SO_RESTRICT_ENABLE = (1 << 0),
SO_RESTRICT_SELECT = (1 << 1),
@@ -377,7 +384,7 @@ typedef enum eSpaceOutliner_ShowRestrictFlag {
SO_RESTRICT_INDIRECT_ONLY = (1 << 6),
} eSpaceOutliner_Restrict;
-/* SpaceOutliner.outlinevis */
+/** #SpaceOutliner.outlinevis */
typedef enum eSpaceOutliner_Mode {
SO_SCENES = 0,
/* SO_CUR_SCENE = 1, */ /* deprecated! */
@@ -398,7 +405,7 @@ typedef enum eSpaceOutliner_Mode {
SO_OVERRIDES_LIBRARY = 16,
} eSpaceOutliner_Mode;
-/* SpaceOutliner.storeflag */
+/** #SpaceOutliner.storeflag */
typedef enum eSpaceOutliner_StoreFlag {
/* cleanup tree */
SO_TREESTORE_CLEANUP = (1 << 0),
@@ -408,7 +415,7 @@ typedef enum eSpaceOutliner_StoreFlag {
SO_TREESTORE_REBUILD = (1 << 2),
} eSpaceOutliner_StoreFlag;
-/* outliner search flags (SpaceOutliner.search_flags) */
+/** Outliner search flags (#SpaceOutliner.search_flags) */
typedef enum eSpaceOutliner_Search_Flags {
SO_FIND_CASE_SENSITIVE = (1 << 0),
SO_FIND_COMPLETE = (1 << 1),
@@ -429,7 +436,7 @@ typedef struct SpaceGraph_Runtime {
ListBase ghost_curves;
} SpaceGraph_Runtime;
-/* 'Graph' Editor (formerly known as the IPO Editor) */
+/** 'Graph' Editor (formerly known as the IPO Editor). */
typedef struct SpaceGraph {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -467,7 +474,7 @@ typedef struct SpaceGraph {
SpaceGraph_Runtime runtime;
} SpaceGraph;
-/* SpaceGraph.flag (Graph Editor Settings) */
+/** #SpaceGraph.flag (Graph Editor Settings) */
typedef enum eGraphEdit_Flag {
/* OLD DEPRECATED SETTING */
/* SIPO_LOCK_VIEW = (1 << 0), */
@@ -504,7 +511,7 @@ typedef enum eGraphEdit_Flag {
SIPO_NO_DRAW_EXTRAPOLATION = (1 << 17),
} eGraphEdit_Flag;
-/* SpaceGraph.mode (Graph Editor Mode) */
+/** #SpaceGraph.mode (Graph Editor Mode) */
typedef enum eGraphEdit_Mode {
/* all animation curves (from all over Blender) */
SIPO_MODE_ANIMATION = 0,
@@ -532,7 +539,7 @@ typedef enum eGraphEdit_Runtime_Flag {
/** \name NLA Editor
* \{ */
-/* NLA Editor */
+/** NLA Editor */
typedef struct SpaceNla {
struct SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -552,7 +559,7 @@ typedef struct SpaceNla {
View2D v2d DNA_DEPRECATED;
} SpaceNla;
-/* SpaceNla.flag */
+/** #SpaceNla.flag */
typedef enum eSpaceNla_Flag {
SNLA_FLAG_UNUSED_0 = (1 << 0),
SNLA_FLAG_UNUSED_1 = (1 << 1),
@@ -581,7 +588,7 @@ typedef struct SequencerPreviewOverlay {
char _pad0[4];
} SequencerPreviewOverlay;
-/* SequencerPreviewOverlay.flag */
+/** #SequencerPreviewOverlay.flag */
typedef enum eSpaceSeq_SequencerPreviewOverlay_Flag {
SEQ_PREVIEW_SHOW_2D_CURSOR = (1 << 1),
SEQ_PREVIEW_SHOW_OUTLINE_SELECTED = (1 << 2),
@@ -596,7 +603,7 @@ typedef struct SequencerTimelineOverlay {
char _pad0[4];
} SequencerTimelineOverlay;
-/* SequencerTimelineOverlay.flag */
+/** #SequencerTimelineOverlay.flag */
typedef enum eSpaceSeq_SequencerTimelineOverlay_Flag {
SEQ_TIMELINE_SHOW_STRIP_OFFSETS = (1 << 1),
SEQ_TIMELINE_SHOW_THUMBNAILS = (1 << 2),
@@ -617,7 +624,7 @@ typedef struct SpaceSeqRuntime {
struct GHash *last_displayed_thumbnails;
} SpaceSeqRuntime;
-/* Sequencer */
+/** Sequencer. */
typedef struct SpaceSeq {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -667,7 +674,7 @@ typedef struct SpaceSeq {
SpaceSeqRuntime runtime;
} SpaceSeq;
-/* SpaceSeq.mainb */
+/** #SpaceSeq.mainb */
typedef enum eSpaceSeq_RegionType {
SEQ_DRAW_IMG_IMBUF = 1,
SEQ_DRAW_IMG_WAVEFORM = 2,
@@ -675,14 +682,14 @@ typedef enum eSpaceSeq_RegionType {
SEQ_DRAW_IMG_HISTOGRAM = 4,
} eSpaceSeq_RegionType;
-/* SpaceSeq.draw_flag */
+/** #SpaceSeq.draw_flag */
typedef enum eSpaceSeq_DrawFlag {
SEQ_DRAW_BACKDROP = (1 << 0),
SEQ_DRAW_UNUSED_1 = (1 << 1),
SEQ_DRAW_TRANSFORM_PREVIEW = (1 << 2),
} eSpaceSeq_DrawFlag;
-/* SpaceSeq.flag */
+/** #SpaceSeq.flag */
typedef enum eSpaceSeq_Flag {
SEQ_DRAWFRAMES = (1 << 0),
SEQ_MARKER_TRANS = (1 << 1),
@@ -703,14 +710,14 @@ typedef enum eSpaceSeq_Flag {
SEQ_SHOW_GRID = (1 << 18),
} eSpaceSeq_Flag;
-/* SpaceSeq.view */
+/** #SpaceSeq.view */
typedef enum eSpaceSeq_Displays {
SEQ_VIEW_SEQUENCE = 1,
SEQ_VIEW_PREVIEW = 2,
SEQ_VIEW_SEQUENCE_PREVIEW = 3,
} eSpaceSeq_Dispays;
-/* SpaceSeq.render_size */
+/** #SpaceSeq.render_size */
typedef enum eSpaceSeq_Proxy_RenderSize {
SEQ_RENDER_SIZE_NONE = -1,
SEQ_RENDER_SIZE_SCENE = 0,
@@ -740,7 +747,7 @@ enum {
SEQ_GIZMO_HIDE_TOOL = (1 << 3),
};
-/* SpaceSeq.mainb */
+/** #SpaceSeq.mainb */
typedef enum eSpaceSeq_OverlayFrameType {
SEQ_OVERLAY_FRAME_TYPE_RECT = 0,
SEQ_OVERLAY_FRAME_TYPE_REFERENCE = 1,
@@ -753,7 +760,7 @@ typedef enum eSpaceSeq_OverlayFrameType {
/** \name File Selector
* \{ */
-/* Config and Input for File Selector */
+/** Config and Input for File Selector. */
typedef struct FileSelectParams {
/** Title, also used for the text of the execute button. */
char title[96];
@@ -857,7 +864,7 @@ typedef struct FileFolderHistory {
ListBase folders_next;
} FileFolderHistory;
-/* File Browser */
+/** File Browser. */
typedef struct SpaceFile {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -921,7 +928,7 @@ typedef struct SpaceFile {
SpaceFile_Runtime *runtime;
} SpaceFile;
-/* SpaceFile.browse_mode (File Space Browsing Mode) */
+/** #SpaceFile.browse_mode (File Space Browsing Mode). */
typedef enum eFileBrowse_Mode {
/* Regular Blender File Browser */
FILE_BROWSE_MODE_FILES = 0,
@@ -929,7 +936,7 @@ typedef enum eFileBrowse_Mode {
FILE_BROWSE_MODE_ASSETS = 1,
} eFileBrowse_Mode;
-/* FileSelectParams.display */
+/** #FileSelectParams.display */
enum eFileDisplayType {
/** Internal (not exposed to users): Keep whatever display type was used during the last File
* Browser use, or the default if no such record is found. Use this unless there's a good reason
@@ -943,7 +950,7 @@ enum eFileDisplayType {
FILE_IMGDISPLAY = 3,
};
-/* FileSelectParams.sort */
+/** #FileSelectParams.sort */
enum eFileSortType {
/** Internal (not exposed to users): Sort by whatever was sorted by during the last File Browser
* use, or the default if no such record is found. Use this unless there's a good reason to set a
@@ -958,14 +965,14 @@ enum eFileSortType {
FILE_SORT_SIZE = 4,
};
-/* SpaceFile.tags */
+/** #SpaceFile.tags */
enum eFileTags {
/** Tag the space as having to update files representing or containing main data. Must be set
* after file read and undo/redo. */
FILE_TAG_REBUILD_MAIN_FILES = (1 << 0),
};
-/* FileSelectParams.details_flags */
+/** #FileSelectParams.details_flags */
enum eFileDetails {
FILE_DETAILS_SIZE = (1 << 0),
FILE_DETAILS_DATETIME = (1 << 1),
@@ -986,7 +993,7 @@ enum eFileDetails {
*/
#define FILE_SELECT_MAX_RECURSIONS (FILE_MAX_LIBEXTRA / 2)
-/* filesel types */
+/** File selector types. */
typedef enum eFileSelectType {
FILE_LOADLIB = 1,
FILE_MAIN = 2,
@@ -1000,14 +1007,14 @@ typedef enum eFileSelectType {
FILE_SPECIAL = 9,
} eFileSelectType;
-/* filesel op property -> action */
+/** File-selector op property -> action. */
typedef enum eFileSel_Action {
FILE_OPENFILE = 0,
FILE_SAVE = 1,
} eFileSel_Action;
-/* sfile->params->flag */
/**
+ * #FileSelectParams.flag / `sfile->params->flag`.
* \note short flag, also used as 16 lower bits of flags in link/append code
* (WM and BLO code area, see #eBLOLibLinkFlags in BLO_readfile.h).
*/
@@ -1022,7 +1029,7 @@ typedef enum eFileSel_Params_Flag {
FILE_DIRSEL_ONLY = (1 << 7),
FILE_FILTER = (1 << 8),
FILE_PARAMS_FLAG_UNUSED_3 = (1 << 9),
- FILE_PARAMS_FLAG_UNUSED_4 = (1 << 10),
+ FILE_PATH_TOKENS_ALLOW = (1 << 10),
FILE_SORT_INVERT = (1 << 11),
FILE_HIDE_TOOL_PROPS = (1 << 12),
FILE_CHECK_EXISTING = (1 << 13),
@@ -1037,8 +1044,10 @@ typedef enum eFileSel_Params_AssetCatalogVisibility {
FILE_SHOW_ASSETS_WITHOUT_CATALOG,
} eFileSel_Params_AssetCatalogVisibility;
-/* sfile->params->rename_flag */
-/* NOTE: short flag. Defined as bitflags, but currently only used as exclusive status markers... */
+/**
+ * #FileSelectParams.rename_flag / `sfile->params->rename_flag`.
+ * \note short flag. Defined as bit-flags, but currently only used as exclusive status markers.
+ */
typedef enum eFileSel_Params_RenameFlag {
/** Used when we only have the name of the entry we want to rename,
* but not yet access to its matching file entry. */
@@ -1084,7 +1093,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_BLENDERLIB = (1u << 31),
} eFileSel_File_Types;
-/* Selection Flags in filesel: struct direntry, unsigned char selflag */
+/** Selection Flags in filesel: struct direntry, unsigned char selflag. */
typedef enum eDirEntry_SelectFlag {
/* FILE_SEL_ACTIVE = (1 << 1), */ /* UNUSED */
FILE_SEL_HIGHLIGHTED = (1 << 2),
@@ -1156,7 +1165,7 @@ typedef struct FileDirEntryArr {
char root[1024];
} FileDirEntryArr;
-/* FileDirEntry.flags */
+/** #FileDirEntry.flags */
enum {
/* The preview for this entry could not be generated. */
FILE_ENTRY_INVALID_PREVIEW = 1 << 0,
@@ -1243,7 +1252,7 @@ typedef struct SpaceImage {
SpaceImageOverlay overlay;
} SpaceImage;
-/* SpaceImage.dt_uv */
+/** #SpaceImage.dt_uv */
typedef enum eSpaceImage_UVDT {
SI_UVDT_OUTLINE = 0,
SI_UVDT_DASH = 1,
@@ -1251,20 +1260,20 @@ typedef enum eSpaceImage_UVDT {
SI_UVDT_WHITE = 3,
} eSpaceImage_UVDT;
-/* SpaceImage.dt_uvstretch */
+/** #SpaceImage.dt_uvstretch */
typedef enum eSpaceImage_UVDT_Stretch {
SI_UVDT_STRETCH_ANGLE = 0,
SI_UVDT_STRETCH_AREA = 1,
} eSpaceImage_UVDT_Stretch;
-/* SpaceImage.pixel_snap_mode */
+/** #SpaceImage.pixel_snap_mode */
typedef enum eSpaceImage_PixelSnapMode {
SI_PIXEL_SNAP_DISABLED = 0,
SI_PIXEL_SNAP_CENTER = 1,
SI_PIXEL_SNAP_CORNER = 2,
} eSpaceImage_Snap_Mode;
-/* SpaceImage.mode */
+/** #SpaceImage.mode */
typedef enum eSpaceImage_Mode {
SI_MODE_VIEW = 0,
SI_MODE_PAINT = 1,
@@ -1281,7 +1290,7 @@ typedef enum eSpaceImage_Sticky {
SI_STICKY_VERTEX = 2,
} eSpaceImage_Sticky;
-/* SpaceImage.flag */
+/** #SpaceImage.flag */
typedef enum eSpaceImage_Flag {
SI_FLAG_UNUSED_0 = (1 << 0), /* cleared */
SI_FLAG_UNUSED_1 = (1 << 1), /* cleared */
@@ -1375,7 +1384,7 @@ typedef struct SpaceText_Runtime {
} SpaceText_Runtime;
-/* Text Editor */
+/** Text Editor. */
typedef struct SpaceText {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1425,7 +1434,7 @@ typedef struct SpaceText {
SpaceText_Runtime runtime;
} SpaceText;
-/* SpaceText flags (moved from DNA_text_types.h) */
+/** SpaceText flags (moved from DNA_text_types.h). */
typedef enum eSpaceText_Flags {
/* scrollable */
ST_SCROLL_SELECT = (1 << 0),
@@ -1449,7 +1458,7 @@ typedef enum eSpaceText_Flags {
/** \name Script View (Obsolete)
* \{ */
-/* Script Runtime Data - Obsolete (pre 2.5) */
+/** Script Runtime Data - Obsolete (pre 2.5). */
typedef struct Script {
ID id;
@@ -1474,7 +1483,7 @@ typedef struct Script {
_script->py_globaldict = NULL; \
_script->flags = 0
-/* Script View - Obsolete (pre 2.5) */
+/** Script View - Obsolete (pre 2.5). */
typedef struct SpaceScript {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1584,7 +1593,7 @@ typedef struct SpaceNode {
SpaceNode_Runtime *runtime;
} SpaceNode;
-/* SpaceNode.flag */
+/** #SpaceNode.flag */
typedef enum eSpaceNode_Flag {
SNODE_BACKDRAW = (1 << 1),
SNODE_SHOW_GPENCIL = (1 << 2),
@@ -1602,7 +1611,7 @@ typedef enum eSpaceNode_Flag {
SNODE_SKIP_INSOFFSET = (1 << 13),
} eSpaceNode_Flag;
-/* SpaceNode.texfrom */
+/** #SpaceNode.texfrom */
typedef enum eSpaceNode_TexFrom {
/* SNODE_TEX_OBJECT = 0, */
SNODE_TEX_WORLD = 1,
@@ -1610,14 +1619,14 @@ typedef enum eSpaceNode_TexFrom {
SNODE_TEX_LINESTYLE = 3,
} eSpaceNode_TexFrom;
-/* SpaceNode.shaderfrom */
+/** #SpaceNode.shaderfrom */
typedef enum eSpaceNode_ShaderFrom {
SNODE_SHADER_OBJECT = 0,
SNODE_SHADER_WORLD = 1,
SNODE_SHADER_LINESTYLE = 2,
} eSpaceNode_ShaderFrom;
-/* SpaceNode.insert_ofs_dir */
+/** #SpaceNode.insert_ofs_dir */
enum {
SNODE_INSERTOFS_DIR_RIGHT = 0,
SNODE_INSERTOFS_DIR_LEFT = 1,
@@ -1629,7 +1638,7 @@ enum {
/** \name Console
* \{ */
-/* Console content */
+/** Console content. */
typedef struct ConsoleLine {
struct ConsoleLine *next, *prev;
@@ -1645,7 +1654,7 @@ typedef struct ConsoleLine {
int type;
} ConsoleLine;
-/* ConsoleLine.type */
+/** #ConsoleLine.type */
typedef enum eConsoleLine_Type {
CONSOLE_LINE_OUTPUT = 0,
CONSOLE_LINE_INPUT = 1,
@@ -1653,7 +1662,7 @@ typedef enum eConsoleLine_Type {
CONSOLE_LINE_ERROR = 3,
} eConsoleLine_Type;
-/* Console View */
+/** Console View. */
typedef struct SpaceConsole {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1707,7 +1716,7 @@ typedef struct SpaceUserPref {
/** \name Motion Tracking
* \{ */
-/* Clip Editor */
+/** Clip Editor. */
typedef struct SpaceClip {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1753,7 +1762,7 @@ typedef struct SpaceClip {
*/
float stabmat[4][4], unistabmat[4][4];
- /* movie postprocessing */
+ /** Movie postprocessing. */
int postproc_flag;
/* grease pencil */
@@ -1770,7 +1779,7 @@ typedef struct SpaceClip {
MaskSpaceInfo mask_info;
} SpaceClip;
-/* SpaceClip.flag */
+/** #SpaceClip.flag */
typedef enum eSpaceClip_Flag {
SC_SHOW_MARKER_PATTERN = (1 << 0),
SC_SHOW_MARKER_SEARCH = (1 << 1),
@@ -1797,7 +1806,7 @@ typedef enum eSpaceClip_Flag {
SC_SHOW_METADATA = (1 << 22),
} eSpaceClip_Flag;
-/* SpaceClip.mode */
+/** #SpaceClip.mode */
typedef enum eSpaceClip_Mode {
SC_MODE_TRACKING = 0,
// SC_MODE_RECONSTRUCTION = 1, /* DEPRECATED */
@@ -1805,14 +1814,14 @@ typedef enum eSpaceClip_Mode {
SC_MODE_MASKEDIT = 3,
} eSpaceClip_Mode;
-/* SpaceClip.view */
+/** #SpaceClip.view */
typedef enum eSpaceClip_View {
SC_VIEW_CLIP = 0,
SC_VIEW_GRAPH = 1,
SC_VIEW_DOPESHEET = 2,
} eSpaceClip_View;
-/* SpaceClip.gpencil_src */
+/** #SpaceClip.gpencil_src */
typedef enum eSpaceClip_GPencil_Source {
SC_GPENCIL_SRC_CLIP = 0,
SC_GPENCIL_SRC_TRACK = 1,
@@ -2006,6 +2015,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,
@@ -2029,8 +2039,10 @@ typedef enum eSpreadsheetColumnValueType {
/** \name Space Defines (eSpace_Type)
* \{ */
-/* space types, moved from DNA_screen_types.h */
-/* Do NOT change order, append on end. types are hardcoded needed */
+/**
+ * Space types: #SpaceLink.spacetype & #ScrArea.spacetype.
+ * \note Do NOT change order, append on end. types are hardcoded needed.
+ */
typedef enum eSpace_Type {
SPACE_EMPTY = 0,
SPACE_VIEW3D = 1,
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index 2c3cd8eab77..cd19825d29f 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -98,8 +98,10 @@ typedef struct CBData {
int cur;
} CBData;
-/* 32 = MAXCOLORBAND */
-/* note that this has to remain a single struct, for UserDef */
+/**
+ * 32 = #MAXCOLORBAND
+ * \note that this has to remain a single struct, for UserDef.
+ */
typedef struct ColorBand {
short tot, cur;
char ipotype, ipotype_hue;
@@ -454,14 +456,14 @@ typedef struct ColorMapping {
/* **************** ColorBand ********************* */
-/* colormode */
+/** color-mode. */
enum {
COLBAND_BLEND_RGB = 0,
COLBAND_BLEND_HSV = 1,
COLBAND_BLEND_HSL = 2,
};
-/* interpolation */
+/** Interpolation. */
enum {
COLBAND_INTERP_LINEAR = 0,
COLBAND_INTERP_EASE = 1,
@@ -470,7 +472,7 @@ enum {
COLBAND_INTERP_CONSTANT = 4,
};
-/* color interpolation */
+/** Color interpolation. */
enum {
COLBAND_HUE_NEAR = 0,
COLBAND_HUE_FAR = 1,
@@ -509,7 +511,7 @@ enum {
/* #define TEX_PD_NOISE_AGE 2 */ /* Deprecated */
/* #define TEX_PD_NOISE_TIME 3 */ /* Deprecated */
-/* color_source */
+/** color_source. */
enum {
TEX_PD_COLOR_CONSTANT = 0,
/* color_source: particles */
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index 0e313183300..815fab59876 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -462,7 +462,7 @@ typedef struct MovieTracking {
MovieTrackingDopesheet dopesheet;
} MovieTracking;
-/* MovieTrackingCamera->distortion_model */
+/** #MovieTrackingCamera.distortion_model */
enum {
TRACKING_DISTORTION_MODEL_POLYNOMIAL = 0,
TRACKING_DISTORTION_MODEL_DIVISION = 1,
@@ -470,13 +470,13 @@ enum {
TRACKING_DISTORTION_MODEL_BROWN = 3,
};
-/* MovieTrackingCamera->units */
+/** #MovieTrackingCamera.units */
enum {
CAMERA_UNITS_PX = 0,
CAMERA_UNITS_MM = 1,
};
-/* MovieTrackingMarker->flag */
+/** #MovieTrackingMarker.flag */
enum {
MARKER_DISABLED = (1 << 0),
MARKER_TRACKED = (1 << 1),
@@ -485,7 +485,7 @@ enum {
MARKER_GRAPH_SEL = (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y),
};
-/* MovieTrackingTrack->flag */
+/** #MovieTrackingTrack.flag */
enum {
TRACK_HAS_BUNDLE = (1 << 1),
TRACK_DISABLE_RED = (1 << 2),
@@ -501,7 +501,7 @@ enum {
TRACK_USE_2D_STAB_ROT = (1 << 12),
};
-/* MovieTrackingTrack->motion_model */
+/** #MovieTrackingTrack.motion_model */
enum {
TRACK_MOTION_MODEL_TRANSLATION = 0,
TRACK_MOTION_MODEL_TRANSLATION_ROTATION = 1,
@@ -511,27 +511,27 @@ enum {
TRACK_MOTION_MODEL_HOMOGRAPHY = 5,
};
-/* MovieTrackingTrack->algorithm_flag */
+/** #MovieTrackingTrack.algorithm_flag */
enum {
TRACK_ALGORITHM_FLAG_USE_BRUTE = (1 << 0),
TRACK_ALGORITHM_FLAG_USE_NORMALIZATION = (1 << 2),
TRACK_ALGORITHM_FLAG_USE_MASK = (1 << 3),
};
-/* MovieTrackingTrack->pattern_match */
+/** #MovieTrackingTrack.pattern_match */
typedef enum eTrackFrameMatch {
TRACK_MATCH_KEYFRAME = 0,
TRACK_MATCH_PREVIOS_FRAME = 1,
} eTrackFrameMatch;
-/* MovieTrackingSettings->motion_flag */
+/** #MovieTrackingSettings.motion_flag */
enum {
TRACKING_MOTION_TRIPOD = (1 << 0),
TRACKING_MOTION_MODAL = (TRACKING_MOTION_TRIPOD),
};
-/* MovieTrackingSettings->speed */
+/** #MovieTrackingSettings.speed */
enum {
TRACKING_SPEED_FASTEST = 0,
TRACKING_SPEED_REALTIME = 1,
@@ -540,13 +540,13 @@ enum {
TRACKING_SPEED_DOUBLE = 5,
};
-/* MovieTrackingSettings->reconstruction_flag */
+/** #MovieTrackingSettings.reconstruction_flag */
enum {
/* TRACKING_USE_FALLBACK_RECONSTRUCTION = (1 << 0), */ /* DEPRECATED */
TRACKING_USE_KEYFRAME_SELECTION = (1 << 1),
};
-/* MovieTrackingSettings->refine_camera_intrinsics */
+/** #MovieTrackingSettings.refine_camera_intrinsics */
enum {
REFINE_NO_INTRINSICS = (0),
@@ -556,7 +556,7 @@ enum {
REFINE_TANGENTIAL_DISTORTION = (1 << 3),
};
-/* MovieTrackingStabilization->flag */
+/** #MovieTrackingStabilization.flag */
enum {
TRACKING_2D_STABILIZATION = (1 << 0),
TRACKING_AUTOSCALE = (1 << 1),
@@ -565,19 +565,19 @@ enum {
TRACKING_SHOW_STAB_TRACKS = (1 << 5),
};
-/* MovieTrackingStabilization->filter */
+/** #MovieTrackingStabilization.filter */
enum {
TRACKING_FILTER_NEAREST = 0,
TRACKING_FILTER_BILINEAR = 1,
TRACKING_FILTER_BICUBIC = 2,
};
-/* MovieTrackingReconstruction->flag */
+/** #MovieTrackingReconstruction.flag */
enum {
TRACKING_RECONSTRUCTED = (1 << 0),
};
-/* MovieTrackingObject->flag */
+/** #MovieTrackingObject.flag */
enum {
TRACKING_OBJECT_CAMERA = (1 << 0),
};
@@ -588,7 +588,7 @@ enum {
TRACKING_CLEAN_DELETE_SEGMENT = 2,
};
-/* MovieTrackingDopesheet->sort_method */
+/** #MovieTrackingDopesheet.sort_method */
enum {
TRACKING_DOPE_SORT_NAME = 0,
TRACKING_DOPE_SORT_LONGEST = 1,
@@ -598,27 +598,27 @@ enum {
TRACKING_DOPE_SORT_END = 5,
};
-/* MovieTrackingDopesheet->flag */
+/** #MovieTrackingDopesheet.flag */
enum {
TRACKING_DOPE_SORT_INVERSE = (1 << 0),
TRACKING_DOPE_SELECTED_ONLY = (1 << 1),
TRACKING_DOPE_SHOW_HIDDEN = (1 << 2),
};
-/* MovieTrackingDopesheetCoverageSegment->trackness */
+/** #MovieTrackingDopesheetCoverageSegment.trackness */
enum {
TRACKING_COVERAGE_BAD = 0,
TRACKING_COVERAGE_ACCEPTABLE = 1,
TRACKING_COVERAGE_OK = 2,
};
-/* MovieTrackingPlaneMarker->flag */
+/** #MovieTrackingPlaneMarker.flag */
enum {
PLANE_MARKER_DISABLED = (1 << 0),
PLANE_MARKER_TRACKED = (1 << 1),
};
-/* MovieTrackingPlaneTrack->flag */
+/** #MovieTrackingPlaneTrack.flag */
enum {
PLANE_TRACK_HIDDEN = (1 << 1),
PLANE_TRACK_LOCKED = (1 << 2),
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index c8fdac19b61..15bb1ef920d 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -30,7 +30,8 @@
extern "C" {
#endif
-/* themes; defines in BIF_resource.h */
+/* Themes; defines in `BIF_resource.h`. */
+
struct ColorBand;
/* ************************ style definitions ******************** */
@@ -50,19 +51,20 @@ typedef enum eUIFont_ID {
/* UIFONT_CUSTOM2 = 3, */ /* UNUSED */
} eUIFont_ID;
-/* default fonts to load/initialize */
-/* first font is the default (index 0), others optional */
+/**
+ * Default fonts to load/initialize.
+ * First font is the default (index 0), others optional.
+ */
+#
+#
typedef struct uiFont {
struct uiFont *next, *prev;
/** 1024 = FILE_MAX. */
- char filename[1024];
+ char filepath[1024];
/** From blfont lib. */
short blf_id;
/** Own id (eUIFont_ID). */
short uifont_id;
- /** Fonts that read from left to right. */
- short r_to_l;
- char _pad0[2];
} uiFont;
/** This state defines appearance of text. */
@@ -445,7 +447,7 @@ typedef enum eBackgroundGradientTypes {
TH_BACKGROUND_GRADIENT_RADIAL = 2,
} eBackgroundGradientTypes;
-/* set of colors for use as a custom color set for Objects/Bones wire drawing */
+/** Set of colors for use as a custom color set for Objects/Bones wire drawing. */
typedef struct ThemeWireColor {
unsigned char solid[4];
unsigned char select[4];
@@ -653,6 +655,7 @@ typedef struct UserDef_Experimental {
char use_cycles_debug;
char use_geometry_nodes_legacy;
char show_asset_debug_info;
+ char no_asset_indexing;
char SANITIZE_AFTER_HERE;
/* The following options are automatically sanitized (set to 0)
* when the release cycle is not alpha. */
@@ -663,7 +666,7 @@ typedef struct UserDef_Experimental {
char use_sculpt_tools_tilt;
char use_extended_asset_browser;
char use_override_templates;
- char _pad[2];
+ char _pad[1];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
@@ -959,7 +962,7 @@ typedef struct UserDef {
UserDef_Runtime runtime;
} UserDef;
-/* from blenkernel blender.c */
+/** From blenkernel `blender.c`. */
extern UserDef U;
/* ***************** USERDEF ****************** */
@@ -1142,6 +1145,7 @@ typedef enum eUserpref_GPU_Flag {
USER_GPU_FLAG_NO_DEPT_PICK = (1 << 0),
USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE = (1 << 1),
USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE = (1 << 2),
+ USER_GPU_FLAG_SUBDIVISION_EVALUATION = (1 << 3),
} eUserpref_GPU_Flag;
/** #UserDef.tablet_api */
diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h
index f8166305fd9..6c03422963d 100644
--- a/source/blender/makesdna/DNA_view2d_types.h
+++ b/source/blender/makesdna/DNA_view2d_types.h
@@ -31,7 +31,7 @@ extern "C" {
/* ---------------------------------- */
-/* View 2D data - stored per region */
+/** View 2D data - stored per region. */
typedef struct View2D {
/** Tot - area that data can be drawn in; cur - region of tot that is visible in viewport. */
rctf tot, cur;
@@ -83,7 +83,7 @@ typedef struct View2D {
/* ---------------------------------- */
-/* view zooming restrictions, per axis (v2d->keepzoom) */
+/** View zooming restrictions, per axis (#View2D.keepzoom) */
enum {
/* zoom is clamped to lie within limits set by minzoom and maxzoom */
V2D_LIMITZOOM = (1 << 0),
@@ -97,7 +97,7 @@ enum {
V2D_LOCKZOOM_Y = (1 << 9),
};
-/* view panning restrictions, per axis (v2d->keepofs) */
+/** View panning restrictions, per axis (#View2D.keepofs). */
enum {
/* panning on x-axis is not allowed */
V2D_LOCKOFS_X = (1 << 1),
@@ -109,7 +109,7 @@ enum {
V2D_KEEPOFS_Y = (1 << 4),
};
-/* view extent restrictions (v2d->keeptot) */
+/** View extent restrictions (#View2D.keeptot). */
enum {
/** 'cur' view can be out of extents of 'tot' */
V2D_KEEPTOT_FREE = 0,
@@ -120,7 +120,7 @@ enum {
V2D_KEEPTOT_STRICT = 2,
};
-/* general refresh settings (v2d->flag) */
+/** General refresh settings (#View2D.flag). */
enum {
/* global view2d horizontal locking (for showing same time interval) */
/* TODO: this flag may be set in old files but is not accessible currently,
@@ -138,7 +138,7 @@ enum {
V2D_IS_INIT = (1 << 10),
};
-/* scroller flags for View2D (v2d->scroll) */
+/** Scroller flags for View2D (#View2D.scroll). */
enum {
/* left scrollbar */
V2D_SCROLL_LEFT = (1 << 0),
@@ -162,13 +162,15 @@ enum {
V2D_SCROLL_HORIZONTAL_FULLR = (1 << 10),
};
-/* scroll_ui, activate flag for drawing */
+/** scroll_ui, activate flag for drawing. */
enum {
V2D_SCROLL_H_ACTIVE = (1 << 0),
V2D_SCROLL_V_ACTIVE = (1 << 1),
};
-/* alignment flags for totrect, flags use 'shading-out' convention (v2d->align) */
+/**
+ * Alignment flags for `totrect`, flags use 'shading-out' convention (#View2D.align).
+ */
enum {
/* all quadrants free */
V2D_ALIGN_FREE = 0,
diff --git a/source/blender/makesdna/DNA_view3d_defaults.h b/source/blender/makesdna/DNA_view3d_defaults.h
index c4d0c83b346..870197a401c 100644
--- a/source/blender/makesdna/DNA_view3d_defaults.h
+++ b/source/blender/makesdna/DNA_view3d_defaults.h
@@ -53,6 +53,7 @@
.wireframe_threshold = 1.0f, \
.wireframe_opacity = 1.0f, \
.xray_alpha_bone = 0.5f, \
+ .bone_wire_alpha = 1.0f, \
.fade_alpha = 0.40f, \
.texture_paint_mode_opacity = 1.0f, \
.weight_paint_mode_opacity = 1.0f, \
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 3fd2f1208dd..dafae6f2eb7 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -71,7 +71,7 @@ typedef struct RegionView3D {
float clip_local[6][4];
struct BoundBox *clipbb;
- /** Allocated backup of its self while in local-view. */
+ /** Allocated backup of itself while in local-view. */
struct RegionView3D *localvd;
struct RenderEngine *render_engine;
@@ -224,6 +224,8 @@ typedef struct View3DOverlay {
/** Armature edit/pose mode settings. */
float xray_alpha_bone;
+ float bone_wire_alpha;
+ char _pad1[4];
/** Darken Inactive. */
float fade_alpha;
@@ -245,7 +247,7 @@ typedef struct View3DOverlay {
char _pad[4];
} View3DOverlay;
-/* View3DOverlay->handle_display */
+/** #View3DOverlay.handle_display */
typedef enum eHandleDisplay {
/* Display only selected points. */
CURVE_HANDLE_SELECTED = 0,
@@ -300,7 +302,7 @@ typedef struct View3D {
struct Object *camera, *ob_center;
rctf render_border;
- /** Allocated backup of its self while in local-view. */
+ /** Allocated backup of itself while in local-view. */
struct View3D *localvd;
/** Optional string for armature bone to define center, MAXBONENAME. */
@@ -419,7 +421,7 @@ enum {
RV3D_LOCK_ANY_TRANSFORM = (RV3D_LOCK_LOCATION | RV3D_LOCK_ROTATION | RV3D_LOCK_ZOOM_AND_DOLLY),
};
-/* Bitwise OR of the regular lock-flags with runtime only lock-flags. */
+/** Bit-wise OR of the regular lock-flags with runtime only lock-flags. */
#define RV3D_LOCK_FLAGS(rv3d) ((rv3d)->viewlock | ((rv3d)->runtime_viewlock))
/** #RegionView3D.viewlock_quad */
diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h
index 1344f295ea9..df5a122faaf 100644
--- a/source/blender/makesdna/DNA_volume_types.h
+++ b/source/blender/makesdna/DNA_volume_types.h
@@ -30,13 +30,13 @@ struct PackedFile;
struct VolumeGridVector;
typedef struct Volume_Runtime {
- /* OpenVDB Grids */
+ /** OpenVDB Grids. */
struct VolumeGridVector *grids;
- /* Current frame in sequence for evaluated volume */
+ /** Current frame in sequence for evaluated volume. */
int frame;
- /* Default simplify level for volume grids loaded from files. */
+ /** Default simplify level for volume grids loaded from files. */
int default_simplify_level;
} Volume_Runtime;
@@ -96,12 +96,12 @@ typedef struct Volume {
Volume_Runtime runtime;
} Volume;
-/* Volume.flag */
+/** #Volume.flag */
enum {
VO_DS_EXPAND = (1 << 0),
};
-/* Volume.sequence_mode */
+/** #Volume.sequence_mode */
typedef enum VolumeSequenceMode {
VOLUME_SEQUENCE_CLIP = 0,
VOLUME_SEQUENCE_EXTEND = 1,
@@ -109,7 +109,7 @@ typedef enum VolumeSequenceMode {
VOLUME_SEQUENCE_PING_PONG = 3,
} VolumeSequenceMode;
-/* VolumeDisplay.wireframe_type */
+/** #VolumeDisplay.wireframe_type */
typedef enum VolumeWireframeType {
VOLUME_WIREFRAME_NONE = 0,
VOLUME_WIREFRAME_BOUNDS = 1,
@@ -117,32 +117,32 @@ typedef enum VolumeWireframeType {
VOLUME_WIREFRAME_POINTS = 3,
} VolumeWireframeType;
-/* VolumeDisplay.wireframe_detail */
+/** #VolumeDisplay.wireframe_detail */
typedef enum VolumeWireframeDetail {
VOLUME_WIREFRAME_COARSE = 0,
VOLUME_WIREFRAME_FINE = 1,
} VolumeWireframeDetail;
-/* VolumeRender.space */
+/** #VolumeRender.space */
typedef enum VolumeRenderSpace {
VOLUME_SPACE_OBJECT = 0,
VOLUME_SPACE_WORLD = 1,
} VolumeRenderSpace;
-/* VolumeDisplay.interpolation_method */
+/** #VolumeDisplay.interpolation_method */
typedef enum VolumeDisplayInterpMethod {
VOLUME_DISPLAY_INTERP_LINEAR = 0,
VOLUME_DISPLAY_INTERP_CUBIC = 1,
VOLUME_DISPLAY_INTERP_CLOSEST = 2,
} VolumeDisplayInterpMethod;
-/* VolumeDisplay.axis_slice_method */
+/** #VolumeDisplay.axis_slice_method */
typedef enum AxisAlignedSlicingMethod {
VOLUME_AXIS_SLICE_FULL = 0,
VOLUME_AXIS_SLICE_SINGLE = 1,
} AxisAlignedSlicingMethod;
-/* VolumeDisplay.slice_axis */
+/** #VolumeDisplay.slice_axis */
typedef enum SliceAxis {
VOLUME_SLICE_AXIS_AUTO = 0,
VOLUME_SLICE_AXIS_X = 1,
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 841edaf8724..d0e4184d2a5 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -33,7 +33,8 @@
extern "C" {
#endif
-/* defined here: */
+/* Defined here: */
+
struct wmWindow;
struct wmWindowManager;
@@ -45,7 +46,8 @@ struct wmMsgBus;
struct wmOperator;
struct wmOperatorType;
-/* forwards */
+/* Forward declarations: */
+
struct PointerRNA;
struct Report;
struct ReportList;
@@ -58,7 +60,7 @@ struct wmTimer;
#define OP_MAX_TYPENAME 64
#define KMAP_MAX_NAME 64
-/* keep in sync with 'rna_enum_wm_report_items' in wm_rna.c */
+/** Keep in sync with 'rna_enum_wm_report_items' in `wm_rna.c`. */
typedef enum eReportType {
RPT_DEBUG = (1 << 0),
RPT_INFO = (1 << 1),
@@ -100,7 +102,9 @@ typedef struct Report {
const char *message;
} Report;
-/* saved in the wm, don't remove */
+/**
+ * \note Saved in the wm, don't remove.
+ */
typedef struct ReportList {
ListBase list;
/** eReportType. */
@@ -133,7 +137,7 @@ typedef struct wmXrData {
/* reports need to be before wmWindowManager */
-/* windowmanager is saved, tag WMAN */
+/** Window-manager is saved, tag WMAN. */
typedef struct wmWindowManager {
ID id;
@@ -204,13 +208,13 @@ typedef struct wmWindowManager {
//#endif
} wmWindowManager;
-/* wmWindowManager.initialized */
+/** #wmWindowManager.initialized */
enum {
WM_WINDOW_IS_INIT = (1 << 0),
WM_KEYCONFIG_IS_INIT = (1 << 1),
};
-/* wmWindowManager.outliner_sync_select_dirty */
+/** #wmWindowManager.outliner_sync_select_dirty */
enum {
WM_OUTLINER_SYNC_SELECT_FROM_OBJECT = (1 << 0),
WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE = (1 << 1),
@@ -231,7 +235,9 @@ enum {
# endif
#endif
-/* the saveable part, rest of data is local in ghostwinlay */
+/**
+ * The saveable part, the rest of the data is local in GHOST.
+ */
typedef struct wmWindow {
struct wmWindow *next, *prev;
@@ -352,7 +358,9 @@ typedef struct wmOperatorTypeMacro {
struct PointerRNA *ptr;
} wmOperatorTypeMacro;
-/* Partial copy of the event, for matching by event handler. */
+/**
+ * Partial copy of the event, for matching by event handler.
+ */
typedef struct wmKeyMapItem {
struct wmKeyMapItem *next, *prev;
@@ -436,7 +444,9 @@ enum {
KMI_TYPE_NDOF = 5,
};
-/* stored in WM, the actively used keymaps */
+/**
+ * Stored in WM, the actively used key-maps.
+ */
typedef struct wmKeyMap {
struct wmKeyMap *next, *prev;
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index a0856588a58..95530c7b0f7 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -60,7 +60,9 @@ typedef struct bToolRef_Runtime {
int flag;
} bToolRef_Runtime;
-/* Stored per mode. */
+/**
+ * \note Stored per mode.
+ */
typedef struct bToolRef {
struct bToolRef *next, *prev;
char idname[64];
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index db34cf83fa9..a3c54e91780 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -159,6 +159,7 @@ set(SRC
../DNA_pointcloud_defaults.h
../DNA_scene_defaults.h
../DNA_simulation_defaults.h
+ ../DNA_space_defaults.h
../DNA_speaker_defaults.h
../DNA_texture_defaults.h
../DNA_vec_defaults.h
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
index 1d4257328a4..5bc5de7a20b 100644
--- a/source/blender/makesdna/intern/dna_defaults.c
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -103,6 +103,7 @@
#include "DNA_light_types.h"
#include "DNA_lightprobe_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_mask_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
@@ -144,6 +145,7 @@
#include "DNA_pointcloud_defaults.h"
#include "DNA_scene_defaults.h"
#include "DNA_simulation_defaults.h"
+#include "DNA_space_defaults.h"
#include "DNA_speaker_defaults.h"
#include "DNA_texture_defaults.h"
#include "DNA_volume_defaults.h"
@@ -208,6 +210,8 @@ SDNA_DEFAULT_DECL_STRUCT(MetaBall);
/* DNA_movieclip_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(MovieClip);
+SDNA_DEFAULT_DECL_STRUCT(MovieClipUser);
+SDNA_DEFAULT_DECL_STRUCT(MovieClipScopes);
/* DNA_object_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(Object);
@@ -225,6 +229,9 @@ SDNA_DEFAULT_DECL_STRUCT(ToolSettings);
/* DNA_simulation_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(Simulation);
+/* DNA_space_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(SpaceClip);
+
/* DNA_speaker_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(Speaker);
@@ -406,11 +413,18 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
/* DNA_mesh_defaults.h */
SDNA_DEFAULT_DECL(Mesh),
+ /* DNA_space_defaults.h */
+ SDNA_DEFAULT_DECL(SpaceClip),
+ SDNA_DEFAULT_DECL_EX(MaskSpaceInfo, SpaceClip.mask_info),
+
/* DNA_meta_defaults.h */
SDNA_DEFAULT_DECL(MetaBall),
/* DNA_movieclip_defaults.h */
SDNA_DEFAULT_DECL(MovieClip),
+ SDNA_DEFAULT_DECL(MovieClipUser),
+ SDNA_DEFAULT_DECL(MovieClipScopes),
+ SDNA_DEFAULT_DECL_EX(MovieTrackingMarker, MovieClipScopes.undist_marker),
/* DNA_object_defaults.h */
SDNA_DEFAULT_DECL(Object),
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index bdf29b22787..6322cb459dd 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -1127,7 +1127,7 @@ static void reconstruct_structs(const DNA_ReconstructInfo *reconstruct_info,
*
* \param reconstruct_info: Preprocessed reconstruct information generated by
* #DNA_reconstruct_info_create.
- * \param new_struct_nr: Index in newsdna->structs of the struct that is being reconstructed.
+ * \param new_struct_nr: Index in `newsdna->structs` of the struct that is being reconstructed.
* \param old_block: Memory buffer containing the old struct.
* \param new_block: Where to put converted struct contents.
*/
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index c5769d7eee4..cb8052856a7 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -107,6 +107,7 @@ 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(RenderData, bake_filter, bake_margin)
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)
diff --git a/source/blender/makesdna/intern/dna_utils.h b/source/blender/makesdna/intern/dna_utils.h
index b89c45a7a43..e161e317c42 100644
--- a/source/blender/makesdna/intern/dna_utils.h
+++ b/source/blender/makesdna/intern/dna_utils.h
@@ -45,7 +45,7 @@ uint DNA_elem_id_strip(char *elem);
* return true if it does, with start/end offsets.
*/
bool DNA_elem_id_match(const char *elem_search,
- const int elem_search_len,
+ int elem_search_len,
const char *elem_full,
uint *r_elem_full_offset);
/**
@@ -53,14 +53,16 @@ bool DNA_elem_id_match(const char *elem_search,
*/
char *DNA_elem_id_rename(struct MemArena *mem_arena,
const char *elem_src,
- const int elem_src_len,
+ int elem_src_len,
const char *elem_dst,
- const int elem_dst_len,
+ int elem_dst_len,
const char *elem_src_full,
- const int elem_src_full_len,
- const uint elem_src_full_offset_len);
+ int elem_src_full_len,
+ uint elem_src_full_offset_len);
-/* When requesting version info, support both directions. */
+/**
+ * When requesting version info, support both directions.
+ */
enum eDNA_RenameDir {
DNA_RENAME_STATIC_FROM_ALIAS = -1,
DNA_RENAME_ALIAS_FROM_STATIC = 1,
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 7fa7405add1..1ade964854d 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -105,6 +105,7 @@ extern StructRNA RNA_BuildModifier;
extern StructRNA RNA_ByteColorAttribute;
extern StructRNA RNA_ByteColorAttributeValue;
extern StructRNA RNA_CacheFile;
+extern StructRNA RNA_CacheFileLayer;
extern StructRNA RNA_Camera;
extern StructRNA RNA_CameraDOFSettings;
extern StructRNA RNA_CastModifier;
@@ -137,6 +138,7 @@ extern StructRNA RNA_CompositorNodeChannelMatte;
extern StructRNA RNA_CompositorNodeChromaMatte;
extern StructRNA RNA_CompositorNodeColorMatte;
extern StructRNA RNA_CompositorNodeColorSpill;
+extern StructRNA RNA_CompositorNodeConvertColorSpace;
extern StructRNA RNA_CompositorNodeCombHSVA;
extern StructRNA RNA_CompositorNodeCombRGBA;
extern StructRNA RNA_CompositorNodeCombYCCA;
@@ -184,6 +186,7 @@ extern StructRNA RNA_CompositorNodeRGBToBW;
extern StructRNA RNA_CompositorNodeRLayers;
extern StructRNA RNA_CompositorNodeRotate;
extern StructRNA RNA_CompositorNodeScale;
+extern StructRNA RNA_CompositorNodeSceneTime;
extern StructRNA RNA_CompositorNodeSepHSVA;
extern StructRNA RNA_CompositorNodeSepRGBA;
extern StructRNA RNA_CompositorNodeSepYCCA;
@@ -777,7 +780,7 @@ bool RNA_pointer_is_null(const PointerRNA *ptr);
bool RNA_path_resolved_create(PointerRNA *ptr,
struct PropertyRNA *prop,
- const int prop_index,
+ int prop_index,
PathResolvedRNA *r_anim_rna);
void RNA_blender_rna_pointer_create(PointerRNA *r_ptr);
@@ -937,13 +940,11 @@ void RNA_property_float_ui_range(PointerRNA *ptr,
int RNA_property_float_clamp(PointerRNA *ptr, PropertyRNA *prop, float *value);
int RNA_property_int_clamp(PointerRNA *ptr, PropertyRNA *prop, int *value);
-bool RNA_enum_identifier(const EnumPropertyItem *item, const int value, const char **identifier);
-int RNA_enum_bitflag_identifiers(const EnumPropertyItem *item,
- const int value,
- const char **identifier);
-bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r_name);
-bool RNA_enum_description(const EnumPropertyItem *item, const int value, const char **description);
-int RNA_enum_from_value(const EnumPropertyItem *item, const int value);
+bool RNA_enum_identifier(const EnumPropertyItem *item, int value, const char **identifier);
+int RNA_enum_bitflag_identifiers(const EnumPropertyItem *item, int value, const char **identifier);
+bool RNA_enum_name(const EnumPropertyItem *item, int value, const char **r_name);
+bool RNA_enum_description(const EnumPropertyItem *item, int value, const char **description);
+int RNA_enum_from_value(const EnumPropertyItem *item, int value);
int RNA_enum_from_identifier(const EnumPropertyItem *item, const char *identifier);
/**
* Take care using this with translated enums,
@@ -955,7 +956,7 @@ unsigned int RNA_enum_items_count(const EnumPropertyItem *item);
void RNA_property_enum_items_ex(struct bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
- const bool use_static,
+ bool use_static,
const EnumPropertyItem **r_item,
int *r_totitem,
bool *r_free);
@@ -979,32 +980,20 @@ void RNA_property_enum_items_gettexted_all(struct bContext *C,
bool *r_free);
bool RNA_property_enum_value(
struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const char *identifier, int *r_value);
-bool RNA_property_enum_identifier(struct bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- const int value,
- const char **identifier);
+bool RNA_property_enum_identifier(
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, const char **identifier);
bool RNA_property_enum_name(
- struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **name);
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, const char **name);
bool RNA_property_enum_name_gettexted(
- struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **name);
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, const char **name);
-bool RNA_property_enum_item_from_value(struct bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- const int value,
- EnumPropertyItem *r_item);
-bool RNA_property_enum_item_from_value_gettexted(struct bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- const int value,
- EnumPropertyItem *r_item);
-
-int RNA_property_enum_bitflag_identifiers(struct bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- const int value,
- const char **identifier);
+bool RNA_property_enum_item_from_value(
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, EnumPropertyItem *r_item);
+bool RNA_property_enum_item_from_value_gettexted(
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, EnumPropertyItem *r_item);
+
+int RNA_property_enum_bitflag_identifiers(
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int value, const char **identifier);
StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value);
@@ -1035,9 +1024,7 @@ 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_overridable_library_set(PointerRNA *ptr, PropertyRNA *prop, bool is_overridable);
bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_property_comparable(PointerRNA *ptr, PropertyRNA *prop);
/**
@@ -1156,7 +1143,7 @@ int RNA_property_collection_lookup_string_index(
*/
int RNA_property_collection_assign_int(PointerRNA *ptr,
PropertyRNA *prop,
- const int key,
+ int key,
const PointerRNA *assign_ptr);
bool RNA_property_collection_type_get(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_ptr);
@@ -1557,22 +1544,19 @@ char *RNA_pointer_as_string(struct bContext *C,
*/
char *RNA_pointer_as_string_keywords_ex(struct bContext *C,
PointerRNA *ptr,
- const bool as_function,
- const bool all_args,
- const bool nested_args,
- const int max_prop_length,
+ bool as_function,
+ bool all_args,
+ bool nested_args,
+ int max_prop_length,
PropertyRNA *iterprop);
char *RNA_pointer_as_string_keywords(struct bContext *C,
PointerRNA *ptr,
- const bool as_function,
- const bool all_args,
- const bool nested_args,
- const int max_prop_length);
-char *RNA_function_as_string_keywords(struct bContext *C,
- FunctionRNA *func,
- const bool as_function,
- const bool all_args,
- const int max_prop_length);
+ bool as_function,
+ bool all_args,
+ bool nested_args,
+ int max_prop_length);
+char *RNA_function_as_string_keywords(
+ struct bContext *C, FunctionRNA *func, bool as_function, bool all_args, int max_prop_length);
/* Function */
@@ -1760,9 +1744,9 @@ bool RNA_struct_override_matches(struct Main *bmain,
struct PointerRNA *ptr_local,
struct PointerRNA *ptr_reference,
const char *root_path,
- const size_t root_path_len,
+ size_t root_path_len,
struct IDOverrideLibrary *override,
- const eRNAOverrideMatch flags,
+ eRNAOverrideMatch flags,
eRNAOverrideMatchResult *r_report_flags);
/**
@@ -1793,7 +1777,7 @@ void RNA_struct_override_apply(struct Main *bmain,
struct PointerRNA *ptr_src,
struct PointerRNA *ptr_storage,
struct IDOverrideLibrary *override,
- const eRNAOverrideApplyFlag flag);
+ eRNAOverrideApplyFlag flag);
struct IDOverrideLibraryProperty *RNA_property_override_property_find(struct Main *bmain,
PointerRNA *ptr,
@@ -1808,23 +1792,23 @@ struct IDOverrideLibraryPropertyOperation *RNA_property_override_property_operat
struct Main *bmain,
PointerRNA *ptr,
PropertyRNA *prop,
- const int index,
- const bool strict,
+ int index,
+ bool strict,
bool *r_strict);
struct IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_get(
struct Main *bmain,
PointerRNA *ptr,
PropertyRNA *prop,
- const short operation,
- const int index,
- const bool strict,
+ short operation,
+ int index,
+ bool strict,
bool *r_strict,
bool *r_created);
eRNAOverrideStatus RNA_property_override_library_status(struct Main *bmainm,
PointerRNA *ptr,
PropertyRNA *prop,
- const int index);
+ int index);
void RNA_struct_state_owner_set(const char *name);
const char *RNA_struct_state_owner_get(void);
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 3596a5f2234..ca534316c39 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -53,7 +53,7 @@ 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_define_lib_overridable(bool make_overridable);
void RNA_init(void);
void RNA_exit(void);
diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h
index 531af92c544..baa9ddba1be 100644
--- a/source/blender/makesrna/RNA_enum_items.h
+++ b/source/blender/makesrna/RNA_enum_items.h
@@ -72,6 +72,7 @@ DEF_ENUM(rna_enum_image_generated_type_items)
DEF_ENUM(rna_enum_normal_space_items)
DEF_ENUM(rna_enum_normal_swizzle_items)
DEF_ENUM(rna_enum_bake_save_mode_items)
+DEF_ENUM(rna_enum_bake_margin_type_items)
DEF_ENUM(rna_enum_bake_target_items)
DEF_ENUM(rna_enum_views_format_items)
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index da07f1043a7..fcae1009c8b 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -35,7 +35,9 @@ struct bNodeType;
#define DEF_ENUM(id) extern const EnumPropertyItem id[];
#include "RNA_enum_items.h"
-extern const EnumPropertyItem *rna_enum_attribute_domain_itemf(struct ID *id, bool *r_free);
+extern const EnumPropertyItem *rna_enum_attribute_domain_itemf(struct ID *id,
+ bool include_instances,
+ bool *r_free);
/**
* For ID filters (#FILTER_ID_AC, #FILTER_ID_AR, ...) an int isn't enough. This version allows 64
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index d880c892aa9..c5581c01921 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -240,7 +240,7 @@ typedef enum PropertyFlag {
PROP_ID_REFCOUNT = (1 << 6),
/**
- * Disallow assigning a variable to its self, eg an object tracking its self
+ * Disallow assigning a variable to itself, eg an object tracking itself
* only apply this to types that are derived from an ID ().
*/
PROP_ID_SELF_CHECK = (1 << 20),
@@ -265,7 +265,8 @@ typedef enum PropertyFlag {
* This is crucial information for processes that walk the whole data of an ID e.g.
* (like library override).
* Note that all ID pointers are enforced to this by default,
- * this probably will need to be rechecked (see ugly infamous NodeTrees of mat/tex/scene/etc.).
+ * this probably will need to be rechecked
+ * (see ugly infamous node-trees of material/texture/scene/etc.).
*/
PROP_PTR_NO_OWNERSHIP = (1 << 7),
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 7e6d0aea2ee..e3c89af6186 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -70,6 +70,7 @@ set(DEFSRC
rna_packedfile.c
rna_palette.c
rna_particle.c
+ rna_pointcloud.c
rna_pose.c
rna_render.c
rna_rigidbody.c
@@ -100,11 +101,9 @@ set(DEFSRC
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_SIMULATION_DATABLOCK)
- add_definitions(-DWITH_POINT_CLOUD)
add_definitions(-DWITH_HAIR_NODES)
list(APPEND DEFSRC
rna_hair.c
- rna_pointcloud.c
rna_simulation.c
)
endif()
@@ -203,6 +202,9 @@ set(INC
../../blenloader
${CMAKE_BINARY_DIR}/source/blender/makesdna/intern
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
)
set(INC_SYS
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index a6732ca1760..1e9cebbc3ea 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -4401,9 +4401,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_packedfile.c", NULL, RNA_def_packedfile},
{"rna_palette.c", NULL, RNA_def_palette},
{"rna_particle.c", NULL, RNA_def_particle},
-#ifdef WITH_POINT_CLOUD
{"rna_pointcloud.c", NULL, RNA_def_pointcloud},
-#endif
{"rna_pose.c", "rna_pose_api.c", RNA_def_pose},
{"rna_curveprofile.c", NULL, RNA_def_profile},
{"rna_lightprobe.c", NULL, RNA_def_lightprobe},
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index be612a1602b..264e89b2c2d 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -423,11 +423,9 @@ short RNA_type_to_ID_code(const StructRNA *type)
if (base_type == &RNA_PaintCurve) {
return ID_PC;
}
-# ifdef WITH_POINT_CLOUD
if (base_type == &RNA_PointCloud) {
return ID_PT;
}
-# endif
if (base_type == &RNA_LightProbe) {
return ID_LP;
}
@@ -533,11 +531,7 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_PC:
return &RNA_PaintCurve;
case ID_PT:
-# ifdef WITH_POINT_CLOUD
return &RNA_PointCloud;
-# else
- return &RNA_ID;
-# endif
case ID_LP:
return &RNA_LightProbe;
case ID_SCE:
@@ -1445,7 +1439,7 @@ static void rna_def_ID_properties(BlenderRNA *brna)
RNA_def_struct_refine_func(srna, "rna_PropertyGroup_refine");
/* important so python types can have their name used in list views
- * however this isn't prefect because it overrides how python would set the name
+ * however this isn't perfect because it overrides how python would set the name
* when we only really want this so RNA_def_struct_name_property() is set to something useful */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_flag(prop, PROP_IDPROPERTY);
@@ -1808,6 +1802,14 @@ static void rna_def_ID_override_library(BlenderRNA *brna)
RNA_def_pointer(
srna, "reference", "ID", "Reference ID", "Linked ID used as reference by this override");
+ prop = RNA_def_boolean(srna,
+ "is_in_hierarchy",
+ true,
+ "Is In Hierarchy",
+ "Whether this library override is defined as part of a library "
+ "hierarchy, or as a single, isolated and autonomous override");
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY);
+
prop = RNA_def_collection(srna,
"properties",
"IDOverrideLibraryProperty",
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index b64fa58cf6b..63eb016b5de 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -3260,10 +3260,10 @@ void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *val
rna_idproperty_touch(idprop);
}
else if (sprop->set) {
- sprop->set(ptr, value); /* set function needs to clamp its self */
+ sprop->set(ptr, value); /* set function needs to clamp itself */
}
else if (sprop->set_ex) {
- sprop->set_ex(ptr, prop, value); /* set function needs to clamp its self */
+ sprop->set_ex(ptr, prop, value); /* set function needs to clamp itself */
}
else if (prop->flag & PROP_EDITABLE) {
IDProperty *group;
@@ -3292,11 +3292,11 @@ void RNA_property_string_set_bytes(PointerRNA *ptr, PropertyRNA *prop, const cha
}
else if (sprop->set) {
/* XXX, should take length argument (currently not used). */
- sprop->set(ptr, value); /* set function needs to clamp its self */
+ sprop->set(ptr, value); /* set function needs to clamp itself */
}
else if (sprop->set_ex) {
/* XXX, should take length argument (currently not used). */
- sprop->set_ex(ptr, prop, value); /* set function needs to clamp its self */
+ sprop->set_ex(ptr, prop, value); /* set function needs to clamp itself */
}
else if (prop->flag & PROP_EDITABLE) {
IDProperty *group;
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index 8cc6a095c1d..950eccdb552 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -1059,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'",
@@ -1068,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'",
@@ -1081,15 +1088,24 @@ static void rna_porperty_override_collection_subitem_lookup(
static void rna_property_override_check_resync(Main *bmain,
PointerRNA *ptr_dst,
+ PointerRNA *ptr_src,
PointerRNA *ptr_item_dst,
PointerRNA *ptr_item_src)
{
- ID *id_owner = rna_property_override_property_real_id_owner(bmain, ptr_dst, NULL, NULL);
+ ID *id_owner_src = rna_property_override_property_real_id_owner(bmain, ptr_src, NULL, NULL);
+ ID *id_owner_dst = rna_property_override_property_real_id_owner(bmain, ptr_dst, NULL, NULL);
ID *id_src = rna_property_override_property_real_id_owner(bmain, ptr_item_src, NULL, NULL);
ID *id_dst = rna_property_override_property_real_id_owner(bmain, ptr_item_dst, NULL, NULL);
- BLI_assert(id_src == NULL || ID_IS_OVERRIDE_LIBRARY_REAL(id_src));
- /* Work around file corruption on writing, see T86853. */
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_owner_src));
+
+ /* If the owner ID is not part of an override hierarchy, there is no possible resync. */
+ if (id_owner_src->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY) {
+ return;
+ }
+
+ /* If `id_src` is not a liboverride, we cannot perform any further 'need resync' checks from
+ * here. */
if (id_src != NULL && !ID_IS_OVERRIDE_LIBRARY_REAL(id_src)) {
return;
}
@@ -1109,9 +1125,12 @@ static void rna_property_override_check_resync(Main *bmain,
* NOTE: Here we are testing if `id_owner` is referencing itself, in that case the new
* override copy generated by `BKE_lib_override_library_update` will already have its
* self-references updated to itself, instead of still pointing to its linked source. */
- (id_dst->lib == id_src->lib && id_dst != id_owner))) {
- ptr_dst->owner_id->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
- CLOG_INFO(&LOG, 3, "Local override %s detected as needing resync", ptr_dst->owner_id->name);
+ (id_dst->lib == id_src->lib && id_dst != id_owner_dst))) {
+ id_owner_dst->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
+ if (ID_IS_LINKED(id_owner_src)) {
+ id_owner_src->lib->tag |= LIBRARY_TAG_RESYNC_REQUIRED;
+ }
+ CLOG_INFO(&LOG, 3, "Local override %s detected as needing resync", id_owner_dst->name);
}
}
@@ -1228,7 +1247,8 @@ void RNA_struct_override_apply(Main *bmain,
PointerRNA prop_ptr_src = RNA_property_pointer_get(&data_src, prop_src);
PointerRNA prop_ptr_dst = RNA_property_pointer_get(&data_dst, prop_dst);
- rna_property_override_check_resync(bmain, ptr_dst, &prop_ptr_dst, &prop_ptr_src);
+ rna_property_override_check_resync(
+ bmain, ptr_dst, ptr_src, &prop_ptr_dst, &prop_ptr_src);
}
else if (op->rna_prop_type == PROP_COLLECTION) {
if (RNA_struct_is_ID(RNA_property_pointer_type(&data_src, prop_src))) {
@@ -1259,7 +1279,8 @@ void RNA_struct_override_apply(Main *bmain,
op,
opop);
- rna_property_override_check_resync(bmain, ptr_dst, ptr_item_dst, ptr_item_src);
+ rna_property_override_check_resync(
+ bmain, ptr_dst, ptr_src, ptr_item_dst, ptr_item_src);
}
}
}
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 96e37dfebbb..6b134977c5a 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -907,7 +907,7 @@ static void rna_def_action(BlenderRNA *brna)
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_range(prop, MINFRAME, MAXFRAME, 100, 2);
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);
@@ -916,7 +916,7 @@ static void rna_def_action(BlenderRNA *brna)
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_range(prop, MINFRAME, MAXFRAME, 100, 2);
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);
diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c
index 1511921cef0..0525d2f6fb1 100644
--- a/source/blender/makesrna/intern/rna_animviz.c
+++ b/source/blender/makesrna/intern/rna_animviz.c
@@ -207,6 +207,8 @@ static void rna_def_animviz_paths(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "Motion Path Settings", "Motion Path settings for animation visualization");
+ RNA_define_lib_overridable(true);
+
/* Enums */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "path_type");
@@ -301,6 +303,8 @@ static void rna_def_animviz_paths(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Has Motion Paths", "Are there any bone paths that will need updating (read-only)");
+
+ RNA_define_lib_overridable(false);
}
/* --- */
@@ -312,6 +316,7 @@ void rna_def_animviz_common(StructRNA *srna)
prop = RNA_def_property(srna, "animation_visualization", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "avs");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Animation Visualization", "Animation data for this data-block");
}
@@ -328,6 +333,7 @@ static void rna_def_animviz(BlenderRNA *brna)
/* motion path settings (nested struct) */
prop = RNA_def_property(srna, "motion_path", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_struct_type(prop, "AnimVizMotionPaths");
RNA_def_property_pointer_funcs(prop, "rna_AnimViz_motion_paths_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Motion Paths", "Motion Path settings for visualization");
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 7a934443907..28e50e80f32 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -993,7 +993,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
}
RNA_def_property_float_sdna(prop, NULL, "rad_head");
- /* XXX range is 0 to lim, where lim = 10000.0f * MAX2(1.0, view3d->grid); */
+ /* XXX range is 0 to limit, where limit = 10000.0f * MAX2(1.0, view3d->grid); */
// RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_range(prop, 0.01, 100, 0.1, 3);
RNA_def_property_ui_text(
@@ -1007,7 +1007,7 @@ static void rna_def_bone_common(StructRNA *srna, int editbone)
RNA_def_property_update(prop, 0, "rna_Armature_update_data");
}
RNA_def_property_float_sdna(prop, NULL, "rad_tail");
- /* XXX range is 0 to lim, where lim = 10000.0f * MAX2(1.0, view3d->grid); */
+ /* XXX range is 0 to limit, where limit = 10000.0f * MAX2(1.0, view3d->grid); */
// RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_range(prop, 0.01, 100, 0.1, 3);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.c
index a02f55667e3..7d165ce045d 100644
--- a/source/blender/makesrna/intern/rna_armature_api.c
+++ b/source/blender/makesrna/intern/rna_armature_api.c
@@ -119,7 +119,7 @@ void RNA_api_armature_edit_bone(StructRNA *srna)
func = RNA_def_function(srna, "align_roll", "rna_EditBone_align_roll");
RNA_def_function_ui_description(func,
- "Align the bone to a localspace roll so the Z axis "
+ "Align the bone to a local-space roll so the Z axis "
"points in the direction of the vector given");
parm = RNA_def_float_vector(
func, "vector", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index 78c15444308..35da353a043 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -166,7 +166,9 @@ static int rna_Attribute_type_get(PointerRNA *ptr)
return layer->type;
}
-const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id, bool *r_free)
+const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id,
+ bool include_instances,
+ bool *r_free)
{
EnumPropertyItem *item = NULL;
const EnumPropertyItem *domain_item = NULL;
@@ -188,6 +190,9 @@ const EnumPropertyItem *rna_enum_attribute_domain_itemf(ID *id, bool *r_free)
if (id_type == ID_ME && ELEM(domain_item->value, ATTR_DOMAIN_CURVE)) {
continue;
}
+ if (!include_instances && domain_item->value == ATTR_DOMAIN_INSTANCE) {
+ continue;
+ }
if (domain_item->value == ATTR_DOMAIN_POINT && id_type == ID_ME) {
RNA_enum_item_add(&item, &totitem, &mesh_vertex_domain_item);
@@ -207,7 +212,7 @@ static const EnumPropertyItem *rna_Attribute_domain_itemf(bContext *UNUSED(C),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
- return rna_enum_attribute_domain_itemf(ptr->owner_id, r_free);
+ return rna_enum_attribute_domain_itemf(ptr->owner_id, true, r_free);
}
static int rna_Attribute_domain_get(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c
index 74d924b8937..2f8fc004d85 100644
--- a/source/blender/makesrna/intern/rna_cachefile.c
+++ b/source/blender/makesrna/intern/rna_cachefile.c
@@ -32,6 +32,7 @@
#ifdef RNA_RUNTIME
+# include "BLI_math.h"
# include "BLI_string.h"
# include "BKE_cachefile.h"
@@ -54,6 +55,14 @@ static void rna_CacheFile_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
+static void rna_CacheFileLayer_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+
+ DEG_id_tag_update(&cache_file->id, ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+}
+
static void rna_CacheFile_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
rna_CacheFile_update(bmain, scene, ptr);
@@ -66,6 +75,91 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P
rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL);
}
+static PointerRNA rna_CacheFile_active_layer_get(PointerRNA *ptr)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+ return rna_pointer_inherit_refine(
+ ptr, &RNA_CacheFileLayer, BKE_cachefile_get_active_layer(cache_file));
+}
+
+static void rna_CacheFile_active_layer_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *reports)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+ int index = BLI_findindex(&cache_file->layers, value.data);
+ if (index == -1) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Layer '%s' not found in object '%s'",
+ ((CacheFileLayer *)value.data)->filepath,
+ cache_file->id.name + 2);
+ return;
+ }
+
+ cache_file->active_layer = index + 1;
+}
+
+static int rna_CacheFile_active_layer_index_get(PointerRNA *ptr)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+ return cache_file->active_layer - 1;
+}
+
+static void rna_CacheFile_active_layer_index_set(PointerRNA *ptr, int value)
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+ cache_file->active_layer = value + 1;
+}
+
+static void rna_CacheFile_active_layer_index_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ CacheFile *cache_file = (CacheFile *)ptr->owner_id;
+
+ *min = 0;
+ *max = max_ii(0, BLI_listbase_count(&cache_file->layers) - 1);
+}
+
+static void rna_CacheFileLayer_hidden_flag_set(PointerRNA *ptr, const bool value)
+{
+ CacheFileLayer *layer = (CacheFileLayer *)ptr->data;
+
+ if (value) {
+ layer->flag |= CACHEFILE_LAYER_HIDDEN;
+ }
+ else {
+ layer->flag &= ~CACHEFILE_LAYER_HIDDEN;
+ }
+}
+
+static CacheFileLayer *rna_CacheFile_layer_new(CacheFile *cache_file,
+ bContext *C,
+ ReportList *reports,
+ const char *filepath)
+{
+ CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filepath);
+ if (layer == NULL) {
+ BKE_reportf(
+ reports, RPT_ERROR, "Cannot add a layer to CacheFile '%s'", cache_file->id.name + 2);
+ return NULL;
+ }
+
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ BKE_cachefile_reload(depsgraph, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ return layer;
+}
+
+static void rna_CacheFile_layer_remove(CacheFile *cache_file, bContext *C, PointerRNA *layer_ptr)
+{
+ CacheFileLayer *layer = layer_ptr->data;
+ BKE_cachefile_remove_layer(cache_file, layer);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ BKE_cachefile_reload(depsgraph, cache_file);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+}
+
#else
/* cachefile.object_paths */
@@ -94,6 +188,61 @@ static void rna_def_cachefile_object_paths(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_struct_ui_text(srna, "Object Paths", "Collection of object paths");
}
+static void rna_def_cachefile_layer(BlenderRNA *brna)
+{
+ StructRNA *srna = RNA_def_struct(brna, "CacheFileLayer", NULL);
+ RNA_def_struct_sdna(srna, "CacheFileLayer");
+ RNA_def_struct_ui_text(
+ srna,
+ "Cache Layer",
+ "Layer of the cache, used to load or override data from the first the first layer");
+
+ PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_ui_text(prop, "File Path", "Path to the archive");
+ RNA_def_property_update(prop, 0, "rna_CacheFileLayer_update");
+
+ prop = RNA_def_property(srna, "hide_layer", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CACHEFILE_LAYER_HIDDEN);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_CacheFileLayer_hidden_flag_set");
+ RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
+ RNA_def_property_ui_text(prop, "Hide Layer", "Do not load data from this layer");
+ RNA_def_property_update(prop, 0, "rna_CacheFileLayer_update");
+}
+
+static void rna_def_cachefile_layers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ RNA_def_property_srna(cprop, "CacheFileLayers");
+ StructRNA *srna = RNA_def_struct(brna, "CacheFileLayers", NULL);
+ RNA_def_struct_sdna(srna, "CacheFile");
+ RNA_def_struct_ui_text(srna, "Cache Layers", "Collection of cache layers");
+
+ PropertyRNA *prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "CacheFileLayer");
+ RNA_def_property_pointer_funcs(
+ prop, "rna_CacheFile_active_layer_get", "rna_CacheFile_active_layer_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Active Layer", "Active layer of the CacheFile");
+
+ /* Add a layer. */
+ FunctionRNA *func = RNA_def_function(srna, "new", "rna_CacheFile_layer_new");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Add a new layer");
+ PropertyRNA *parm = RNA_def_string(
+ func, "filepath", "File Path", 0, "", "File path to the archive used as a layer");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* Return type. */
+ parm = RNA_def_pointer(func, "layer", "CacheFileLayer", "", "Newly created layer");
+ RNA_def_function_return(func, parm);
+
+ /* Remove a layer. */
+ func = RNA_def_function(srna, "remove", "rna_CacheFile_layer_remove");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Remove an existing layer from the cache file");
+ parm = RNA_def_pointer(func, "layer", "CacheFileLayer", "", "Layer to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+}
+
static void rna_def_cachefile(BlenderRNA *brna)
{
StructRNA *srna = RNA_def_struct(brna, "CacheFile", "ID");
@@ -234,6 +383,23 @@ static void rna_def_cachefile(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_CacheFile_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ /* ----------------- Alembic Layers ----------------- */
+
+ prop = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "layers", NULL);
+ RNA_def_property_struct_type(prop, "CacheFileLayer");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Cache Layers", "Layers of the cache");
+ rna_def_cachefile_layers(brna, prop);
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_int_sdna(prop, NULL, "active_layer");
+ RNA_def_property_int_funcs(prop,
+ "rna_CacheFile_active_layer_index_get",
+ "rna_CacheFile_active_layer_index_set",
+ "rna_CacheFile_active_layer_index_range");
+
RNA_define_lib_overridable(false);
rna_def_cachefile_object_paths(brna, prop);
@@ -245,6 +411,7 @@ void RNA_def_cachefile(BlenderRNA *brna)
{
rna_def_cachefile(brna);
rna_def_alembic_object_path(brna);
+ rna_def_cachefile_layer(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index 2bc00dd5af5..187e232b030 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -584,6 +584,8 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ClothSimSettings");
RNA_def_struct_path_func(srna, "rna_ClothSettings_path");
+ RNA_define_lib_overridable(true);
+
/* goal */
prop = RNA_def_property(srna, "goal_min", PROP_FLOAT, PROP_FACTOR);
@@ -659,6 +661,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_mass_vgroup_get",
"rna_ClothSettings_mass_vgroup_length",
"rna_ClothSettings_mass_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Mass Vertex Group", "Vertex Group for pinning of vertices");
RNA_def_property_update(prop, 0, "rna_cloth_pinning_changed");
@@ -707,6 +710,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_shrink_vgroup_get",
"rna_ClothSettings_shrink_vgroup_length",
"rna_ClothSettings_shrink_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Shrink Vertex Group", "Vertex Group for shrinking cloth");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -810,6 +814,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_struct_vgroup_get",
"rna_ClothSettings_struct_vgroup_length",
"rna_ClothSettings_struct_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop,
"Structural Stiffness Vertex Group",
"Vertex group for fine control over structural stiffness");
@@ -820,6 +825,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_shear_vgroup_get",
"rna_ClothSettings_shear_vgroup_length",
"rna_ClothSettings_shear_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop, "Shear Stiffness Vertex Group", "Vertex group for fine control over shear stiffness");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -856,6 +862,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_bend_vgroup_get",
"rna_ClothSettings_bend_vgroup_length",
"rna_ClothSettings_bend_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop,
"Bending Stiffness Vertex Group",
"Vertex group for fine control over bending stiffness");
@@ -874,6 +881,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_rest_shape_key_set",
NULL,
NULL);
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop, "Rest Shape Key", "Shape key to use the rest spring lengths from");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -976,6 +984,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_internal_vgroup_get",
"rna_ClothSettings_internal_vgroup_length",
"rna_ClothSettings_internal_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop,
"Internal Springs Vertex Group",
"Vertex group for fine control over the internal spring stiffness");
@@ -1044,6 +1053,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_pressure_vgroup_get",
"rna_ClothSettings_pressure_vgroup_length",
"rna_ClothSettings_pressure_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop,
"Pressure Vertex Group",
@@ -1082,6 +1092,8 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Maximum Spring Extension", "Maximum extension before spring gets cut");
# endif
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_cloth_collision_settings(BlenderRNA *brna)
@@ -1097,6 +1109,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ClothCollSettings");
RNA_def_struct_path_func(srna, "rna_ClothCollisionSettings_path");
+ RNA_define_lib_overridable(true);
+
/* general collision */
prop = RNA_def_property(srna, "use_collision", PROP_BOOLEAN, PROP_NONE);
@@ -1169,7 +1183,6 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "group");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Collision Collection", "Limit colliders to this Collection");
RNA_def_property_update(prop, 0, "rna_cloth_dependency_update");
@@ -1178,6 +1191,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
"rna_CollSettings_selfcol_vgroup_get",
"rna_CollSettings_selfcol_vgroup_length",
"rna_CollSettings_selfcol_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop,
"Selfcollision Vertex Group",
@@ -1189,6 +1203,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
"rna_CollSettings_objcol_vgroup_get",
"rna_CollSettings_objcol_vgroup_length",
"rna_CollSettings_objcol_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop,
"Collision Vertex Group",
@@ -1203,6 +1218,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
"Impulse Clamping",
"Clamp collision impulses to avoid instability (0.0 to disable clamping)");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ RNA_define_lib_overridable(false);
}
void RNA_def_cloth(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 5c12fc3a227..b12ec4651b4 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -26,6 +26,8 @@
#include "BLI_utildefines.h"
+#include "BKE_node_tree_update.h"
+
#include "RNA_define.h"
#include "rna_internal.h"
@@ -321,7 +323,8 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
CMP_NODE_VALTORGB,
TEX_NODE_VALTORGB,
GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP)) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
}
break;
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 6cca0c51988..86ed0f307c4 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -453,8 +453,8 @@ static void rna_Curve_bevelObject_set(PointerRNA *ptr,
Object *ob = (Object *)value.data;
if (ob) {
- /* if bevel object has got the save curve, as object, for which it's */
- /* set as bevobj, there could be infinity loop in displist calculation */
+ /* If bevel object has got the save curve, as object, for which it's set as bevobj,
+ * there could be infinity loop in #DispList calculation. */
if (ob->type == OB_CURVE && ob->data != cu) {
cu->bevobj = ob;
id_lib_extern((ID *)ob);
@@ -528,8 +528,8 @@ static void rna_Curve_taperObject_set(PointerRNA *ptr,
Object *ob = (Object *)value.data;
if (ob) {
- /* if taper object has got the save curve, as object, for which it's */
- /* set as bevobj, there could be infinity loop in displist calculation */
+ /* If taper object has got the save curve, as object, for which it's set as bevobj,
+ * there could be infinity loop in #DispList calculation. */
if (ob->type == OB_CURVE && ob->data != cu) {
cu->taperobj = ob;
id_lib_extern((ID *)ob);
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index a9d5ef089bb..b693d78a302 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -589,6 +589,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
prop = RNA_def_property(srna, "drip_velocity", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index a38bbd3d6d2..0e2b64fbca4 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -388,6 +388,7 @@ void rna_DriverVariable_name_set(PointerRNA *ptr, const char *value)
BLI_strncpy_utf8(data->name, value, 64);
driver_variable_name_validate(data);
+ driver_variable_unique_name(data);
}
/* ----------- */
@@ -1013,7 +1014,7 @@ static void rna_FKeyframe_points_add(ID *id, FCurve *fcu, Main *bmain, int tot)
fcu->totvert += tot;
while (tot--) {
- /* defaults, no userprefs gives predictable results for API */
+ /* Defaults, ignoring user-preference gives predictable results for API. */
bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
bezt->ipo = BEZT_IPO_BEZ;
bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index 90e77406f23..7aa96eb8430 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -1461,6 +1461,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
/* object collections */
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index e06aac31124..e4e594cd8cf 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -3211,6 +3211,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
prop, "Boundaries", "Filter feature lines based on face mark boundaries");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "use_face_mark_keep_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "calculation_flags", LRT_FILTER_FACE_MARK_KEEP_CONTOUR);
+ RNA_def_property_ui_text(prop, "Keep Contour", "Preserve contour lines while filtering");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "chaining_image_threshold", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_ui_text(
prop,
@@ -3231,6 +3237,12 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
prop, "Use Geometry Space", "Use geometry distance for chaining instead of image space");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "use_detail_preserve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_CHAIN_PRESERVE_DETAILS);
+ RNA_def_property_ui_text(
+ prop, "Preserve Details", "Keep the zig-zag \"noise\" in initial chaining");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "use_overlap_edge_type_support", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_ALLOW_OVERLAP_EDGE_TYPES);
RNA_def_property_ui_text(prop,
@@ -3444,6 +3456,21 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
prop,
"Image Boundary Trimming",
"Trim all edges right at the boundary of image(including overscan region)");
+
+ prop = RNA_def_property(srna, "use_back_face_culling", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_USE_BACK_FACE_CULLING);
+ RNA_def_property_ui_text(
+ prop,
+ "Back Face Culling",
+ "Remove all back faces to speed up calculation, this will create edges in "
+ "different occlusion levels than when disabled");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_invert_collection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_INVERT_COLLECTION);
+ RNA_def_property_ui_text(prop,
+ "Invert Collection Filtering",
+ "Select everything except lines from specified collection");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
RNA_define_lib_overridable(false);
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 2f42e521b52..0d86572357f 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -168,7 +168,7 @@ static void rna_ImageUser_update(Main *bmain, Scene *scene, PointerRNA *ptr)
if (id) {
if (GS(id->name) == ID_NT) {
/* Special update for nodetrees to find parent datablock. */
- ED_node_tag_update_nodetree(bmain, (bNodeTree *)id, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, NULL);
}
else {
/* Update material or texture for render preview. */
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 7d2697c8770..1c04805be8b 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -243,7 +243,7 @@ static int rna_Image_gl_touch(
BKE_image_tag_time(image);
- if (image->gputexture[TEXTARGET_2D][0] == NULL) {
+ if (image->gputexture[TEXTARGET_2D][0][IMA_TEXTURE_RESOLUTION_FULL] == NULL) {
error = rna_Image_gl_load(image, reports, frame, layer_index, pass_index);
}
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index c1989a5b10d..4687e86916e 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -240,9 +240,9 @@ bool rna_AnimaData_override_apply(struct Main *bmain,
struct PropertyRNA *prop_local,
struct PropertyRNA *prop_reference,
struct PropertyRNA *prop_storage,
- const int len_local,
- const int len_reference,
- const int len_storage,
+ int len_local,
+ int len_reference,
+ int len_storage,
struct PointerRNA *ptr_item_local,
struct PointerRNA *ptr_item_reference,
struct PointerRNA *ptr_item_storage,
@@ -268,7 +268,7 @@ void rna_def_mtex_common(struct BlenderRNA *brna,
const char *update,
const char *update_index);
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);
+void rna_def_view_layer_common(struct BlenderRNA *brna, struct StructRNA *srna, bool scene);
int rna_AssetMetaData_editable(struct PointerRNA *ptr, const char **r_info);
/**
@@ -446,7 +446,7 @@ void RNA_api_space_text(struct StructRNA *srna);
void RNA_api_space_filebrowser(struct StructRNA *srna);
void RNA_api_region_view3d(struct StructRNA *srna);
void RNA_api_texture(struct StructRNA *srna);
-void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastrip);
+void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, bool metastrip);
void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_api_sound(struct StructRNA *srna);
void RNA_api_vfont(struct StructRNA *srna);
@@ -491,9 +491,7 @@ void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop);
#ifdef WITH_HAIR_NODES
void RNA_def_main_hairs(BlenderRNA *brna, PropertyRNA *cprop);
#endif
-#ifdef WITH_POINT_CLOUD
void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop);
-#endif
void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop);
#ifdef WITH_SIMULATION_DATABLOCK
void RNA_def_main_simulations(BlenderRNA *brna, PropertyRNA *cprop);
@@ -541,11 +539,11 @@ struct PropertyRNA *rna_ensure_property(struct PropertyRNA *prop) ATTR_WARN_UNUS
int rna_property_override_diff_default(struct Main *bmain,
struct PropertyRNAOrID *prop_a,
struct PropertyRNAOrID *prop_b,
- const int mode,
+ int mode,
struct IDOverrideLibrary *override,
const char *rna_path,
- const size_t rna_path_len,
- const int flags,
+ size_t rna_path_len,
+ int flags,
bool *r_override_changed);
bool rna_property_override_store_default(struct Main *bmain,
@@ -555,9 +553,9 @@ bool rna_property_override_store_default(struct Main *bmain,
struct PropertyRNA *prop_local,
struct PropertyRNA *prop_reference,
struct PropertyRNA *prop_storage,
- const int len_local,
- const int len_reference,
- const int len_storage,
+ int len_local,
+ int len_reference,
+ int len_storage,
struct IDOverrideLibraryPropertyOperation *opop);
bool rna_property_override_apply_default(struct Main *bmain,
@@ -567,9 +565,9 @@ bool rna_property_override_apply_default(struct Main *bmain,
struct PropertyRNA *prop_dst,
struct PropertyRNA *prop_src,
struct PropertyRNA *prop_storage,
- const int len_dst,
- const int len_src,
- const int len_storage,
+ int len_dst,
+ int len_src,
+ int len_storage,
struct PointerRNA *ptr_item_dst,
struct PointerRNA *ptr_item_src,
struct PointerRNA *ptr_item_storage,
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 29df7a53c44..723ae384fdf 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -211,11 +211,11 @@ typedef struct PropertyRNAOrID {
typedef int (*RNAPropOverrideDiff)(struct Main *bmain,
struct PropertyRNAOrID *prop_a,
struct PropertyRNAOrID *prop_b,
- const int mode,
+ int mode,
struct IDOverrideLibrary *override,
const char *rna_path,
- const size_t rna_path_len,
- const int flags,
+ size_t rna_path_len,
+ int flags,
bool *r_override_changed);
/**
@@ -235,9 +235,9 @@ typedef bool (*RNAPropOverrideStore)(struct Main *bmain,
struct PropertyRNA *prop_local,
struct PropertyRNA *prop_reference,
struct PropertyRNA *prop_storage,
- const int len_local,
- const int len_reference,
- const int len_storage,
+ int len_local,
+ int len_reference,
+ int len_storage,
struct IDOverrideLibraryPropertyOperation *opop);
/**
@@ -254,9 +254,9 @@ typedef bool (*RNAPropOverrideApply)(struct Main *bmain,
struct PropertyRNA *prop_dst,
struct PropertyRNA *prop_src,
struct PropertyRNA *prop_storage,
- const int len_dst,
- const int len_src,
- const int len_storage,
+ int len_dst,
+ int len_src,
+ int len_storage,
struct PointerRNA *ptr_item_dst,
struct PointerRNA *ptr_item_src,
struct PointerRNA *ptr_item_storage,
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index ab4cbc429ce..b02a5c8dc1e 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -53,6 +53,8 @@
# include "BKE_node.h"
# include "BKE_scene.h"
+# include "NOD_composite.h"
+
# include "BLI_listbase.h"
# include "DEG_depsgraph_build.h"
diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c
index 8bec337885e..003eebd8cc8 100644
--- a/source/blender/makesrna/intern/rna_light.c
+++ b/source/blender/makesrna/intern/rna_light.c
@@ -360,7 +360,7 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SHAD_CONTACT);
RNA_def_property_ui_text(prop,
"Contact Shadow",
- "Use screen space raytracing to have correct shadowing "
+ "Use screen space ray-tracing to have correct shadowing "
"near occluder, or for small features that does not appear "
"in shadow maps");
RNA_def_property_update(prop, 0, "rna_Light_update");
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 93d7059d2a6..57a2a867d0a 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)
@@ -128,9 +129,7 @@ RNA_MAIN_LISTBASE_FUNCS_DEF(objects)
RNA_MAIN_LISTBASE_FUNCS_DEF(paintcurves)
RNA_MAIN_LISTBASE_FUNCS_DEF(palettes)
RNA_MAIN_LISTBASE_FUNCS_DEF(particles)
-# ifdef WITH_POINT_CLOUD
RNA_MAIN_LISTBASE_FUNCS_DEF(pointclouds)
-# endif
RNA_MAIN_LISTBASE_FUNCS_DEF(scenes)
RNA_MAIN_LISTBASE_FUNCS_DEF(screens)
RNA_MAIN_LISTBASE_FUNCS_DEF(shapekeys)
@@ -393,14 +392,12 @@ void RNA_def_main(BlenderRNA *brna)
# ifdef WITH_HAIR_NODES
{"hairs", "Hair", "rna_Main_hairs_begin", "Hairs", "Hair data-blocks", RNA_def_main_hairs},
# endif
-# ifdef WITH_POINT_CLOUD
{"pointclouds",
"PointCloud",
"rna_Main_pointclouds_begin",
"Point Clouds",
"Point cloud data-blocks",
RNA_def_main_pointclouds},
-# endif
{"volumes",
"Volume",
"rna_Main_volumes_begin",
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 0276c8a3f8a..4344ed0dff5 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -778,7 +778,6 @@ static Hair *rna_Main_hairs_new(Main *bmain, const char *name)
}
# endif
-# ifdef WITH_POINT_CLOUD
static PointCloud *rna_Main_pointclouds_new(Main *bmain, const char *name)
{
char safe_name[MAX_ID_NAME - 2];
@@ -791,7 +790,6 @@ static PointCloud *rna_Main_pointclouds_new(Main *bmain, const char *name)
return pointcloud;
}
-# endif
static Volume *rna_Main_volumes_new(Main *bmain, const char *name)
{
@@ -866,9 +864,7 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(lightprobes, lightprobes, ID_LP)
# ifdef WITH_HAIR_NODES
RNA_MAIN_ID_TAG_FUNCS_DEF(hairs, hairs, ID_HA)
# endif
-# ifdef WITH_POINT_CLOUD
RNA_MAIN_ID_TAG_FUNCS_DEF(pointclouds, pointclouds, ID_PT)
-# endif
RNA_MAIN_ID_TAG_FUNCS_DEF(volumes, volumes, ID_VO)
# ifdef WITH_SIMULATION_DATABLOCK
RNA_MAIN_ID_TAG_FUNCS_DEF(simulations, simulations, ID_SIM)
@@ -2319,7 +2315,6 @@ void RNA_def_main_hairs(BlenderRNA *brna, PropertyRNA *cprop)
}
# endif
-# ifdef WITH_POINT_CLOUD
void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -2366,7 +2361,6 @@ void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_boolean(func, "value", 0, "Value", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
-# endif
void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop)
{
diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c
index 9c90c209389..21bacf2e6be 100644
--- a/source/blender/makesrna/intern/rna_mask.c
+++ b/source/blender/makesrna/intern/rna_mask.c
@@ -23,6 +23,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_mask_types.h"
#include "DNA_object_types.h" /* SELECT */
#include "DNA_scene_types.h"
@@ -84,7 +85,7 @@ static void rna_Mask_update_parent(Main *bmain, Scene *scene, PointerRNA *ptr)
if (track) {
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_framenr);
float marker_pos_ofs[2], parmask_pos[2];
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
BKE_movieclip_user_set_frame(&user, scene->r.cfra);
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 5a937e6b06b..55b70fd1b41 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -317,18 +317,26 @@ static void rna_Mesh_update_facemask(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_MeshVertex_normal_get(PointerRNA *ptr, float *value)
{
- MVert *mvert = (MVert *)ptr->data;
- normal_short_to_float_v3(value, mvert->no);
+ Mesh *mesh = rna_mesh(ptr);
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+
+ const int index = (MVert *)ptr->data - mesh->mvert;
+ BLI_assert(index >= 0);
+ BLI_assert(index < mesh->totvert);
+
+ copy_v3_v3(value, vert_normals[index]);
}
static void rna_MeshVertex_normal_set(PointerRNA *ptr, const float *value)
{
- MVert *mvert = (MVert *)ptr->data;
- float no[3];
+ Mesh *mesh = rna_mesh(ptr);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
+
+ const int index = (MVert *)ptr->data - mesh->mvert;
+ BLI_assert(index >= 0);
+ BLI_assert(index < mesh->totvert);
- copy_v3_v3(no, value);
- normalize_v3(no);
- normal_float_to_short_v3(mvert->no, no);
+ copy_v3_v3(vert_normals[index], value);
}
static float rna_MeshVertex_bevel_weight_get(PointerRNA *ptr)
@@ -976,6 +984,30 @@ static int rna_MeshSkinVertexLayer_data_length(PointerRNA *ptr)
/* End skin vertices */
+/* Vertex creases */
+DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_crease, vdata, CD_CREASE)
+
+static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collection, int type);
+static char *rna_MeshVertexCreaseLayer_path(PointerRNA *ptr)
+{
+ return rna_VertCustomData_data_path(ptr, "vertex_creases", CD_CREASE);
+}
+
+static void rna_MeshVertexCreaseLayer_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
+ rna_iterator_array_begin(iter, layer->data, sizeof(float), me->totvert, 0, NULL);
+}
+
+static int rna_MeshVertexCreaseLayer_data_length(PointerRNA *ptr)
+{
+ Mesh *me = rna_mesh(ptr);
+ return me->totvert;
+}
+
+/* End vertex creases */
+
/* Paint mask */
DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_paint_mask, vdata, CD_PAINT_MASK)
@@ -1280,6 +1312,32 @@ static char *rna_LoopCustomData_data_path(PointerRNA *ptr, const char *collectio
return NULL;
}
+static void rna_Mesh_vertex_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ const Mesh *mesh = rna_mesh(ptr);
+ const float(*normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ rna_iterator_array_begin(iter, (void *)normals, sizeof(float[3]), mesh->totvert, false, NULL);
+}
+
+static int rna_Mesh_vertex_normals_length(PointerRNA *ptr)
+{
+ const Mesh *mesh = rna_mesh(ptr);
+ return mesh->totvert;
+}
+
+static void rna_Mesh_poly_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ const Mesh *mesh = rna_mesh(ptr);
+ const float(*normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
+ rna_iterator_array_begin(iter, (void *)normals, sizeof(float[3]), mesh->totpoly, false, NULL);
+}
+
+static int rna_Mesh_poly_normals_length(PointerRNA *ptr)
+{
+ const Mesh *mesh = rna_mesh(ptr);
+ return mesh->totpoly;
+}
+
static char *rna_MeshUVLoop_path(PointerRNA *ptr)
{
return rna_LoopCustomData_data_path(ptr, "uv_layers", CD_MLOOPUV);
@@ -1641,6 +1699,7 @@ static void UNUSED_FUNCTION(rna_mesh_unused)(void)
(void)rna_Mesh_face_map_active_index_set;
(void)rna_Mesh_face_map_active_index_get;
(void)rna_Mesh_face_map_active_set;
+ (void)rna_Mesh_vertex_crease_index_range;
/* end unused function block */
}
@@ -2512,6 +2571,20 @@ static void rna_def_mesh_polygons(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
+/* Defines a read-only vector type since normals should not be modified manually. */
+static void rna_def_normal_layer_value(BlenderRNA *brna)
+{
+ StructRNA *srna = RNA_def_struct(brna, "MeshNormalValue", NULL);
+ RNA_def_struct_sdna(srna, "vec3f");
+ RNA_def_struct_ui_text(srna, "Mesh Normal Vector", "Vector in a mesh normal array");
+
+ PropertyRNA *prop = RNA_def_property(srna, "vector", PROP_FLOAT, PROP_DIRECTION);
+ RNA_def_property_ui_text(prop, "Vector", "3D vector");
+ RNA_def_property_float_sdna(prop, NULL, "x");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+}
+
static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -2859,6 +2932,40 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
+static void rna_def_vertex_creases(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "MeshVertexCreaseLayer", NULL);
+ RNA_def_struct_ui_text(srna, "Mesh Vertex Crease Layer", "Per-vertex crease");
+ RNA_def_struct_sdna(srna, "CustomDataLayer");
+ RNA_def_struct_path_func(srna, "rna_MeshVertexCreaseLayer_path");
+
+ prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshVertexCrease");
+ RNA_def_property_ui_text(prop, "Data", "");
+ RNA_def_property_collection_funcs(prop,
+ "rna_MeshVertexCreaseLayer_data_begin",
+ "rna_iterator_array_next",
+ "rna_iterator_array_end",
+ "rna_iterator_array_get",
+ "rna_MeshVertexCreaseLayer_data_length",
+ NULL,
+ NULL,
+ NULL);
+
+ /* VertexCrease struct */
+ srna = RNA_def_struct(brna, "MeshVertexCrease", NULL);
+ RNA_def_struct_sdna(srna, "MFloatProperty");
+ RNA_def_struct_ui_text(srna, "Float Property", "");
+
+ prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "f");
+ RNA_def_property_ui_text(prop, "Value", "");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
+}
+
static void rna_def_paint_mask(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
{
StructRNA *srna;
@@ -3009,6 +3116,42 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Polygons", "Polygons of the mesh");
rna_def_mesh_polygons(brna, prop);
+ rna_def_normal_layer_value(brna);
+
+ prop = RNA_def_property(srna, "vertex_normals", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshNormalValue");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
+ RNA_def_property_ui_text(prop,
+ "Vertex Normals",
+ "The normal direction of each vertex, defined as the average of the "
+ "surrounding face normals");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Mesh_vertex_normals_begin",
+ "rna_iterator_array_next",
+ "rna_iterator_array_end",
+ "rna_iterator_array_get",
+ "rna_Mesh_vertex_normals_length",
+ NULL,
+ NULL,
+ NULL);
+
+ prop = RNA_def_property(srna, "polygon_normals", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshNormalValue");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
+ RNA_def_property_ui_text(prop,
+ "Polygon Normals",
+ "The normal direction of each polygon, defined by the winding order "
+ "and position of its vertices");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Mesh_poly_normals_begin",
+ "rna_iterator_array_next",
+ "rna_iterator_array_end",
+ "rna_iterator_array_get",
+ "rna_Mesh_poly_normals_length",
+ NULL,
+ NULL,
+ NULL);
+
prop = RNA_def_property(srna, "loop_triangles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "runtime.looptris.array", "runtime.looptris.len");
RNA_def_property_struct_type(prop, "MeshLoopTriangle");
@@ -3016,7 +3159,7 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Loop Triangles", "Tessellation of mesh polygons into triangles");
rna_def_mesh_looptris(brna, prop);
- /* TODO: should this be allowed to be its self? */
+ /* TODO: should this be allowed to be itself? */
prop = RNA_def_property(srna, "texture_mesh", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "texcomesh");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
@@ -3105,6 +3248,7 @@ static void rna_def_mesh(BlenderRNA *brna)
NULL,
NULL);
RNA_def_property_struct_type(prop, "MeshVertColorLayer");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
RNA_def_property_ui_text(prop, "Sculpt Vertex Colors", "All vertex colors");
rna_def_vert_colors(brna, prop);
@@ -3240,6 +3384,24 @@ static void rna_def_mesh(BlenderRNA *brna)
rna_def_skin_vertices(brna, prop);
/* End skin vertices */
+ /* Vertex Crease */
+ prop = RNA_def_property(srna, "vertex_creases", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "MeshVertexCreaseLayer");
+ RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Mesh_vertex_creases_begin",
+ NULL,
+ NULL,
+ NULL,
+ "rna_Mesh_vertex_creases_length",
+ NULL,
+ NULL,
+ NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
+ RNA_def_property_ui_text(prop, "Vertex Creases", "Sharpness of the vertices");
+ rna_def_vertex_creases(brna);
+ /* End vertex crease */
+
/* Paint mask */
prop = RNA_def_property(srna, "vertex_paint_masks", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer");
@@ -3437,6 +3599,10 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_EDGE_BWEIGHT);
RNA_def_property_ui_text(prop, "Store Edge Bevel Weight", "");
+ prop = RNA_def_property(srna, "use_customdata_vertex_crease", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_VERT_CREASE);
+ RNA_def_property_ui_text(prop, "Store Vertex Crease", "");
+
prop = RNA_def_property(srna, "use_customdata_edge_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_EDGE_CREASE);
RNA_def_property_ui_text(prop, "Store Edge Crease", "");
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index d46ae13b482..957b92f204a 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -331,7 +331,12 @@ const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[] = {
"SHORTEST_DIAGONAL",
0,
"Shortest Diagonal",
- "Split the quads based on the distance between the vertices"},
+ "Split the quads along their shortest diagonal"},
+ {MOD_TRIANGULATE_QUAD_LONGEDGE,
+ "LONGEST_DIAGONAL",
+ 0,
+ "Longest Diagonal",
+ "Split the quads along their longest diagonal"},
{0, NULL, 0, NULL, NULL},
};
@@ -1736,7 +1741,7 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_creases", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", eSubsurfModifierFlag_UseCrease);
RNA_def_property_ui_text(
- prop, "Use Creases", "Use mesh edge crease information to sharpen edges");
+ prop, "Use Creases", "Use mesh crease information to sharpen edges or corners");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_custom_normals", PROP_BOOLEAN, PROP_NONE);
@@ -1951,7 +1956,7 @@ static void rna_def_modifier_multires(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_creases", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", eMultiresModifierFlag_UseCrease);
RNA_def_property_ui_text(
- prop, "Use Creases", "Use mesh edge crease information to sharpen edges");
+ prop, "Use Creases", "Use mesh crease information to sharpen edges or corners");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_custom_normals", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index df0271d81d5..38a447a9657 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -42,6 +42,7 @@
#include "BKE_geometry_set.h"
#include "BKE_image.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_texture.h"
#include "RNA_access.h"
@@ -51,6 +52,7 @@
#include "rna_internal.h"
#include "rna_internal_types.h"
+#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -298,9 +300,33 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
};
const EnumPropertyItem rna_enum_node_boolean_math_items[] = {
- {NODE_BOOLEAN_MATH_AND, "AND", 0, "And", "Outputs true only when both inputs are true"},
- {NODE_BOOLEAN_MATH_OR, "OR", 0, "Or", "Outputs or when at least one of the inputs is true"},
- {NODE_BOOLEAN_MATH_NOT, "NOT", 0, "Not", "Outputs the opposite of the input"},
+ {NODE_BOOLEAN_MATH_AND, "AND", 0, "And", "True when both inputs are true"},
+ {NODE_BOOLEAN_MATH_OR, "OR", 0, "Or", "True when at least one input is true"},
+ {NODE_BOOLEAN_MATH_NOT, "NOT", 0, "Not", "Opposite of the input"},
+ {0, "", ICON_NONE, NULL, NULL},
+ {NODE_BOOLEAN_MATH_NAND, "NAND", 0, "Not And", "True when at least one input is false"},
+ {NODE_BOOLEAN_MATH_NOR, "NOR", 0, "Nor", "True when both inputs are false"},
+ {NODE_BOOLEAN_MATH_XNOR,
+ "XNOR",
+ 0,
+ "Equal",
+ "True when both inputs are equal (exclusive nor)"},
+ {NODE_BOOLEAN_MATH_XOR,
+ "XOR",
+ 0,
+ "Not Equal",
+ "True when both inputs are different (exclusive or)"},
+ {0, "", ICON_NONE, NULL, NULL},
+ {NODE_BOOLEAN_MATH_IMPLY,
+ "IMPLY",
+ 0,
+ "Imply",
+ "True unless the first input is true and the second is false"},
+ {NODE_BOOLEAN_MATH_NIMPLY,
+ "NIMPLY",
+ 0,
+ "Subtract",
+ "True when the first input is true and the second is false (not imply)"},
{0, NULL, 0, NULL, NULL},
};
@@ -629,6 +655,7 @@ static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_no_bo
# include "NOD_geometry.h"
# include "NOD_shader.h"
# include "NOD_socket.h"
+# include "NOD_texture.h"
# include "RE_engine.h"
# include "RE_pipeline.h"
@@ -1219,7 +1246,7 @@ static void rna_NodeTree_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *p
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
WM_main_add_notifier(NC_SCENE | ND_NODES, &ntree->id);
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
@@ -1269,14 +1296,9 @@ static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
}
Main *bmain = CTX_data_main(C);
- ntreeUpdateTree(bmain, ntree);
- nodeUpdate(ntree, node);
+ ED_node_tree_propagate_change(C, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
- if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
- DEG_relations_tag_update(bmain);
- }
-
return node;
}
@@ -1300,7 +1322,7 @@ static void rna_NodeTree_node_remove(bNodeTree *ntree,
RNA_POINTER_INVALIDATE(node_ptr);
- ntreeUpdateTree(bmain, ntree); /* update group node socket links */
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1320,8 +1342,7 @@ static void rna_NodeTree_node_clear(bNodeTree *ntree, Main *bmain, ReportList *r
node = next_node;
}
- ntreeUpdateTree(bmain, ntree);
-
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1400,13 +1421,7 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree,
fromsock->flag &= ~SOCK_HIDDEN;
tosock->flag &= ~SOCK_HIDDEN;
- if (tonode) {
- nodeUpdate(ntree, tonode);
- }
-
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, ret->tonode);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
return ret;
@@ -1431,7 +1446,7 @@ static void rna_NodeTree_link_remove(bNodeTree *ntree,
nodeRemLink(ntree, link);
RNA_POINTER_INVALIDATE(link_ptr);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1450,8 +1465,7 @@ static void rna_NodeTree_link_clear(bNodeTree *ntree, Main *bmain, ReportList *r
link = next_link;
}
- ntreeUpdateTree(bmain, ntree);
-
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1508,7 +1522,7 @@ static bNodeSocket *rna_NodeTree_inputs_new(
bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_IN, type, name);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -1523,7 +1537,7 @@ static bNodeSocket *rna_NodeTree_outputs_new(
bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_OUT, type, name);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -1544,8 +1558,7 @@ static void rna_NodeTree_socket_remove(bNodeTree *ntree,
else {
ntreeRemoveSocketInterface(ntree, sock);
- ntreeUpdateTree(bmain, ntree);
- DEG_id_tag_update(&ntree->id, 0);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
}
@@ -1560,7 +1573,7 @@ static void rna_NodeTree_inputs_clear(bNodeTree *ntree, Main *bmain, ReportList
ntreeRemoveSocketInterface(ntree, socket);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1574,7 +1587,7 @@ static void rna_NodeTree_outputs_clear(bNodeTree *ntree, Main *bmain, ReportList
ntreeRemoveSocketInterface(ntree, socket);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1603,9 +1616,9 @@ static void rna_NodeTree_inputs_move(bNodeTree *ntree, Main *bmain, int from_ind
}
}
- ntree->update |= NTREE_UPDATE_GROUP_IN;
+ BKE_ntree_update_tag_interface(ntree);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1634,9 +1647,9 @@ static void rna_NodeTree_outputs_move(bNodeTree *ntree, Main *bmain, int from_in
}
}
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
+ BKE_ntree_update_tag_interface(ntree);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1644,10 +1657,8 @@ static void rna_NodeTree_interface_update(bNodeTree *ntree, bContext *C)
{
Main *bmain = CTX_data_main(C);
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
/* ******** NodeLink ******** */
@@ -1968,7 +1979,7 @@ static bNodeType *rna_Node_register_base(Main *bmain,
/* setup dummy node & node type to store static properties in */
memset(&dummynt, 0, sizeof(bNodeType));
/* this does some additional initialization of default values */
- node_type_base_custom(&dummynt, identifier, "", 0, 0);
+ node_type_base_custom(&dummynt, identifier, "", 0);
memset(&dummynode, 0, sizeof(bNode));
dummynode.typeinfo = &dummynt;
@@ -2210,6 +2221,20 @@ static const EnumPropertyItem *rna_FunctionNodeRandomValue_type_itemf(bContext *
return itemf_function_check(rna_enum_attribute_type_items, random_value_type_supported);
}
+static bool accumulate_field_type_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_INT32);
+}
+
+static const EnumPropertyItem *rna_GeoNodeAccumulateField_type_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ *r_free = true;
+ return itemf_function_check(rna_enum_attribute_type_items, accumulate_field_type_supported);
+}
+
static const EnumPropertyItem *rna_GeometryNodeAttributeRandomize_operation_itemf(
bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -2617,7 +2642,8 @@ static void rna_Node_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -2626,9 +2652,10 @@ static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr
DEG_relations_tag_update(bmain);
}
-static void rna_Node_socket_value_update(ID *id, bNode *node, bContext *C)
+static void rna_Node_socket_value_update(ID *id, bNode *UNUSED(node), bContext *C)
{
- ED_node_tag_update_nodetree(CTX_data_main(C), (bNodeTree *)id, node);
+ BKE_ntree_update_tag_all((bNodeTree *)id);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), (bNodeTree *)id);
}
static void rna_Node_select_set(PointerRNA *ptr, bool value)
@@ -2682,7 +2709,7 @@ static bNodeSocket *rna_Node_inputs_new(ID *id,
BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2716,7 +2743,7 @@ static bNodeSocket *rna_Node_outputs_new(ID *id,
BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2734,7 +2761,7 @@ static void rna_Node_socket_remove(
else {
nodeRemoveSocket(ntree, node, sock);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
}
@@ -2749,7 +2776,7 @@ static void rna_Node_inputs_clear(ID *id, bNode *node, Main *bmain)
nodeRemoveSocket(ntree, node, sock);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2763,7 +2790,7 @@ static void rna_Node_outputs_clear(ID *id, bNode *node, Main *bmain)
nodeRemoveSocket(ntree, node, sock);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2795,7 +2822,7 @@ static void rna_Node_inputs_move(ID *id, bNode *node, Main *bmain, int from_inde
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2827,7 +2854,7 @@ static void rna_Node_outputs_move(ID *id, bNode *node, Main *bmain, int from_ind
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -3055,10 +3082,9 @@ static void rna_NodeSocket_update(Main *bmain, Scene *UNUSED(scene), PointerRNA
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocket *sock = (bNodeSocket *)ptr->data;
- bNode *node;
- if (nodeFindNode(ntree, sock, &node, NULL)) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
- }
+
+ BKE_ntree_update_tag_socket_property(ntree, sock);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static bool rna_NodeSocket_is_output_get(PointerRNA *ptr)
@@ -3069,7 +3095,6 @@ static bool rna_NodeSocket_is_output_get(PointerRNA *ptr)
static void rna_NodeSocket_link_limit_set(PointerRNA *ptr, int value)
{
- /* Does not have any effect if the link limit is defined in the socket type. */
bNodeSocket *sock = ptr->data;
sock->limit = (value == 0 ? 0xFFF : value);
}
@@ -3351,10 +3376,8 @@ static void rna_NodeSocketInterface_update(Main *bmain, Scene *UNUSED(scene), Po
return;
}
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
/* ******** Standard Node Socket Base Types ******** */
@@ -3452,28 +3475,14 @@ static void rna_NodeSocketStandard_vector_range(
/* using a context update function here, to avoid searching the node if possible */
static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *ptr)
{
- bNode *node;
-
/* default update */
rna_NodeSocket_update(CTX_data_main(C), CTX_data_scene(C), ptr);
-
- /* try to use node from context, faster */
- node = CTX_data_pointer_get(C, "node").data;
- if (!node) {
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNodeSocket *sock = ptr->data;
-
- /* fall back to searching node in the tree */
- nodeFindNode(ntree, sock, &node, NULL);
- }
}
static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C, PointerRNA *ptr)
{
rna_NodeSocketStandard_value_update(C, ptr);
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
Main *bmain = CTX_data_main(C);
- ntreeUpdateTree(bmain, ntree);
DEG_relations_tag_update(bmain);
}
@@ -3567,12 +3576,11 @@ static bool rna_NodeInternal_poll_instance(bNode *node, bNodeTree *ntree)
}
}
-static void rna_NodeInternal_update(ID *id, bNode *node)
+static void rna_NodeInternal_update(ID *id, bNode *node, Main *bmain)
{
bNodeTree *ntree = (bNodeTree *)id;
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_NodeInternal_draw_buttons(ID *id,
@@ -3721,7 +3729,8 @@ static void rna_Node_tex_image_update(Main *bmain, Scene *UNUSED(scene), Pointer
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_IMAGE, NULL);
}
@@ -3730,11 +3739,8 @@ static void rna_NodeGroup_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- if (node->id) {
- ntreeUpdateTree(bmain, (bNodeTree *)node->id);
- }
-
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
DEG_relations_tag_update(bmain);
}
@@ -4142,13 +4148,12 @@ static const EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C),
return item;
}
-static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Image_Node_update_id(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
node->update |= NODE_UPDATE_ID;
- nodeUpdate(ntree, node); /* to update image node sockets */
+ rna_Node_update(bmain, scene, ptr);
}
static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -4395,7 +4400,7 @@ static bNodeSocket *rna_NodeOutputFile_slots_new(
sock = ntreeCompositOutputFileAddSocket(ntree, node, name, im_format);
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -4504,42 +4509,27 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p
RE_engine_free(engine);
}
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_ShaderNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_Node_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_GeometryNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
@@ -4701,6 +4691,55 @@ bool rna_NodeSocketMaterial_default_value_poll(PointerRNA *UNUSED(ptr), PointerR
return ma->gp_style == NULL;
}
+static int rna_NodeConvertColorSpace_from_color_space_get(struct PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeConvertColorSpace *node_storage = node->storage;
+ return IMB_colormanagement_colorspace_get_named_index(node_storage->from_color_space);
+}
+
+static void rna_NodeConvertColorSpace_from_color_space_set(struct PointerRNA *ptr, int value)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeConvertColorSpace *node_storage = node->storage;
+ const char *name = IMB_colormanagement_colorspace_get_indexed_name(value);
+
+ if (name && name[0]) {
+ BLI_strncpy(node_storage->from_color_space, name, sizeof(node_storage->from_color_space));
+ }
+}
+static int rna_NodeConvertColorSpace_to_color_space_get(struct PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeConvertColorSpace *node_storage = node->storage;
+ return IMB_colormanagement_colorspace_get_named_index(node_storage->to_color_space);
+}
+
+static void rna_NodeConvertColorSpace_to_color_space_set(struct PointerRNA *ptr, int value)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeConvertColorSpace *node_storage = node->storage;
+ const char *name = IMB_colormanagement_colorspace_get_indexed_name(value);
+
+ if (name && name[0]) {
+ BLI_strncpy(node_storage->to_color_space, name, sizeof(node_storage->to_color_space));
+ }
+}
+
+static const EnumPropertyItem *rna_NodeConvertColorSpace_color_space_itemf(
+ bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ EnumPropertyItem *items = NULL;
+ int totitem = 0;
+
+ IMB_colormanagement_colorspace_items_add(&items, &totitem);
+ RNA_enum_item_end(&items, &totitem);
+
+ *r_free = true;
+
+ return items;
+}
+
#else
static const EnumPropertyItem prop_image_layer_items[] = {
@@ -7348,6 +7387,42 @@ static void def_cmp_distance_matte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_cmp_convert_color_space(StructRNA *srna)
+{
+ PropertyRNA *prop;
+ RNA_def_struct_sdna_from(srna, "NodeConvertColorSpace", "storage");
+
+ static const EnumPropertyItem color_space_items[] = {
+ {0,
+ "NONE",
+ 0,
+ "None",
+ "Do not perform any color transform on load, treat colors as in scene linear space "
+ "already"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ prop = RNA_def_property(srna, "from_color_space", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
+ RNA_def_property_enum_items(prop, color_space_items);
+ RNA_def_property_enum_funcs(prop,
+ "rna_NodeConvertColorSpace_from_color_space_get",
+ "rna_NodeConvertColorSpace_from_color_space_set",
+ "rna_NodeConvertColorSpace_color_space_itemf");
+ RNA_def_property_ui_text(prop, "From", "Color space of the input image");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "to_color_space", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
+ RNA_def_property_enum_items(prop, color_space_items);
+ RNA_def_property_enum_funcs(prop,
+ "rna_NodeConvertColorSpace_to_color_space_get",
+ "rna_NodeConvertColorSpace_to_color_space_set",
+ "rna_NodeConvertColorSpace_color_space_itemf");
+ RNA_def_property_ui_text(prop, "To", "Color space of the output image");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_cmp_color_spill(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9438,7 +9513,12 @@ static void def_geo_triangulate(StructRNA *srna)
"SHORTEST_DIAGONAL",
0,
"Shortest Diagonal",
- "Split the quads based on the distance between the vertices"},
+ "Split the quads along their shortest diagonal"},
+ {GEO_NODE_TRIANGULATE_QUAD_LONGEDGE,
+ "LONGEST_DIAGONAL",
+ 0,
+ "Longest Diagonal",
+ "Split the quads along their longest diagonal"},
{0, NULL, 0, NULL, NULL},
};
@@ -9491,6 +9571,28 @@ static void def_geo_subdivision_surface(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_geo_accumulate_field(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeAccumulateField", "storage");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "data_type");
+ RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeoNodeAccumulateField_type_itemf");
+ RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
+ RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "domain");
+ RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
+ RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT);
+ RNA_def_property_ui_text(prop, "Domain", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_fn_random_value(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9817,6 +9919,27 @@ static void def_geo_point_distribute(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_extrude_mesh(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem mode_items[] = {
+ {GEO_NODE_EXTRUDE_MESH_VERTICES, "VERTICES", 0, "Vertices", ""},
+ {GEO_NODE_EXTRUDE_MESH_EDGES, "EDGES", 0, "Edges", ""},
+ {GEO_NODE_EXTRUDE_MESH_FACES, "FACES", 0, "Faces", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryExtrudeMesh", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_enum_default(prop, GEO_NODE_EXTRUDE_MESH_FACES);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_geo_distribute_points_on_faces(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10062,6 +10185,33 @@ static void def_geo_curve_primitive_circle(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_curve_primitive_arc(StructRNA *srna)
+{
+ static const EnumPropertyItem mode_items[] = {
+
+ {GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS,
+ "POINTS",
+ ICON_NONE,
+ "Points",
+ "Define arc by 3 points on circle. Arc is calculated between start and end points"},
+ {GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS,
+ "RADIUS",
+ ICON_NONE,
+ "Radius",
+ "Define radius with a float"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryCurvePrimitiveArc", "storage");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "Method used to determine radius and placement");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_curve_primitive_line(StructRNA *srna)
{
static const EnumPropertyItem mode_items[] = {
@@ -11228,6 +11378,33 @@ static void def_geo_string_to_curves(StructRNA *srna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem rna_node_geometry_string_to_curves_pivot_mode[] = {
+ {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_MIDPOINT, "MIDPOINT", 0, "Midpoint", "Midpoint"},
+ {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_LEFT, "TOP_LEFT", 0, "Top Left", "Top Left"},
+ {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_CENTER,
+ "TOP_CENTER",
+ 0,
+ "Top Center",
+ "Top Center"},
+ {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_RIGHT, "TOP_RIGHT", 0, "Top Right", "Top Right"},
+ {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_LEFT,
+ "BOTTOM_LEFT",
+ 0,
+ "Bottom Left",
+ "Bottom Left"},
+ {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_CENTER,
+ "BOTTOM_CENTER",
+ 0,
+ "Bottom Center",
+ "Bottom Center"},
+ {GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_RIGHT,
+ "BOTTOM_RIGHT",
+ 0,
+ "Bottom Right",
+ "Bottom Right"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
PropertyRNA *prop;
prop = RNA_def_property(srna, "font", PROP_POINTER, PROP_NONE);
@@ -11260,6 +11437,13 @@ static void def_geo_string_to_curves(StructRNA *srna)
RNA_def_property_enum_default(prop, GEO_NODE_STRING_TO_CURVES_ALIGN_Y_TOP_BASELINE);
RNA_def_property_ui_text(prop, "Align Y", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "pivot_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "pivot_mode");
+ RNA_def_property_enum_items(prop, rna_node_geometry_string_to_curves_pivot_mode);
+ RNA_def_property_enum_default(prop, GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_LEFT);
+ RNA_def_property_ui_text(prop, "Pivot Point", "Pivot point position relative to character");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_geo_separate_geometry(StructRNA *srna)
@@ -11300,6 +11484,71 @@ static void def_geo_realize_instances(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
}
+static void def_geo_field_at_index(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
+ RNA_def_property_ui_text(prop, "Domain", "Domain the field is evaluated in");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_ui_text(prop, "Data Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+}
+
+static void def_geo_scale_elements(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem domain_items[] = {
+ {ATTR_DOMAIN_FACE,
+ "FACE",
+ ICON_NONE,
+ "Face",
+ "Scale individual faces or neighboring face islands"},
+ {ATTR_DOMAIN_EDGE,
+ "EDGE",
+ ICON_NONE,
+ "Edge",
+ "Scale individual edges or neighboring edge islands"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem scale_mode_items[] = {
+ {GEO_NODE_SCALE_ELEMENTS_UNIFORM,
+ "UNIFORM",
+ ICON_NONE,
+ "Uniform",
+ "Scale elements by the same factor in every direction"},
+ {GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS,
+ "SINGLE_AXIS",
+ ICON_NONE,
+ "Single Axis",
+ "Scale elements in a single direction"},
+ {0, NULL, 0, NULL, NULL},
+
+ };
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, domain_items);
+ RNA_def_property_enum_default(prop, ATTR_DOMAIN_FACE);
+ RNA_def_property_ui_text(prop, "Domain", "Element type to transform");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+
+ prop = RNA_def_property(srna, "scale_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_items(prop, scale_mode_items);
+ RNA_def_property_ui_text(prop, "Scale Mode", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
@@ -12386,7 +12635,7 @@ static void rna_def_internal_node(BlenderRNA *brna)
func = RNA_def_function(srna, "update", "rna_NodeInternal_update");
RNA_def_function_ui_description(
func, "Update on node graph topology changes (adding or removing nodes and links)");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_ALLOW_WRITE);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_ALLOW_WRITE);
/* draw buttons */
func = RNA_def_function(srna, "draw_buttons", "rna_NodeInternal_draw_buttons");
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 0cb132786cd..a098693459b 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -620,11 +620,7 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr)
return &RNA_ID;
# endif
case OB_POINTCLOUD:
-# ifdef WITH_POINT_CLOUD
return &RNA_PointCloud;
-# else
- return &RNA_ID;
-# endif
case OB_VOLUME:
return &RNA_Volume;
default:
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 63c4774d0e5..cc9f6454337 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -68,6 +68,7 @@ static const EnumPropertyItem space_items[] = {
# include "BKE_bvhutils.h"
# include "BKE_constraint.h"
# include "BKE_context.h"
+# include "BKE_crazyspace.h"
# include "BKE_customdata.h"
# include "BKE_global.h"
# include "BKE_layer.h"
@@ -379,6 +380,39 @@ static void rna_Object_camera_fit_coords(
depsgraph, (const float(*)[3])cos, num_cos / 3, ob, co_ret, scale_ret);
}
+static void rna_Object_crazyspace_eval(Object *object,
+ ReportList *reports,
+ Depsgraph *depsgraph,
+ Scene *scene)
+{
+ BKE_crazyspace_api_eval(depsgraph, scene, object, reports);
+}
+
+static void rna_Object_crazyspace_displacement_to_deformed(Object *object,
+ ReportList *reports,
+ const int vertex_index,
+ float displacement[3],
+ float r_displacement_deformed[3])
+{
+ BKE_crazyspace_api_displacement_to_deformed(
+ object, reports, vertex_index, displacement, r_displacement_deformed);
+}
+
+static void rna_Object_crazyspace_displacement_to_original(Object *object,
+ ReportList *reports,
+ const int vertex_index,
+ float displacement_deformed[3],
+ float r_displacement[3])
+{
+ BKE_crazyspace_api_displacement_to_original(
+ object, reports, vertex_index, displacement_deformed, r_displacement);
+}
+
+static void rna_Object_crazyspace_eval_clear(Object *object)
+{
+ BKE_crazyspace_api_eval_clear(object);
+}
+
/* copied from Mesh_getFromObject and adapted to RNA interface */
static Mesh *rna_Object_to_mesh(Object *object,
ReportList *reports,
@@ -729,7 +763,7 @@ void rna_Object_me_eval_info(
}
if (me_eval) {
- ret = BKE_mesh_runtime_debug_info(me_eval);
+ ret = BKE_mesh_debug_info(me_eval);
if (ret) {
strcpy(result, ret);
MEM_freeN(ret);
@@ -978,6 +1012,52 @@ void RNA_api_object(StructRNA *srna)
parm, "", "The ortho scale to aim to be able to see all given points (if relevant)");
RNA_def_parameter_flags(parm, 0, PARM_OUTPUT);
+ /* Crazyspace access. */
+
+ func = RNA_def_function(srna, "crazyspace_eval", "rna_Object_crazyspace_eval");
+ RNA_def_function_ui_description(
+ func,
+ "Compute orientation mapping between vertices of an original object and object with shape "
+ "keys and deforming modifiers applied."
+ "The evaluation is to be freed with the crazyspace_eval_free function");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(
+ func, "depsgraph", "Depsgraph", "Dependency Graph", "Evaluated dependency graph");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "scene", "Scene", "Scene", "Scene of the object");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+
+ func = RNA_def_function(srna,
+ "crazyspace_displacement_to_deformed",
+ "rna_Object_crazyspace_displacement_to_deformed");
+ RNA_def_function_ui_description(
+ func, "Convert displacement vector from non-deformed object space to deformed object space");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_property(func, "vertex_index", PROP_INT, PROP_NONE);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_property(func, "displacement", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ parm = RNA_def_property(func, "displacement_deformed", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ RNA_def_function_output(func, parm);
+
+ func = RNA_def_function(srna,
+ "crazyspace_displacement_to_original",
+ "rna_Object_crazyspace_displacement_to_original");
+ RNA_def_function_ui_description(
+ func, "Convert displacement vector from deformed object space to non-deformed object space");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_property(func, "vertex_index", PROP_INT, PROP_NONE);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_property(func, "displacement", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ parm = RNA_def_property(func, "displacement_original", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_array(parm, 3);
+ RNA_def_function_output(func, parm);
+
+ RNA_def_function(srna, "crazyspace_eval_clear", "rna_Object_crazyspace_eval_clear");
+ RNA_def_function_ui_description(func, "Free evaluated state of crazyspace");
+
/* mesh */
func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh");
RNA_def_function_ui_description(
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 2fca9f0af7a..d697a48e04b 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -1128,6 +1128,8 @@ static void rna_def_collision(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "Collision Settings", "Collision settings for object in physics simulation");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "deflect", 1);
RNA_def_property_ui_text(
@@ -1230,6 +1232,8 @@ static void rna_def_collision(BlenderRNA *brna)
"Cloth collision impulses act in the direction of the collider normals "
"(more reliable in some cases)");
RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_effector_weight(BlenderRNA *brna)
@@ -1243,6 +1247,8 @@ static void rna_def_effector_weight(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Effector Weights", "Effector weights for physics simulation");
RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+ RNA_define_lib_overridable(true);
+
/* Flags */
prop = RNA_def_property(srna, "apply_to_hair_growing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", EFF_WEIGHT_DO_HAIR);
@@ -1362,6 +1368,8 @@ static void rna_def_effector_weight(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_ui_text(prop, "Fluid Flow", "Fluid Flow effector weight");
RNA_def_property_update(prop, 0, "rna_EffectorWeight_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_field(BlenderRNA *brna)
@@ -1471,6 +1479,8 @@ static void rna_def_field(BlenderRNA *brna)
srna, "Field Settings", "Field settings for an object in physics simulation");
RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+ RNA_define_lib_overridable(true);
+
/* Enums */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
@@ -1514,34 +1524,34 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_strength");
- RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Strength", "Strength of force field");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
/* different ui range to above */
prop = RNA_def_property(srna, "linear_drag", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_strength");
- RNA_def_property_range(prop, -2.0f, 2.0f);
+ RNA_def_property_ui_range(prop, -2.0f, 2.0f, 10, 3);
RNA_def_property_ui_text(prop, "Linear Drag", "Drag component proportional to velocity");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
prop = RNA_def_property(srna, "harmonic_damping", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_damp");
- RNA_def_property_range(prop, 0.0f, 10.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3);
RNA_def_property_ui_text(prop, "Harmonic Damping", "Damping of the harmonic force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
/* different ui range to above */
prop = RNA_def_property(srna, "quadratic_drag", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_damp");
- RNA_def_property_range(prop, -2.0f, 2.0f);
+ RNA_def_property_ui_range(prop, -2.0f, 2.0f, 10, 3);
RNA_def_property_ui_text(
prop, "Quadratic Drag", "Drag component proportional to the square of velocity");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
prop = RNA_def_property(srna, "flow", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_flow");
- RNA_def_property_range(prop, 0.0f, 10.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3);
RNA_def_property_ui_text(prop, "Flow", "Convert effector force into air flow velocity");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1557,7 +1567,7 @@ static void rna_def_field(BlenderRNA *brna)
/* different ui range to above */
prop = RNA_def_property(srna, "inflow", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_flow");
- RNA_def_property_range(prop, -10.0f, 10.0f);
+ RNA_def_property_ui_range(prop, -10.0f, 10.0f, 10, 3);
RNA_def_property_ui_text(prop, "Inflow", "Inwards component of the vortex force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1570,7 +1580,8 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "rest_length", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_size");
- RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(prop, "Rest Length", "Rest length of the harmonic force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1728,7 +1739,7 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "guide_minimum", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_strength");
- RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(
prop, "Minimum Distance", "The distance from which particles are affected fully");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1799,6 +1810,8 @@ static void rna_def_field(BlenderRNA *brna)
/* Variables used for Curve Guide, already wrapped, used for other fields too */
/* falloff_power, use_max_distance, maximum_distance */
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_softbody(BlenderRNA *brna)
@@ -2134,6 +2147,7 @@ static void rna_def_softbody(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "effector_weights");
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
}
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index f732e14d905..fbc7625d815 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -3498,6 +3498,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
/* animation here? */
@@ -3507,12 +3508,14 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "pd");
RNA_def_property_struct_type(prop, "FieldSettings");
RNA_def_property_pointer_funcs(prop, "rna_Particle_field1_get", NULL, NULL, NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Force Field 1", "");
prop = RNA_def_property(srna, "force_field_2", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "pd2");
RNA_def_property_struct_type(prop, "FieldSettings");
RNA_def_property_pointer_funcs(prop, "rna_Particle_field2_get", NULL, NULL, NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Force Field 2", "");
/* twist */
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index fcb46904e8d..65e9a140f82 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -98,6 +98,7 @@ const EnumPropertyItem rna_enum_bake_pass_type_items[] = {
# include "RNA_access.h"
+# include "BKE_appdir.h"
# include "BKE_context.h"
# include "BKE_report.h"
@@ -420,6 +421,16 @@ static StructRNA *rna_RenderEngine_refine(PointerRNA *ptr)
&RNA_RenderEngine;
}
+static void rna_RenderEngine_tempdir_get(PointerRNA *UNUSED(ptr), char *value)
+{
+ BLI_strncpy(value, BKE_tempdir_session(), FILE_MAX);
+}
+
+static int rna_RenderEngine_tempdir_length(PointerRNA *UNUSED(ptr))
+{
+ return strlen(BKE_tempdir_session());
+}
+
static PointerRNA rna_RenderEngine_render_get(PointerRNA *ptr)
{
RenderEngine *engine = (RenderEngine *)ptr->data;
@@ -860,6 +871,12 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "resolution_y");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "temporary_directory", PROP_STRING, PROP_NONE);
+ RNA_def_function_ui_description(func, "The temp directory used by Blender");
+ RNA_def_property_string_funcs(
+ prop, "rna_RenderEngine_tempdir_get", "rna_RenderEngine_tempdir_length", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
/* Render Data */
prop = RNA_def_property(srna, "render", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "RenderSettings");
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index c0fb904101d..10e28ac3948 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -957,6 +957,7 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
/* Sweep test */
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 285f6365ea1..85955c5e9f7 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -2984,14 +2984,14 @@ static void rna_def_function(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"No Self",
- "Function does not pass its self as an argument (becomes a static method in python)");
+ "Function does not pass itself as an argument (becomes a static method in python)");
prop = RNA_def_property(srna, "use_self_type", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Function_use_self_type_get", NULL);
RNA_def_property_ui_text(prop,
"Use Self Type",
- "Function passes its self type as an argument (becomes a class method "
+ "Function passes itself type as an argument (becomes a class method "
"in python if use_self is false)");
}
@@ -3117,7 +3117,11 @@ static void rna_def_number_property(StructRNA *srna, PropertyType type)
prop = RNA_def_property(srna, "precision", PROP_INT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_int_funcs(prop, "rna_FloatProperty_precision_get", NULL, NULL);
- RNA_def_property_ui_text(prop, "Precision", "Number of digits after the dot used by buttons");
+ RNA_def_property_ui_text(prop,
+ "Precision",
+ "Number of digits after the dot used by buttons. Fraction is "
+ "automatically hidden for exact integer values of fields with unit "
+ "'NONE' or 'TIME' (frame count) and step divisible by 100");
}
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index d05f2a13c4b..7f9890e492d 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -86,8 +86,7 @@ const EnumPropertyItem rna_enum_exr_codec_items[] = {
{R_IMF_EXR_CODEC_B44, "B44", 0, "B44 (lossy)", ""},
{R_IMF_EXR_CODEC_B44A, "B44A", 0, "B44A (lossy)", ""},
{R_IMF_EXR_CODEC_DWAA, "DWAA", 0, "DWAA (lossy)", ""},
- /* NOTE: Commented out for until new OpenEXR is released, see T50673. */
- /* {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""}, */
+ {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""},
{0, NULL, 0, NULL, NULL},
};
#endif
@@ -433,6 +432,16 @@ const EnumPropertyItem rna_enum_normal_swizzle_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_bake_margin_type_items[] = {
+ {R_BAKE_ADJACENT_FACES,
+ "ADJACENT_FACES",
+ 0,
+ "Adjacent Faces",
+ "Use pixels from adjacent faces across UV seams"},
+ {R_BAKE_EXTEND, "EXTEND", 0, "Extend", "Extend border pixels outwards"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_bake_target_items[] = {
{R_BAKE_TARGET_IMAGE_TEXTURES,
"IMAGE_TEXTURES",
@@ -646,6 +655,8 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = {
# include "BKE_screen.h"
# include "BKE_unit.h"
+# include "NOD_composite.h"
+
# include "ED_image.h"
# include "ED_info.h"
# include "ED_keyframing.h"
@@ -3262,6 +3273,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Automerge",
"Join by distance last drawn stroke with previous strokes in the active layer");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt");
@@ -5055,6 +5067,11 @@ static void rna_def_bake_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Margin", "Extends the baked result as a post process filter");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "margin_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_bake_margin_type_items);
+ RNA_def_property_ui_text(prop, "Margin Type", "Algorithm to extend the baked result");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "max_ray_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3);
@@ -5583,7 +5600,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", ""},
@@ -5846,6 +5863,16 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem bake_margin_type_items[] = {
+ {R_BAKE_ADJACENT_FACES,
+ "ADJACENT_FACES",
+ 0,
+ "Adjacent Faces",
+ "Use pixels from adjacent faces across UV seams"},
+ {R_BAKE_EXTEND, "EXTEND", 0, "Extend", "Extend border pixels outwards"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
static const EnumPropertyItem pixel_size_items[] = {
{0, "AUTO", 0, "Automatic", "Automatic pixel size, depends on the user interface scale"},
{1, "1", 0, "1x", "Render at full resolution"},
@@ -6261,11 +6288,17 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "bake_margin", PROP_INT, PROP_PIXEL);
- RNA_def_property_int_sdna(prop, NULL, "bake_filter");
+ RNA_def_property_int_sdna(prop, NULL, "bake_margin");
RNA_def_property_range(prop, 0, 64);
RNA_def_property_ui_text(prop, "Margin", "Extends the baked result as a post process filter");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "bake_margin_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "bake_margin_type");
+ RNA_def_property_enum_items(prop, bake_margin_type_items);
+ RNA_def_property_ui_text(prop, "Margin Type", "Algorithm to generate the margin");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "bake_bias", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "bake_biasdist");
RNA_def_property_range(prop, 0.0, 1000.0);
@@ -7073,7 +7106,7 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "ssr_quality", PROP_FLOAT, PROP_FACTOR);
- RNA_def_property_ui_text(prop, "Trace Precision", "Precision of the screen space raytracing");
+ RNA_def_property_ui_text(prop, "Trace Precision", "Precision of the screen space ray-tracing");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -7880,8 +7913,10 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "clip");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "MovieClip");
- RNA_def_property_ui_text(
- prop, "Active Movie Clip", "Active movie clip used for constraints and viewport drawing");
+ RNA_def_property_ui_text(prop,
+ "Active Movie Clip",
+ "Active Movie Clip that can be used by motion tracking constraints "
+ "or as a camera's background image");
RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
/* color management */
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 543d69842be..41ba8119202 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -91,7 +91,7 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf
if (!G.is_rendering) {
/* can't use NC_SCENE|ND_FRAME because this causes wm_event_do_notifiers to call
* BKE_scene_graph_update_for_newframe which will lose any un-keyed changes T24690. */
- /* WM_main_add_notifier(NC_SCENE|ND_FRAME, scene); */
+ // WM_main_add_notifier(NC_SCENE|ND_FRAME, scene);
/* instead just redraw the views */
WM_main_add_notifier(NC_WINDOW, NULL);
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index a2db1536f55..2358d236c4d 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -672,7 +672,7 @@ static void rna_def_paint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Cavity Mask", "Mask painting according to mesh geometry cavity");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "tile_offset", PROP_FLOAT, PROP_XYZ);
+ prop = RNA_def_property(srna, "tile_offset", PROP_FLOAT, PROP_XYZ_LENGTH);
RNA_def_property_float_sdna(prop, NULL, "tile_offset");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.01, FLT_MAX);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 9be66a6553b..6c3e3ab3058 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -3012,7 +3012,7 @@ static void rna_def_text(StructRNA *srna)
RNA_def_property_float_sdna(prop, NULL, "text_size");
RNA_def_property_ui_text(prop, "Size", "Size of the text");
RNA_def_property_range(prop, 0.0, 2000);
- RNA_def_property_ui_range(prop, 0.0f, 2000, 10.f, 1);
+ RNA_def_property_ui_range(prop, 0.0f, 2000, 10.0f, 1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 16e9a6208fb..e2411f5f4ae 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -1861,6 +1861,9 @@ static void rna_SpaceTextEditor_text_set(PointerRNA *ptr,
SpaceText *st = (SpaceText *)(ptr->data);
st->text = value.data;
+ if (st->text != NULL) {
+ id_us_ensure_real((ID *)st->text);
+ }
ScrArea *area = rna_area_from_space(ptr);
if (area) {
@@ -2337,7 +2340,8 @@ static void seq_build_proxy(bContext *C, PointerRNA *ptr)
seq->strip->proxy->build_size_flags |= SEQ_rendersize_to_proxysize(sseq->render_size);
/* Build proxy. */
- SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
+ SEQ_proxy_rebuild_context(
+ pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue, true);
}
BLI_gset_free(file_list, MEM_freeN);
@@ -4301,6 +4305,15 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "bone_wire_alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "overlay.bone_wire_alpha");
+ RNA_def_property_ui_text(
+ prop, "Bone Wireframe Opacity", "Maximim opacity of bones in wireframe display mode");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1, 2);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
prop = RNA_def_property(srna, "show_motion_paths", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_MOTION_PATHS);
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 5a74cfa9964..f66fb2653b5 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -199,7 +199,7 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt
}
else if (GS(id->name) == ID_NT) {
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
}
diff --git a/source/blender/makesrna/intern/rna_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_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index c81588aa8b5..2d4d5ee766f 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -24,6 +24,7 @@
#include "MEM_guardedalloc.h"
#include "BKE_movieclip.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "RNA_access.h"
@@ -31,6 +32,7 @@
#include "rna_internal.h"
+#include "DNA_defaults.h"
#include "DNA_movieclip_types.h"
#include "DNA_object_types.h" /* SELECT */
#include "DNA_scene_types.h"
@@ -415,11 +417,12 @@ static void rna_tracking_stabRotTracks_active_index_range(
*max = max_ii(0, clip->tracking.stabilization.tot_rot_track - 1);
}
-static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_tracking_flushUpdate(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->owner_id;
- nodeUpdateID(scene->nodetree, &clip->id);
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
+ BKE_ntree_update_main(bmain, NULL);
WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
WM_main_add_notifier(NC_SCENE, NULL);
@@ -607,7 +610,7 @@ static MovieTrackingTrack *add_track_to_base(
MovieClip *clip, MovieTracking *tracking, ListBase *tracksbase, const char *name, int frame)
{
int width, height;
- MovieClipUser user = {0};
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
MovieTrackingTrack *track;
user.framenr = 1;
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index f96b3fc5eee..5bf778d1962 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -582,6 +582,56 @@ static void rna_uiTemplateCacheFile(uiLayout *layout,
uiTemplateCacheFile(layout, C, ptr, propname);
}
+static void rna_uiTemplateCacheFileVelocity(uiLayout *layout,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
+ return;
+ }
+
+ uiTemplateCacheFileVelocity(layout, &fileptr);
+}
+
+static void rna_uiTemplateCacheFileProcedural(uiLayout *layout,
+ bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
+ return;
+ }
+
+ uiTemplateCacheFileProcedural(layout, C, &fileptr);
+}
+
+static void rna_uiTemplateCacheFileTimeSettings(uiLayout *layout,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
+ return;
+ }
+
+ uiTemplateCacheFileTimeSettings(layout, &fileptr);
+}
+
+static void rna_uiTemplateCacheFileLayers(uiLayout *layout,
+ bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
+ return;
+ }
+
+ uiTemplateCacheFileLayers(layout, C, &fileptr);
+}
+
static void rna_uiTemplatePathBuilder(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -1795,6 +1845,26 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
+ func = RNA_def_function(srna, "template_cache_file_velocity", "rna_uiTemplateCacheFileVelocity");
+ RNA_def_function_ui_description(func, "Show cache files velocity properties");
+ api_ui_item_rna_common(func);
+
+ func = RNA_def_function(
+ srna, "template_cache_file_procedural", "rna_uiTemplateCacheFileProcedural");
+ RNA_def_function_ui_description(func, "Show cache files render procedural properties");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+
+ func = RNA_def_function(
+ srna, "template_cache_file_time_settings", "rna_uiTemplateCacheFileTimeSettings");
+ RNA_def_function_ui_description(func, "Show cache files time settings");
+ api_ui_item_rna_common(func);
+
+ func = RNA_def_function(srna, "template_cache_file_layers", "rna_uiTemplateCacheFileLayers");
+ RNA_def_function_ui_description(func, "Show cache files override layers properties");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+
func = RNA_def_function(srna, "template_recent_files", "uiTemplateRecentFiles");
RNA_def_function_ui_description(func, "Show list of recently saved .blend files");
RNA_def_int(func, "rows", 5, 1, INT_MAX, "", "Maximum number of items to show", 1, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index dd1252ffebf..4379b4ebe1d 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -182,6 +182,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
# include "BKE_image.h"
# include "BKE_main.h"
# include "BKE_mesh_runtime.h"
+# include "BKE_object.h"
# include "BKE_paint.h"
# include "BKE_pbvh.h"
# include "BKE_preferences.h"
@@ -578,6 +579,20 @@ static PointerRNA rna_UserDef_apps_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_PreferencesApps, ptr->data);
}
+/* Reevaluate objects with a subsurf modifier as the last in their modifiers stacks. */
+static void rna_UserDef_subdivision_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob;
+
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ if (BKE_object_get_last_subsurf_modifier(ob) != NULL) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ }
+
+ rna_userdef_update(bmain, scene, ptr);
+}
+
static void rna_UserDef_audio_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
BKE_sound_init(bmain);
@@ -2889,7 +2904,7 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "group_node", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "syntaxc");
- RNA_def_property_array(prop, 4);
+ RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Group Node", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
@@ -5651,6 +5666,16 @@ static void rna_def_userdef_system(BlenderRNA *brna)
"Use the depth buffer for picking 3D View selection "
"(without this the front most object may not be selected first)");
+ /* GPU subdivision evaluation. */
+
+ prop = RNA_def_property(srna, "use_gpu_subdivision", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpu_flag", USER_GPU_FLAG_SUBDIVISION_EVALUATION);
+ RNA_def_property_ui_text(prop,
+ "GPU Subdivision",
+ "Enable GPU acceleration for evaluating the last subdivision surface "
+ "modifiers in the stack");
+ RNA_def_property_update(prop, 0, "rna_UserDef_subdivision_update");
+
/* Audio */
prop = RNA_def_property(srna, "audio_mixing_buffer", PROP_ENUM, PROP_NONE);
@@ -6412,6 +6437,14 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
"Enable some extra fields in the Asset Browser to aid in debugging");
RNA_def_property_update(prop, 0, "rna_userdef_ui_update");
+ prop = RNA_def_property(srna, "use_asset_indexing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "no_asset_indexing", 1);
+ RNA_def_property_ui_text(prop,
+ "Asset Indexing",
+ "Disabling the asset indexer forces every asset library refresh to "
+ "completely reread assets from disk");
+ RNA_def_property_update(prop, 0, "rna_userdef_ui_update");
+
prop = RNA_def_property(srna, "use_override_templates", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_override_templates", 1);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 8c128292fd7..c64a47fc2ab 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -965,7 +965,7 @@ static void rna_wmKeyMapItem_keymodifier_set(PointerRNA *ptr, int value)
if (value == EVT_ESCKEY) {
/* pass */
}
- else if (value >= EVT_AKEY) {
+ else if (ISKEYBOARD(value) && !ISKEYMODIFIER(value)) {
kmi->keymodifier = value;
}
else {
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 06edf6f443e..9e41d8c03fc 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -313,7 +313,7 @@ static wmKeyMapItem *rna_KeyMap_item_new_from_item(wmKeyMap *km,
wmKeyMapItem *kmi_src,
bool head)
{
- /* wmWindowManager *wm = CTX_wm_manager(C); */
+ // wmWindowManager *wm = CTX_wm_manager(C);
if ((km->flag & KEYMAP_MODAL) == (kmi_src->idname[0] != '\0')) {
BKE_report(reports, RPT_ERROR, "Can not mix modal/non-modal items");
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index c30beaf001a..bb933ba97a5 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -114,7 +114,7 @@ set(SRC
intern/MOD_weightvgedit.c
intern/MOD_weightvgmix.c
intern/MOD_weightvgproximity.c
- intern/MOD_weld.c
+ intern/MOD_weld.cc
intern/MOD_wireframe.c
MOD_modifiertypes.h
@@ -236,7 +236,6 @@ endif()
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_SIMULATION_DATABLOCK)
- add_definitions(-DWITH_POINT_CLOUD)
add_definitions(-DWITH_HAIR_NODES)
endif()
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 2f0f11ab56d..56db68b163c 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -285,7 +285,8 @@ static void mesh_merge_transform(Mesh *result,
int cap_nloops,
int cap_npolys,
int *remap,
- int remap_len)
+ int remap_len,
+ const bool recalc_normals_later)
{
int *index_orig;
int i;
@@ -307,6 +308,15 @@ static void mesh_merge_transform(Mesh *result,
mv->flag = mv->bweight = 0;
}
+ /* We have to correct normals too, if we do not tag them as dirty later! */
+ if (!recalc_normals_later) {
+ float(*dst_vert_normals)[3] = BKE_mesh_vertex_normals_for_write(result);
+ for (i = 0; i < cap_nverts; i++) {
+ mul_mat3_m4_v3(cap_offset, dst_vert_normals[cap_verts_index + i]);
+ normalize_v3(dst_vert_normals[cap_verts_index + i]);
+ }
+ }
+
/* remap the vertex groups if necessary */
if (result->dvert != NULL) {
BKE_object_defgroup_index_map_apply(
@@ -360,7 +370,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
Mesh *mesh)
{
const MVert *src_mvert;
- MVert *mv, *mv_prev, *result_dm_verts;
+ MVert *result_dm_verts;
MEdge *me;
MLoop *ml;
@@ -572,6 +582,14 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
first_chunk_nverts = chunk_nverts;
unit_m4(current_offset);
+ const float(*src_vert_normals)[3] = NULL;
+ float(*dst_vert_normals)[3] = NULL;
+ if (!use_recalc_normals) {
+ src_vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+ dst_vert_normals = BKE_mesh_vertex_normals_for_write(result);
+ BKE_mesh_vertex_normals_clear_dirty(result);
+ }
+
for (c = 1; c < count; c++) {
/* copy customdata to new geometry */
CustomData_copy_data(&mesh->vdata, &result->vdata, 0, c * chunk_nverts, chunk_nverts);
@@ -579,23 +597,21 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
CustomData_copy_data(&mesh->ldata, &result->ldata, 0, c * chunk_nloops, chunk_nloops);
CustomData_copy_data(&mesh->pdata, &result->pdata, 0, c * chunk_npolys, chunk_npolys);
- mv_prev = result_dm_verts;
- mv = mv_prev + c * chunk_nverts;
+ const int vert_offset = c * chunk_nverts;
/* recalculate cumulative offset here */
mul_m4_m4m4(current_offset, current_offset, offset);
/* apply offset to all new verts */
- for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) {
- mul_m4_v3(current_offset, mv->co);
+ for (i = 0; i < chunk_nverts; i++) {
+ const int i_dst = vert_offset + i;
+ mul_m4_v3(current_offset, result_dm_verts[i_dst].co);
/* We have to correct normals too, if we do not tag them as dirty! */
if (!use_recalc_normals) {
- float no[3];
- normal_short_to_float_v3(no, mv->no);
- mul_mat3_m4_v3(current_offset, no);
- normalize_v3(no);
- normal_float_to_short_v3(mv->no, no);
+ copy_v3_v3(dst_vert_normals[i_dst], src_vert_normals[i]);
+ mul_mat3_m4_v3(current_offset, dst_vert_normals[i_dst]);
+ normalize_v3(dst_vert_normals[i_dst]);
}
}
@@ -711,7 +727,8 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
start_cap_nloops,
start_cap_npolys,
vgroup_start_cap_remap,
- vgroup_start_cap_remap_len);
+ vgroup_start_cap_remap_len,
+ use_recalc_normals);
/* Identify doubles with first chunk */
if (use_merge) {
dm_mvert_map_doubles(full_doubles_map,
@@ -740,7 +757,8 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
end_cap_nloops,
end_cap_npolys,
vgroup_end_cap_remap,
- vgroup_end_cap_remap_len);
+ vgroup_end_cap_remap_len,
+ use_recalc_normals);
/* Identify doubles with last chunk */
if (use_merge) {
dm_mvert_map_doubles(full_doubles_map,
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index f8c181905b5..bb05ae3e1b3 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -248,9 +248,14 @@ static BMesh *BMD_mesh_bm_create(
BMeshCreateParams bmesh_create_params{};
BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
- /* Needed so active layers are set based on `mesh` not `mesh_operand_ob`,
- * otherwise the wrong active render layer is used, see T92384. */
- BM_mesh_copy_init_customdata_from_mesh(bm, mesh, &allocsize);
+ /* Keep `mesh` first, needed so active layers are set based on `mesh` not `mesh_operand_ob`,
+ * otherwise the wrong active render layer is used, see T92384.
+ *
+ * NOTE: while initializing customer data layers the is not essential,
+ * it avoids the overhead of having to re-allocate #BMHeader.data when the 2nd mesh is added
+ * (if it contains additional custom-data layers). */
+ const Mesh *mesh_array[2] = {mesh, mesh_operand_ob};
+ BM_mesh_copy_init_customdata_from_mesh_array(bm, mesh_array, ARRAY_SIZE(mesh_array), &allocsize);
BMeshFromMeshParams bmesh_from_mesh_params{};
bmesh_from_mesh_params.calc_face_normal = true;
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 6cd8d70383d..86f0df1418b 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -280,9 +280,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, struct
MEM_freeN(edgeMap);
MEM_freeN(faceMap);
- if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- BKE_mesh_normals_tag_dirty(result);
- }
+ BKE_mesh_normals_tag_dirty(result);
/* TODO(sybren): also copy flags & tags? */
return result;
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 9e8f5bee396..49ff4acb31f 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -588,7 +588,7 @@ static void correctivesmooth_modifier_do(ModifierData *md,
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
const bool force_delta_cache_update =
- /* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
+ /* XXX, take care! if mesh data itself changes we need to forcefully recalculate deltas */
!cache_settings_equal(csmd) ||
((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
(((ID *)ob->data)->recalc & ID_RECALC_ALL));
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 07da18f990d..010292d2ebb 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -177,6 +177,7 @@ typedef struct DisplaceUserdata {
float (*vertexCos)[3];
float local_mat[4][4];
MVert *mvert;
+ const float (*vert_normals)[3];
float (*vert_clnors)[3];
} DisplaceUserdata;
@@ -194,7 +195,6 @@ static void displaceModifier_do_task(void *__restrict userdata,
bool use_global_direction = data->use_global_direction;
float(*tex_co)[3] = data->tex_co;
float(*vertexCos)[3] = data->vertexCos;
- MVert *mvert = data->mvert;
float(*vert_clnors)[3] = data->vert_clnors;
const float delta_fixed = 1.0f -
@@ -272,9 +272,7 @@ static void displaceModifier_do_task(void *__restrict userdata,
add_v3_v3(vertexCos[iter], local_vec);
break;
case MOD_DISP_DIR_NOR:
- vertexCos[iter][0] += delta * (mvert[iter].no[0] / 32767.0f);
- vertexCos[iter][1] += delta * (mvert[iter].no[1] / 32767.0f);
- vertexCos[iter][2] += delta * (mvert[iter].no[2] / 32767.0f);
+ madd_v3_v3fl(vertexCos[iter], data->vert_normals[iter], delta);
break;
case MOD_DISP_DIR_CLNOR:
madd_v3_v3fl(vertexCos[iter], vert_clnors[iter], delta);
@@ -363,6 +361,9 @@ static void displaceModifier_do(DisplaceModifierData *dmd,
data.vertexCos = vertexCos;
copy_m4_m4(data.local_mat, local_mat);
data.mvert = mvert;
+ if (direction == MOD_DISP_DIR_NOR) {
+ data.vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+ }
data.vert_clnors = vert_clnors;
if (tex_target != NULL) {
data.pool = BKE_image_pool_new();
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 493b59b3a1a..68d6b4a3626 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -1118,7 +1118,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* finalization */
BKE_mesh_calc_edges_tessface(explode);
BKE_mesh_convert_mfaces_to_mpolys(explode);
- explode->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(explode);
if (psmd->psys->lattice_deform_data) {
BKE_lattice_deform_data_destroy(psmd->psys->lattice_deform_data);
diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc
index f452b0c7091..0de8b26a1b7 100644
--- a/source/blender/modifiers/intern/MOD_mask.cc
+++ b/source/blender/modifiers/intern/MOD_mask.cc
@@ -70,19 +70,6 @@ using blender::MutableSpan;
using blender::Span;
using blender::Vector;
-/* For delete geometry node. */
-void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span<int> vertex_map);
-void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- Span<int> vertex_map,
- Span<int> edge_map);
-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);
-
static void initData(ModifierData *md)
{
MaskModifierData *mmd = (MaskModifierData *)md;
@@ -355,7 +342,9 @@ static void compute_interpolated_polygons(const Mesh *mesh,
*r_num_add_loops = num_add_loops;
}
-void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span<int> vertex_map)
+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()) {
@@ -438,16 +427,6 @@ static void add_interp_verts_copy_edges_to_new_mesh(const Mesh &src_mesh,
MVert &v2 = src_mesh.mvert[e_src.v2];
interp_v3_v3v3(v.co, v1.co, v2.co, fac);
-
- float no1[3];
- float no2[3];
- normal_short_to_float_v3(no1, v1.no);
- normal_short_to_float_v3(no2, v2.no);
- mul_v3_fl(no1, weights[0]);
- madd_v3_v3fl(no1, no2, weights[1]);
- normalize_v3(no1);
- normal_float_to_short_v3(v.no, no1);
-
vert_index++;
}
}
@@ -455,10 +434,10 @@ static void add_interp_verts_copy_edges_to_new_mesh(const Mesh &src_mesh,
BLI_assert(edge_index == num_masked_edges);
}
-void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- Span<int> vertex_map,
- Span<int> edge_map)
+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());
@@ -508,35 +487,6 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
}
}
}
-void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
- Mesh &dst_mesh,
- Span<int> vertex_map,
- Span<int> edge_map,
- Span<int> masked_poly_indices,
- Span<int> new_loop_starts)
-{
- for (const int i_dst : masked_poly_indices.index_range()) {
- const int i_src = masked_poly_indices[i_dst];
-
- const MPoly &mp_src = src_mesh.mpoly[i_src];
- MPoly &mp_dst = dst_mesh.mpoly[i_dst];
- const int i_ml_src = mp_src.loopstart;
- const int i_ml_dst = new_loop_starts[i_dst];
-
- CustomData_copy_data(&src_mesh.pdata, &dst_mesh.pdata, i_src, i_dst, 1);
- CustomData_copy_data(&src_mesh.ldata, &dst_mesh.ldata, i_ml_src, i_ml_dst, mp_src.totloop);
-
- const MLoop *ml_src = src_mesh.mloop + i_ml_src;
- MLoop *ml_dst = dst_mesh.mloop + i_ml_dst;
-
- mp_dst = mp_src;
- mp_dst.loopstart = i_ml_dst;
- for (int i : IndexRange(mp_src.totloop)) {
- ml_dst[i].v = vertex_map[ml_src[i].v];
- ml_dst[i].e = edge_map[ml_src[i].e];
- }
- }
-}
static void add_interpolated_polys_to_new_mesh(const Mesh &src_mesh,
Mesh &dst_mesh,
@@ -702,7 +652,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx)
Object *armature_ob = mmd->ob_arm;
/* Return input mesh if there is no armature with bones. */
- if (ELEM(NULL, armature_ob, armature_ob->pose)) {
+ if (ELEM(nullptr, armature_ob, armature_ob->pose)) {
return mesh;
}
diff --git a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
index 778b5746471..910b52dea67 100644
--- a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
+++ b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
@@ -197,8 +197,8 @@ static float compute_voxel_size(const ModifierEvalContext *ctx,
/* Compute the voxel size based on the desired number of voxels and the approximated bounding box
* of the volume. */
const BoundBox *bb = BKE_object_boundbox_get(mvmd->object);
- const float diagonal = float3::distance(transform * float3(bb->vec[6]),
- transform * float3(bb->vec[0]));
+ const float diagonal = math::distance(transform * float3(bb->vec[6]),
+ transform * float3(bb->vec[0]));
const float approximate_volume_side_length = diagonal + mvmd->exterior_band_width * 2.0f;
const float voxel_size = approximate_volume_side_length / mvmd->voxel_amount / volume_simplify;
return voxel_size;
diff --git a/source/blender/modifiers/intern/MOD_meshcache_util.h b/source/blender/modifiers/intern/MOD_meshcache_util.h
index 74131099e3c..b1a8a3ffc19 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_util.h
+++ b/source/blender/modifiers/intern/MOD_meshcache_util.h
@@ -23,52 +23,45 @@
/* MOD_meshcache_mdd.c */
bool MOD_meshcache_read_mdd_index(FILE *fp,
float (*vertexCos)[3],
- const int vertex_tot,
- const int index,
- const float factor,
+ int vertex_tot,
+ int index,
+ float factor,
const char **err_str);
bool MOD_meshcache_read_mdd_frame(FILE *fp,
float (*vertexCos)[3],
- const int verts_tot,
- const char interp,
- const float frame,
+ int verts_tot,
+ char interp,
+ float frame,
const char **err_str);
bool MOD_meshcache_read_mdd_times(const char *filepath,
float (*vertexCos)[3],
- const int verts_tot,
- const char interp,
- const float time,
- const float fps,
- const char time_mode,
+ int verts_tot,
+ char interp,
+ float time,
+ float fps,
+ char time_mode,
const char **err_str);
/* MOD_meshcache_pc2.c */
-bool MOD_meshcache_read_pc2_index(FILE *fp,
- float (*vertexCos)[3],
- const int verts_tot,
- const int index,
- const float factor,
- const char **err_str);
+bool MOD_meshcache_read_pc2_index(
+ FILE *fp, float (*vertexCos)[3], int verts_tot, int index, float factor, const char **err_str);
bool MOD_meshcache_read_pc2_frame(FILE *fp,
float (*vertexCos)[3],
- const int verts_tot,
- const char interp,
- const float frame,
+ int verts_tot,
+ char interp,
+ float frame,
const char **err_str);
bool MOD_meshcache_read_pc2_times(const char *filepath,
float (*vertexCos)[3],
- const int verts_tot,
- const char interp,
- const float time,
- const float fps,
- const char time_mode,
+ int verts_tot,
+ char interp,
+ float time,
+ float fps,
+ char time_mode,
const char **err_str);
/* MOD_meshcache_util.c */
-void MOD_meshcache_calc_range(const float frame,
- const char interp,
- const int frame_tot,
- int r_index_range[2],
- float *r_factor);
+void MOD_meshcache_calc_range(
+ float frame, char interp, int frame_tot, int r_index_range[2], float *r_factor);
#define FRAME_SNAP_EPS 0.0001f
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index bcaf294ec8b..e1459ccba6d 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -328,14 +328,105 @@ static void panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, ptr, "use_vertex_interpolation", 0, NULL, ICON_NONE);
}
+ modifier_panel_end(layout, ptr);
+}
+
+static void velocity_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
+ return;
+ }
+
+ if (RNA_pointer_is_null(&fileptr)) {
+ return;
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiTemplateCacheFileVelocity(layout, &fileptr);
uiItemR(layout, ptr, "velocity_scale", 0, NULL, ICON_NONE);
+}
- modifier_panel_end(layout, ptr);
+static void time_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
+ return;
+ }
+
+ if (RNA_pointer_is_null(&fileptr)) {
+ return;
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiTemplateCacheFileTimeSettings(layout, &fileptr);
+}
+
+static void render_procedural_panel_draw(const bContext *C, Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
+ return;
+ }
+
+ if (RNA_pointer_is_null(&fileptr)) {
+ return;
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiTemplateCacheFileProcedural(layout, C, &fileptr);
+}
+
+static void override_layers_panel_draw(const bContext *C, Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
+ return;
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiTemplateCacheFileLayers(layout, C, &fileptr);
}
static void panelRegister(ARegionType *region_type)
{
- modifier_panel_register(region_type, eModifierType_MeshSequenceCache, panel_draw);
+ PanelType *panel_type = modifier_panel_register(
+ region_type, eModifierType_MeshSequenceCache, panel_draw);
+ modifier_subpanel_register(region_type, "time", "Time", NULL, time_panel_draw, panel_type);
+ modifier_subpanel_register(region_type,
+ "render_procedural",
+ "Render Procedural",
+ NULL,
+ render_procedural_panel_draw,
+ panel_type);
+ modifier_subpanel_register(
+ region_type, "velocity", "Velocity", NULL, velocity_panel_draw, panel_type);
+ modifier_subpanel_register(region_type,
+ "override_layers",
+ "Override Layers",
+ NULL,
+ override_layers_panel_draw,
+ panel_type);
}
static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 79838f61dfe..49528845197 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -28,8 +28,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
-#include "BLI_float3.hh"
#include "BLI_listbase.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_multi_value_map.hh"
#include "BLI_set.hh"
#include "BLI_string.h"
@@ -60,6 +60,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
@@ -237,7 +238,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
DEG_add_modifier_to_transform_relation(ctx->node, "Nodes Modifier");
if (nmd->node_group != nullptr) {
- DEG_add_node_tree_relation(ctx->node, nmd->node_group, "Nodes Modifier");
+ DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier");
Set<ID *> used_ids;
find_used_ids_from_settings(nmd->settings, used_ids);
@@ -268,18 +269,19 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
-static bool checkForTimeNode(bNodeTree *tree, Set<bNodeTree *> &r_checked_trees)
+static bool check_tree_for_time_node(const bNodeTree &tree,
+ Set<const bNodeTree *> &r_checked_trees)
{
- if (!r_checked_trees.add(tree)) {
+ if (!r_checked_trees.add(&tree)) {
return false;
}
- LISTBASE_FOREACH (bNode *, node, &tree->nodes) {
+ LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
return true;
}
if (node->type == NODE_GROUP) {
- bNodeTree *subtree = (bNodeTree *)node->id;
- if (checkForTimeNode(subtree, r_checked_trees)) {
+ 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;
}
}
@@ -291,13 +293,13 @@ static bool dependsOnTime(struct Scene *UNUSED(scene),
ModifierData *md,
const int UNUSED(dag_eval_mode))
{
- NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
- bNodeTree *tree = nmd->node_group;
+ const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ const bNodeTree *tree = nmd->node_group;
if (tree == nullptr) {
return false;
}
- Set<bNodeTree *> checked_trees;
- return checkForTimeNode(tree, checked_trees);
+ 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)
@@ -724,7 +726,7 @@ void MOD_nodes_init(Main *bmain, NodesModifierData *nmd)
group_input_node,
(bNodeSocket *)group_input_node->outputs.first);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, nullptr);
}
static void initialize_group_input(NodesModifierData &nmd,
@@ -1293,7 +1295,7 @@ static void add_attribute_search_button(const bContext &C,
return;
}
- AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData);
+ AttributeSearchData *data = MEM_new<AttributeSearchData>(__func__);
data->object_session_uid = object->id.session_uuid;
STRNCPY(data->modifier_name, nmd.modifier.name);
STRNCPY(data->socket_identifier, socket.identifier);
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index 4e808120f4a..5362d86a87f 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -66,31 +66,55 @@ struct SingleInputValue {
void *value = nullptr;
};
-struct MultiInputValueItem {
- /**
- * The socket where this value is coming from. This is required to sort the inputs correctly
- * based on the link order later on.
- */
- DSocket origin;
+struct MultiInputValue {
/**
- * Should only be null directly after construction. After that it should always point to a value
- * of the correct type.
+ * Ordered sockets connected to this multi-input.
*/
- void *value = nullptr;
-};
-
-struct MultiInputValue {
+ Vector<DSocket> origins;
/**
- * Collection of all the inputs that have been provided already. Note, the same origin can occur
- * multiple times. However, it is guaranteed that if two items have the same origin, they will
- * also have the same value (the pointer is different, but they point to values that would
- * compare equal).
+ * A value for every origin socket. The order is determined by #origins.
+ * Note, the same origin can occur multiple times. However, it is guaranteed that values coming
+ * from the same origin have the same value (the pointer is different, but they point to values
+ * that would compare equal).
*/
- Vector<MultiInputValueItem> items;
+ Vector<void *> values;
/**
- * Number of items that need to be added until all inputs have been provided.
+ * Number of non-null values.
*/
- int expected_size = 0;
+ int provided_value_count = 0;
+
+ bool all_values_available() const
+ {
+ return this->missing_values() == 0;
+ }
+
+ int missing_values() const
+ {
+ return this->values.size() - this->provided_value_count;
+ }
+
+ void add_value(const DSocket origin, void *value)
+ {
+ const int index = this->find_available_index(origin);
+ this->values[index] = value;
+ this->provided_value_count++;
+ }
+
+ private:
+ int find_available_index(DSocket origin) const
+ {
+ for (const int i : origins.index_range()) {
+ if (values[i] != nullptr) {
+ continue;
+ }
+ if (origins[i] != origin) {
+ continue;
+ }
+ return i;
+ }
+ BLI_assert_unreachable();
+ return -1;
+ }
};
struct InputState {
@@ -211,9 +235,10 @@ struct NodeState {
MutableSpan<OutputState> outputs;
/**
- * Nodes that don't support laziness have some special handling the first time they are executed.
+ * Most nodes have inputs that are always required. Those have special handling to avoid an extra
+ * call to the node execution function.
*/
- bool non_lazy_node_is_initialized = false;
+ bool non_lazy_inputs_handled = false;
/**
* Used to check that nodes that don't support laziness do not run more than once.
@@ -356,6 +381,11 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value)
new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>(side));
return true;
}
+ if (bnode.type == GEO_NODE_EXTRUDE_MESH) {
+ new (r_value)
+ ValueOrField<float3>(Field<float3>(std::make_shared<bke::NormalFieldInput>()));
+ return true;
+ }
new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position"));
return true;
}
@@ -556,13 +586,14 @@ class GeometryNodesEvaluator {
/* Construct the correct struct that can hold the input(s). */
if (socket->is_multi_input_socket()) {
input_state.value.multi = allocator.construct<MultiInputValue>().release();
+ MultiInputValue &multi_value = *input_state.value.multi;
/* Count how many values should be added until the socket is complete. */
- socket.foreach_origin_socket(
- [&](DSocket UNUSED(origin)) { input_state.value.multi->expected_size++; });
+ socket.foreach_origin_socket([&](DSocket origin) { multi_value.origins.append(origin); });
/* If no links are connected, we do read the value from socket itself. */
- if (input_state.value.multi->expected_size == 0) {
- input_state.value.multi->expected_size = 1;
+ if (multi_value.origins.is_empty()) {
+ multi_value.origins.append(socket);
}
+ multi_value.values.resize(multi_value.origins.size(), nullptr);
}
else {
input_state.value.single = allocator.construct<SingleInputValue>().release();
@@ -623,8 +654,10 @@ class GeometryNodesEvaluator {
const InputSocketRef &socket_ref = node->input(i);
if (socket_ref.is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- for (MultiInputValueItem &item : multi_value.items) {
- input_state.type->destruct(item.value);
+ for (void *value : multi_value.values) {
+ if (value != nullptr) {
+ input_state.type->destruct(value);
+ }
}
multi_value.~MultiInputValue();
}
@@ -774,12 +807,12 @@ class GeometryNodesEvaluator {
if (!this->prepare_node_outputs_for_execution(locked_node)) {
return;
}
- /* Initialize nodes that don't support laziness. This is done after at least one output is
+ /* Initialize inputs that don't support laziness. This is done after at least one output is
* required and before we check that all required inputs are provided. This reduces the
* number of "round-trips" through the task pool by one for most nodes. */
- if (!node_state.non_lazy_node_is_initialized && !node_supports_laziness(node)) {
- this->initialize_non_lazy_node(locked_node);
- node_state.non_lazy_node_is_initialized = true;
+ if (!node_state.non_lazy_inputs_handled) {
+ this->require_non_lazy_inputs(locked_node);
+ node_state.non_lazy_inputs_handled = true;
}
/* Prepare inputs and check if all required inputs are provided. */
if (!this->prepare_node_inputs_for_execution(locked_node)) {
@@ -853,17 +886,27 @@ class GeometryNodesEvaluator {
return execution_is_necessary;
}
- void initialize_non_lazy_node(LockedNode &locked_node)
+ void require_non_lazy_inputs(LockedNode &locked_node)
+ {
+ this->foreach_non_lazy_input(locked_node, [&](const DInputSocket socket) {
+ this->set_input_required(locked_node, socket);
+ });
+ }
+
+ void foreach_non_lazy_input(LockedNode &locked_node, FunctionRef<void(DInputSocket socket)> fn)
{
+ if (node_supports_laziness(locked_node.node)) {
+ /* In the future only some of the inputs may support laziness. */
+ return;
+ }
+ /* Nodes that don't support laziness require all inputs. */
for (const int i : locked_node.node->inputs().index_range()) {
InputState &input_state = locked_node.node_state.inputs[i];
if (input_state.type == nullptr) {
/* Ignore unavailable/non-data sockets. */
continue;
}
- /* Nodes that don't support laziness require all inputs. */
- const DInputSocket input_socket = locked_node.node.input(i);
- this->set_input_required(locked_node, input_socket);
+ fn(locked_node.node.input(i));
}
}
@@ -892,7 +935,7 @@ class GeometryNodesEvaluator {
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
/* Checks if all the linked sockets have been provided already. */
- if (multi_value.items.size() == multi_value.expected_size) {
+ if (multi_value.all_values_available()) {
input_state.was_ready_for_execution = true;
}
else if (is_required) {
@@ -1243,7 +1286,7 @@ class GeometryNodesEvaluator {
int missing_values = 0;
if (input_socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- missing_values = multi_value.expected_size - multi_value.items.size();
+ missing_values = multi_value.missing_values();
}
else {
SingleInputValue &single_value = *input_state.value.single;
@@ -1501,10 +1544,10 @@ class GeometryNodesEvaluator {
if (socket->is_multi_input_socket()) {
/* Add a new value to the multi-input. */
MultiInputValue &multi_value = *input_state.value.multi;
- multi_value.items.append({origin, value.get()});
+ multi_value.add_value(origin, value.get());
- if (multi_value.expected_size == multi_value.items.size()) {
- this->log_socket_value({socket}, input_state, multi_value.items);
+ if (multi_value.all_values_available()) {
+ this->log_socket_value({socket}, input_state, multi_value.values);
}
}
else {
@@ -1543,9 +1586,9 @@ class GeometryNodesEvaluator {
GMutablePointer value = this->get_value_from_socket(origin_socket, *input_state.type);
if (input_socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- multi_value.items.append({origin_socket, value.get()});
- if (multi_value.expected_size == multi_value.items.size()) {
- this->log_socket_value({input_socket}, input_state, multi_value.items);
+ multi_value.add_value(origin_socket, value.get());
+ if (multi_value.all_values_available()) {
+ this->log_socket_value({input_socket}, input_state, multi_value.values);
}
}
else {
@@ -1568,10 +1611,13 @@ class GeometryNodesEvaluator {
InputState &input_state = locked_node.node_state.inputs[socket->index()];
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- for (MultiInputValueItem &item : multi_value.items) {
- input_state.type->destruct(item.value);
+ for (void *&value : multi_value.values) {
+ if (value != nullptr) {
+ input_state.type->destruct(value);
+ value = nullptr;
+ }
}
- multi_value.items.clear();
+ multi_value.provided_value_count = 0;
}
else {
SingleInputValue &single_value = *input_state.value.single;
@@ -1653,7 +1699,7 @@ class GeometryNodesEvaluator {
return *node_states_.lookup_key_as(node).state;
}
- void log_socket_value(DSocket socket, InputState &input_state, Span<MultiInputValueItem> values)
+ void log_socket_value(DSocket socket, InputState &input_state, Span<void *> values)
{
if (params_.geo_logger == nullptr) {
return;
@@ -1662,8 +1708,8 @@ class GeometryNodesEvaluator {
Vector<GPointer, 16> value_pointers;
value_pointers.reserve(values.size());
const CPPType &type = *input_state.type;
- for (const MultiInputValueItem &item : values) {
- value_pointers.append({type, item.value});
+ for (const void *value : values) {
+ value_pointers.append({type, value});
}
params_.geo_logger->local().log_multi_value_socket(socket, value_pointers);
}
@@ -1749,7 +1795,7 @@ bool NodeParamsProvider::can_get_input(StringRef identifier) const
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- return multi_value.items.size() == multi_value.expected_size;
+ return multi_value.all_values_available();
}
SingleInputValue &single_value = *input_state.value.single;
return single_value.value != nullptr;
@@ -1789,25 +1835,11 @@ Vector<GMutablePointer> NodeParamsProvider::extract_multi_input(StringRef identi
MultiInputValue &multi_value = *input_state.value.multi;
Vector<GMutablePointer> ret_values;
- socket.foreach_origin_socket([&](DSocket origin) {
- for (MultiInputValueItem &item : multi_value.items) {
- if (item.origin == origin && item.value != nullptr) {
- ret_values.append({*input_state.type, item.value});
- /* Make sure we do not use the same value again if two values have the same origin. */
- item.value = nullptr;
- return;
- }
- }
- BLI_assert_unreachable();
- });
- if (ret_values.is_empty()) {
- /* If the socket is not linked, we just use the value from the socket itself. */
- BLI_assert(multi_value.items.size() == 1);
- MultiInputValueItem &item = multi_value.items[0];
- BLI_assert(item.origin == socket);
- ret_values.append({*input_state.type, item.value});
- }
- multi_value.items.clear();
+ for (void *&value : multi_value.values) {
+ BLI_assert(value != nullptr);
+ ret_values.append({*input_state.type, value});
+ value = nullptr;
+ }
return ret_values;
}
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index db2eedf9c02..61099fedf46 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -227,7 +227,7 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
Mesh *mesh,
short (*clnors)[2],
float (*loopnors)[3],
- float (*polynors)[3],
+ const float (*polynors)[3],
const short mix_mode,
const float mix_factor,
const float mix_limit,
@@ -334,14 +334,16 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
}
if (do_polynors_fix &&
- polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) {
+ polygons_check_flip(
+ mloop, nos, &mesh->ldata, mpoly, BKE_mesh_poly_normals_for_write(mesh), num_polys)) {
/* XXX TODO: is this still needed? */
// mesh->dirty |= DM_DIRTY_TESS_CDLAYERS;
/* We need to recompute vertex normals! */
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
}
BKE_mesh_normals_loop_custom_set(mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
num_verts,
medge,
num_edges,
@@ -349,7 +351,7 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
nos,
num_loops,
mpoly,
- (const float(*)[3])polynors,
+ polynors,
num_polys,
clnors);
@@ -364,7 +366,7 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
Mesh *mesh,
short (*clnors)[2],
float (*loopnors)[3],
- float (*polynors)[3],
+ const float (*polynors)[3],
const short mix_mode,
const float mix_factor,
const float mix_limit,
@@ -449,11 +451,13 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
}
if (do_polynors_fix &&
- polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) {
+ polygons_check_flip(
+ mloop, nos, &mesh->ldata, mpoly, BKE_mesh_poly_normals_for_write(mesh), num_polys)) {
BKE_mesh_normals_tag_dirty(mesh);
}
BKE_mesh_normals_loop_custom_set(mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
num_verts,
medge,
num_edges,
@@ -461,7 +465,7 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
nos,
num_loops,
mpoly,
- (const float(*)[3])polynors,
+ polynors,
num_polys,
clnors);
@@ -545,26 +549,10 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
float(*loopnors)[3] = NULL;
short(*clnors)[2] = NULL;
- float(*polynors)[3];
-
CustomData *ldata = &result->ldata;
- /* Compute poly (always needed) and vert normals. */
- CustomData *pdata = &result->pdata;
- polynors = CustomData_get_layer(pdata, CD_NORMAL);
- if (!polynors) {
- polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, num_polys);
- CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (result->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- BKE_mesh_calc_normals_poly_and_vertex(
- mvert, num_verts, mloop, num_loops, mpoly, num_polys, polynors, NULL);
- }
- else {
- BKE_mesh_calc_normals_poly(mvert, num_verts, mloop, num_loops, mpoly, num_polys, polynors);
- }
-
- result->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ const float(*poly_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
if (use_current_clnors) {
@@ -572,6 +560,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
loopnors = MEM_malloc_arrayN((size_t)num_loops, sizeof(*loopnors), __func__);
BKE_mesh_normals_loop_split(mvert,
+ vert_normals,
num_verts,
medge,
num_edges,
@@ -579,7 +568,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
loopnors,
num_loops,
mpoly,
- (const float(*)[3])polynors,
+ poly_normals,
num_polys,
true,
result->smoothresh,
@@ -601,7 +590,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
result,
clnors,
loopnors,
- polynors,
+ poly_normals,
enmd->mix_mode,
enmd->mix_factor,
enmd->mix_limit,
@@ -624,7 +613,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
result,
clnors,
loopnors,
- polynors,
+ poly_normals,
enmd->mix_mode,
enmd->mix_factor,
enmd->mix_limit,
@@ -641,8 +630,6 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
num_polys);
}
- /* Currently Modifier stack assumes there is no poly normal data passed around... */
- CustomData_free_layers(pdata, CD_NORMAL, num_polys);
MEM_SAFE_FREE(loopnors);
result->runtime.is_original = false;
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 4566cf93dd7..d821caf25a7 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -376,7 +376,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
result = generate_ocean_geometry(omd, mesh, resolution);
- BKE_mesh_ensure_normals(result);
+ BKE_mesh_normals_tag_dirty(result);
}
else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
result = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE);
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index f24f6951690..f5db3bced7a 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -395,6 +395,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
medge_orig = mesh->medge;
mvert_new = result->mvert;
+ float(*vert_normals_new)[3] = BKE_mesh_vertex_normals_for_write(result);
+ BKE_mesh_vertex_normals_clear_dirty(result);
mpoly_new = result->mpoly;
mloop_new = result->mloop;
medge_new = result->medge;
@@ -835,7 +837,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
normalize_v3(vc->no);
- normal_float_to_short_v3(mvert_new[i].no, vc->no);
+ copy_v3_v3(vert_normals_new[i], vc->no);
/* Done with normals */
}
@@ -884,7 +886,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
mul_v3_m3v3(nor_tx, mat3, vert_connect[j].no);
/* set the normal now its transformed */
- normal_float_to_short_v3(mv_new->no, nor_tx);
+ copy_v3_v3(vert_normals_new[mv_new - mvert_new], nor_tx);
}
/* set location */
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index 20d65b9d9f8..fa8d08bf839 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -43,20 +43,6 @@
#endif
/* -------------------------------------------------------------------- */
-/** \name Local Utilities
- * \{ */
-
-/* specific function for solidify - define locally */
-BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f)
-{
- r[0] += (float)a[0] * f;
- r[1] += (float)a[1] * f;
- r[2] += (float)a[2] * f;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name High Quality Normal Calculation Function
* \{ */
@@ -81,20 +67,18 @@ BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
* \param poly_nors: Precalculated face normals.
* \param r_vert_nors: Return vert normals.
*/
-static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_vert_nors)[3])
+static void mesh_calc_hq_normal(Mesh *mesh, const float (*poly_nors)[3], float (*r_vert_nors)[3])
{
int i, numVerts, numEdges, numPolys;
MPoly *mpoly, *mp;
MLoop *mloop, *ml;
MEdge *medge, *ed;
- MVert *mvert, *mv;
numVerts = mesh->totvert;
numEdges = mesh->totedge;
numPolys = mesh->totpoly;
mpoly = mesh->mpoly;
medge = mesh->medge;
- mvert = mesh->mvert;
mloop = mesh->mloop;
/* we don't want to overwrite any referenced layers */
@@ -105,7 +89,6 @@ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_ver
cddm->mvert = mv;
#endif
- mv = mvert;
mp = mpoly;
{
@@ -171,9 +154,10 @@ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_ver
}
/* normalize vertex normals and assign */
- for (i = 0; i < numVerts; i++, mv++) {
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ for (i = 0; i < numVerts; i++) {
if (normalize_v3(r_vert_nors[i]) == 0.0f) {
- normal_short_to_float_v3(r_vert_nors[i], mv->no);
+ copy_v3_v3(r_vert_nors[i], vert_normals[i]);
}
}
}
@@ -220,7 +204,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
int *edge_order = NULL;
float(*vert_nors)[3] = NULL;
- float(*poly_nors)[3] = NULL;
+ const float(*poly_nors)[3] = NULL;
const bool need_poly_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) ||
(smd->flag & MOD_SOLIDIFY_EVEN) ||
@@ -249,6 +233,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
/* array size is doubled in case of using a shell */
const uint stride = do_shell ? 2 : 1;
+ const float(*mesh_vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+
MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
orig_mvert = mesh->mvert;
@@ -258,14 +244,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
if (need_poly_normals) {
/* calculate only face normals */
- poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
- BKE_mesh_calc_normals_poly(orig_mvert,
- (int)numVerts,
- orig_mloop,
- (int)numLoops,
- orig_mpoly,
- (int)numPolys,
- poly_nors);
+ poly_nors = BKE_mesh_poly_normals_ensure(mesh);
}
STACK_INIT(new_vert_arr, numVerts * 2);
@@ -636,7 +615,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
madd_v3_v3fl(mv->co, vert_nors[i], ofs_new_vgroup);
}
else {
- madd_v3v3short_fl(mv->co, mv->no, ofs_new_vgroup / 32767.0f);
+ madd_v3_v3fl(mv->co, mesh_vert_normals[i], ofs_new_vgroup);
}
}
}
@@ -687,7 +666,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
madd_v3_v3fl(mv->co, vert_nors[i], ofs_new_vgroup);
}
else {
- madd_v3v3short_fl(mv->co, mv->no, ofs_new_vgroup / 32767.0f);
+ madd_v3_v3fl(mv->co, mesh_vert_normals[i], ofs_new_vgroup);
}
}
}
@@ -740,7 +719,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
if (vert_nors == NULL) {
vert_nors = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "mod_solid_vno");
for (i = 0, mv = mvert; i < numVerts; i++, mv++) {
- normal_short_to_float_v3(vert_nors[i], mv->no);
+ copy_v3_v3(vert_nors[i], mesh_vert_normals[i]);
}
}
@@ -995,8 +974,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
uint i;
/* flip vertex normals for copied verts */
mv = mvert + numVerts;
- for (i = 0; i < numVerts; i++, mv++) {
- negate_v3_short(mv->no);
+ for (i = 0; i < numVerts; i++) {
+ negate_v3((float *)mesh_vert_normals[i]);
}
}
@@ -1201,7 +1180,6 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
ed = medge + (numEdges * stride);
for (i = 0; i < rimVerts; i++, ed++, ed_orig++) {
float nor_cpy[3];
- short *nor_short;
int k;
/* NOTE: only the first vertex (lower half of the index) is calculated. */
@@ -1209,11 +1187,10 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
normalize_v3_v3(nor_cpy, edge_vert_nos[ed_orig->v1]);
for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
- nor_short = mvert[*(&ed->v1 + k)].no;
- normal_short_to_float_v3(nor, nor_short);
+ copy_v3_v3(nor, mesh_vert_normals[*(&ed->v1 + k)]);
add_v3_v3(nor, nor_cpy);
normalize_v3(nor);
- normal_float_to_short_v3(nor_short, nor);
+ copy_v3_v3((float *)mesh_vert_normals[*(&ed->v1 + k)], nor);
}
}
@@ -1232,10 +1209,6 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
MEM_freeN(old_vert_arr);
}
- if (poly_nors) {
- MEM_freeN(poly_nors);
- }
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index 997f5943060..1aa52d44509 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -158,7 +158,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
const uint numVerts = (uint)mesh->totvert;
const uint numEdges = (uint)mesh->totedge;
const uint numPolys = (uint)mesh->totpoly;
- const uint numLoops = (uint)mesh->totloop;
if (numPolys == 0 && numVerts != 0) {
return mesh;
@@ -170,8 +169,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
const short mat_ofs = mat_nrs > 1 ? smd->mat_ofs : 0;
const short mat_ofs_rim = mat_nrs > 1 ? smd->mat_ofs_rim : 0;
- 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. */
@@ -217,10 +214,9 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
#define MOD_SOLIDIFY_EMPTY_TAG ((uint)-1)
- /* Calculate only face normals. */
- poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
- BKE_mesh_calc_normals_poly(
- orig_mvert, (int)numVerts, orig_mloop, (int)numLoops, orig_mpoly, (int)numPolys, poly_nors);
+ /* Calculate only face normals. Copied because they are modified directly below. */
+ float(*poly_nors)[3] = MEM_malloc_arrayN(numPolys, sizeof(float[3]), __func__);
+ memcpy(poly_nors, BKE_mesh_poly_normals_ensure(mesh), sizeof(float[3]) * numPolys);
NewFaceRef *face_sides_arr = MEM_malloc_arrayN(
numPolys * 2, sizeof(*face_sides_arr), "face_sides_arr in solidify");
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 7470f2abb15..a8c6687193b 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -39,6 +39,7 @@
#include "DNA_screen_types.h"
#include "BKE_context.h"
+#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -46,6 +47,7 @@
#include "BKE_subdiv_ccg.h"
#include "BKE_subdiv_deform.h"
#include "BKE_subdiv_mesh.h"
+#include "BKE_subdiv_modifier.h"
#include "BKE_subsurf.h"
#include "UI_interface.h"
@@ -65,11 +67,6 @@
#include "intern/CCGSubSurf.h"
-typedef struct SubsurfRuntimeData {
- /* Cached subdivision surface descriptor, with topology and settings. */
- struct Subdiv *subdiv;
-} SubsurfRuntimeData;
-
static void initData(ModifierData *md)
{
SubsurfModifierData *smd = (SubsurfModifierData *)md;
@@ -88,6 +85,9 @@ static void requiredDataMask(Object *UNUSED(ob),
r_cddata_masks->lmask |= CD_MASK_NORMAL;
r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
}
+ if (smd->flags & eSubsurfModifierFlag_UseCrease) {
+ r_cddata_masks->vmask |= CD_MASK_CREASE;
+ }
}
static bool dependsOnNormals(ModifierData *md)
@@ -155,37 +155,6 @@ static int subdiv_levels_for_modifier_get(const SubsurfModifierData *smd,
return get_render_subsurf_level(&scene->r, requested_levels, use_render_params);
}
-static void subdiv_settings_init(SubdivSettings *settings,
- const SubsurfModifierData *smd,
- const ModifierEvalContext *ctx)
-{
- const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER);
- const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels;
-
- settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
- settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
- settings->level = settings->is_simple ?
- 1 :
- (settings->is_adaptive ? smd->quality : requested_levels);
- settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
- settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
- smd->boundary_smooth);
- settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
- smd->uv_smooth);
-}
-
-/* Main goal of this function is to give usable subdivision surface descriptor
- * which matches settings and topology. */
-static Subdiv *subdiv_descriptor_ensure(SubsurfModifierData *smd,
- const SubdivSettings *subdiv_settings,
- const Mesh *mesh)
-{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
- Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh);
- runtime_data->subdiv = subdiv;
- return subdiv;
-}
-
/* Subdivide into fully qualified mesh. */
static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings,
@@ -240,14 +209,17 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
return result;
}
-static SubsurfRuntimeData *subsurf_ensure_runtime(SubsurfModifierData *smd)
+/* Cache settings for lazy CPU evaluation. */
+
+static void subdiv_cache_cpu_evaluation_settings(const ModifierEvalContext *ctx,
+ Mesh *me,
+ SubsurfModifierData *smd)
{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
- if (runtime_data == NULL) {
- runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
- smd->modifier.runtime = runtime_data;
- }
- return runtime_data;
+ SubdivToMeshSettings mesh_settings;
+ subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
+ me->runtime.subsurf_apply_render = (ctx->flag & MOD_APPLY_RENDER) != 0;
+ me->runtime.subsurf_resolution = mesh_settings.resolution;
+ me->runtime.subsurf_use_optimal_display = mesh_settings.use_optimal_display;
}
/* Modifier itself. */
@@ -261,12 +233,31 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
SubdivSettings subdiv_settings;
- subdiv_settings_init(&subdiv_settings, smd, ctx);
+ BKE_subsurf_modifier_subdiv_settings_init(
+ &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
if (subdiv_settings.level == 0) {
return result;
}
- SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd);
- Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh);
+ SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+
+ /* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier.
+ */
+ if ((ctx->flag & MOD_APPLY_TO_BASE_MESH) == 0) {
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ const bool is_render_mode = (ctx->flag & MOD_APPLY_RENDER) != 0;
+ /* Same check as in `DRW_mesh_batch_cache_create_requested` to keep both code coherent. The
+ * difference is that here we do not check for the final edit mesh pointer as it is not yet
+ * assigned at this stage of modifier stack evaluation. */
+ const bool is_editmode = (mesh->edit_mesh != NULL);
+ const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode);
+ if (BKE_subsurf_modifier_can_do_gpu_subdiv_ex(scene, ctx->object, smd, required_mode, false)) {
+ subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd);
+ return result;
+ }
+ }
+
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
+ smd, &subdiv_settings, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return result;
@@ -320,12 +311,14 @@ static void deformMatrices(ModifierData *md,
SubsurfModifierData *smd = (SubsurfModifierData *)md;
SubdivSettings subdiv_settings;
- subdiv_settings_init(&subdiv_settings, smd, ctx);
+ BKE_subsurf_modifier_subdiv_settings_init(
+ &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
if (subdiv_settings.level == 0) {
return;
}
- SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd);
- Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh);
+ SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
+ smd, &subdiv_settings, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return;
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 52d5f3e97ef..b713df05b80 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -48,17 +48,11 @@
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
-Mesh *triangulate_mesh(Mesh *mesh,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const int flag);
-
-Mesh *triangulate_mesh(Mesh *mesh,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const int flag)
+static Mesh *triangulate_mesh(Mesh *mesh,
+ const int quad_method,
+ const int ngon_method,
+ const int min_vertices,
+ const int flag)
{
Mesh *result;
BMesh *bm;
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 16ef65f7838..d04aee91c71 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -234,9 +234,11 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
}
+ /* TODO: Remove this "use_normals" argument, since the caller should retrieve normals afterwards
+ * if necessary. */
if (use_normals) {
if (LIKELY(mesh)) {
- BKE_mesh_ensure_normals(mesh);
+ BKE_mesh_vertex_normals_ensure(mesh);
}
}
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index a6fc2749e71..de02b55440a 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -51,9 +51,9 @@ struct Mesh *MOD_deform_mesh_eval_get(struct Object *ob,
struct BMEditMesh *em,
struct Mesh *mesh,
const float (*vertexCos)[3],
- const int num_verts,
- const bool use_normals,
- const bool use_orco);
+ int num_verts,
+ bool use_normals,
+ bool use_orco);
void MOD_get_vgroup(struct Object *ob,
struct Mesh *mesh,
diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc
index fcf75040a9a..a1ca29f454c 100644
--- a/source/blender/modifiers/intern/MOD_volume_displace.cc
+++ b/source/blender/modifiers/intern/MOD_volume_displace.cc
@@ -203,9 +203,10 @@ struct DisplaceGridOp {
template<typename GridType> void operator()()
{
- if constexpr (std::is_same_v<GridType, openvdb::points::PointDataGrid> ||
- std::is_same_v<GridType, openvdb::StringGrid> ||
- std::is_same_v<GridType, openvdb::MaskGrid>) {
+ if constexpr (blender::is_same_any_v<GridType,
+ openvdb::points::PointDataGrid,
+ openvdb::StringGrid,
+ openvdb::MaskGrid>) {
/* We don't support displacing these grid types yet. */
return;
}
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 03f8e3a1dfb..b7ab5dac388 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -163,8 +163,10 @@ static void waveModifier_do(WaveModifierData *md,
float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */
const bool invert_group = (wmd->flag & MOD_WAVE_INVERT_VGROUP) != 0;
+ const float(*vert_normals)[3] = NULL;
if ((wmd->flag & MOD_WAVE_NORM) && (mesh != NULL)) {
mvert = mesh->mvert;
+ vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
}
if (wmd->objectcenter != NULL) {
@@ -288,13 +290,13 @@ static void waveModifier_do(WaveModifierData *md,
if (mvert) {
/* move along normals */
if (wmd->flag & MOD_WAVE_NORM_X) {
- co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f;
+ co[0] += (lifefac * amplit) * vert_normals[i][0];
}
if (wmd->flag & MOD_WAVE_NORM_Y) {
- co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f;
+ co[1] += (lifefac * amplit) * vert_normals[i][1];
}
if (wmd->flag & MOD_WAVE_NORM_Z) {
- co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f;
+ co[2] += (lifefac * amplit) * vert_normals[i][2];
}
}
else {
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c
index 1ee64b935b7..bfe389eb080 100644
--- a/source/blender/modifiers/intern/MOD_weighted_normal.c
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.c
@@ -85,6 +85,7 @@ typedef struct WeightedNormalData {
const int numPolys;
MVert *mvert;
+ const float (*vert_normals)[3];
MEdge *medge;
MLoop *mloop;
@@ -93,7 +94,7 @@ typedef struct WeightedNormalData {
const float split_angle;
MPoly *mpoly;
- float (*polynors)[3];
+ const float (*polynors)[3];
int *poly_strength;
MDeformVert *dvert;
@@ -143,7 +144,7 @@ static void aggregate_item_normal(WeightedNormalModifierData *wnmd,
const float curr_val,
const bool use_face_influence)
{
- float(*polynors)[3] = wn_data->polynors;
+ const float(*polynors)[3] = wn_data->polynors;
MDeformVert *dvert = wn_data->dvert;
const int defgrp_index = wn_data->defgrp_index;
@@ -206,7 +207,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
int *loop_to_poly = wn_data->loop_to_poly;
MPoly *mpoly = wn_data->mpoly;
- float(*polynors)[3] = wn_data->polynors;
+ const float(*polynors)[3] = wn_data->polynors;
int *poly_strength = wn_data->poly_strength;
MDeformVert *dvert = wn_data->dvert;
@@ -234,6 +235,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
* we do not actually care about computed loop_normals for now... */
loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
BKE_mesh_normals_loop_split(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -360,6 +362,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
}
BKE_mesh_normals_loop_custom_set(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -390,6 +393,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
}
BKE_mesh_normals_loop_custom_from_vertices_set(mvert,
+ wn_data->vert_normals,
vert_normals,
numVerts,
medge,
@@ -407,6 +411,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
BKE_mesh_normals_loop_split(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -430,6 +435,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
}
BKE_mesh_normals_loop_custom_set(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -609,15 +615,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
weight = (weight - 1) * 25;
}
- CustomData *pdata = &result->pdata;
- float(*polynors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
- if (!polynors) {
- polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
- CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- BKE_mesh_calc_normals_poly_and_vertex(
- mvert, numVerts, mloop, numLoops, mpoly, numPolys, polynors, NULL);
-
const float split_angle = mesh->smoothresh;
short(*clnors)[2];
CustomData *ldata = &result->ldata;
@@ -641,6 +638,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
.numPolys = numPolys,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(result),
.medge = medge,
.mloop = mloop,
@@ -649,7 +647,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
.split_angle = split_angle,
.mpoly = mpoly,
- .polynors = polynors,
+ .polynors = BKE_mesh_poly_normals_ensure(mesh),
.poly_strength = CustomData_get_layer_named(
&result->pdata, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID),
@@ -677,9 +675,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
MEM_SAFE_FREE(wn_data.mode_pair);
MEM_SAFE_FREE(wn_data.items_data);
- /* Currently Modifier stack assumes there is no poly normal data passed around... */
- CustomData_free_layers(pdata, CD_NORMAL, numPolys);
-
result->runtime.is_original = false;
return result;
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.h b/source/blender/modifiers/intern/MOD_weightvg_util.h
index 00aecd7342c..3bcbe3ed68b 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.h
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.h
@@ -64,7 +64,7 @@ struct uiLayout;
void weightvg_do_map(int num,
float *new_w,
short falloff_type,
- const bool do_invert,
+ bool do_invert,
struct CurveMapping *cmap,
struct RNG *rng);
@@ -77,22 +77,22 @@ void weightvg_do_map(int num,
* Else, weird results might appear.
*/
void weightvg_do_mask(const ModifierEvalContext *ctx,
- const int num,
+ int num,
const int *indices,
float *org_w,
const float *new_w,
Object *ob,
struct Mesh *mesh,
- const float fact,
+ float fact,
const char defgrp_name[MAX_VGROUP_NAME],
struct Scene *scene,
Tex *texture,
- const int tex_use_channel,
- const int tex_mapping,
+ int tex_use_channel,
+ int tex_mapping,
Object *tex_map_object,
const char *text_map_bone,
const char *tex_uvlayer_name,
- const bool invert_vgroup_mask);
+ bool invert_vgroup_mask);
/**
* Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group.
@@ -107,11 +107,11 @@ void weightvg_update_vg(struct MDeformVert *dvert,
int num,
const int *indices,
const float *weights,
- const bool do_add,
- const float add_thresh,
- const bool do_rem,
- const float rem_thresh,
- const bool do_normalize);
+ bool do_add,
+ float add_thresh,
+ bool do_rem,
+ float rem_thresh,
+ bool do_normalize);
/**
* Common vertex weight mask interface elements for the modifier panels.
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
deleted file mode 100644
index f842bef3298..00000000000
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ /dev/null
@@ -1,2081 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 by the Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup modifiers
- *
- * Weld modifier: Remove doubles.
- */
-
-/* TODOs:
- * - Review weight and vertex color interpolation.;
- */
-
-//#define USE_WELD_DEBUG
-//#define USE_WELD_NORMALS
-//#define USE_BVHTREEKDOP
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_utildefines.h"
-
-#include "BLI_alloca.h"
-#include "BLI_bitmap.h"
-#include "BLI_kdtree.h"
-#include "BLI_math.h"
-
-#include "BLT_translation.h"
-
-#include "DNA_defaults.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_screen_types.h"
-
-#ifdef USE_BVHTREEKDOP
-# include "BKE_bvhutils.h"
-#endif
-
-#include "BKE_context.h"
-#include "BKE_deform.h"
-#include "BKE_mesh.h"
-#include "BKE_modifier.h"
-#include "BKE_screen.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "RNA_access.h"
-
-#include "DEG_depsgraph.h"
-
-#include "MOD_modifiertypes.h"
-#include "MOD_ui_common.h"
-
-/* Indicates when the element was not computed. */
-#define OUT_OF_CONTEXT (uint)(-1)
-/* Indicates if the edge or face will be collapsed. */
-#define ELEM_COLLAPSED (uint)(-2)
-/* indicates whether an edge or vertex in groups_map will be merged. */
-#define ELEM_MERGED (uint)(-2)
-
-/* Used to indicate a range in an array specifying a group. */
-struct WeldGroup {
- uint len;
- uint ofs;
-};
-
-/* Edge groups that will be merged. Final vertices are also indicated. */
-struct WeldGroupEdge {
- struct WeldGroup group;
- uint v1;
- uint v2;
-};
-
-typedef struct WeldVert {
- /* Indexes relative to the original Mesh. */
- uint vert_dest;
- uint vert_orig;
-} WeldVert;
-
-typedef struct WeldEdge {
- union {
- uint flag;
- struct {
- /* Indexes relative to the original Mesh. */
- uint edge_dest;
- uint edge_orig;
- uint vert_a;
- uint vert_b;
- };
- };
-} WeldEdge;
-
-typedef struct WeldLoop {
- union {
- uint flag;
- struct {
- /* Indexes relative to the original Mesh. */
- uint vert;
- uint edge;
- uint loop_orig;
- uint loop_skip_to;
- };
- };
-} WeldLoop;
-
-typedef struct WeldPoly {
- union {
- uint flag;
- struct {
- /* Indexes relative to the original Mesh. */
- uint poly_dst;
- uint poly_orig;
- uint loop_start;
- uint loop_end;
- /* Final Polygon Size. */
- uint len;
- /* Group of loops that will be affected. */
- struct WeldGroup loops;
- };
- };
-} WeldPoly;
-
-typedef struct WeldMesh {
- /* Group of vertices to be merged. */
- struct WeldGroup *vert_groups;
- uint *vert_groups_buffer;
-
- /* Group of edges to be merged. */
- struct WeldGroupEdge *edge_groups;
- uint *edge_groups_buffer;
- /* From the original index of the vertex, this indicates which group it is or is going to be
- * merged. */
- uint *edge_groups_map;
-
- /* References all polygons and loops that will be affected. */
- WeldLoop *wloop;
- WeldPoly *wpoly;
- WeldPoly *wpoly_new;
- uint wloop_len;
- uint wpoly_len;
- uint wpoly_new_len;
-
- /* From the actual index of the element in the mesh, it indicates what is the index of the Weld
- * element above. */
- uint *loop_map;
- uint *poly_map;
-
- uint vert_kill_len;
- uint edge_kill_len;
- uint loop_kill_len;
- uint poly_kill_len; /* Including the new polygons. */
-
- /* Size of the affected polygon with more sides. */
- uint max_poly_len;
-} WeldMesh;
-
-typedef struct WeldLoopOfPolyIter {
- uint loop_start;
- uint loop_end;
- const WeldLoop *wloop;
- const MLoop *mloop;
- const uint *loop_map;
- /* Weld group. */
- uint *group;
-
- uint l_curr;
- uint l_next;
-
- /* Return */
- uint group_len;
- uint v;
- uint e;
- char type;
-} WeldLoopOfPolyIter;
-
-/* -------------------------------------------------------------------- */
-/** \name Debug Utils
- * \{ */
-
-#ifdef USE_WELD_DEBUG
-static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
- const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- uint *group_buffer);
-
-static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter);
-
-static void weld_assert_edge_kill_len(const WeldEdge *wedge,
- const uint wedge_len,
- const uint supposed_kill_len)
-{
- uint kills = 0;
- const WeldEdge *we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- uint edge_dest = we->edge_dest;
- /* Magically includes collapsed edges. */
- if (edge_dest != OUT_OF_CONTEXT) {
- kills++;
- }
- }
- BLI_assert(kills == supposed_kill_len);
-}
-
-static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
- const WeldPoly *wpoly_new,
- const uint wpoly_new_len,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- const uint *poly_map,
- const MPoly *mpoly,
- const uint mpoly_len,
- const uint mloop_len,
- const uint supposed_poly_kill_len,
- const uint supposed_loop_kill_len)
-{
- uint poly_kills = 0;
- uint loop_kills = mloop_len;
- const MPoly *mp = &mpoly[0];
- for (uint i = 0; i < mpoly_len; i++, mp++) {
- uint poly_ctx = poly_map[i];
- if (poly_ctx != OUT_OF_CONTEXT) {
- const WeldPoly *wp = &wpoly[poly_ctx];
- WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
- poly_kills++;
- continue;
- }
- else {
- if (wp->poly_dst != OUT_OF_CONTEXT) {
- poly_kills++;
- continue;
- }
- uint remain = wp->len;
- uint l = wp->loop_start;
- while (remain) {
- uint l_next = l + 1;
- uint loop_ctx = loop_map[l];
- if (loop_ctx != OUT_OF_CONTEXT) {
- const WeldLoop *wl = &wloop[loop_ctx];
- if (wl->loop_skip_to != OUT_OF_CONTEXT) {
- l_next = wl->loop_skip_to;
- }
- if (wl->flag != ELEM_COLLAPSED) {
- loop_kills--;
- remain--;
- }
- }
- else {
- loop_kills--;
- remain--;
- }
- l = l_next;
- }
- }
- }
- else {
- loop_kills -= mp->totloop;
- }
- }
-
- const WeldPoly *wp = &wpoly_new[0];
- for (uint i = wpoly_new_len; i--; wp++) {
- if (wp->poly_dst != OUT_OF_CONTEXT) {
- poly_kills++;
- continue;
- }
- uint remain = wp->len;
- uint l = wp->loop_start;
- while (remain) {
- uint l_next = l + 1;
- uint loop_ctx = loop_map[l];
- if (loop_ctx != OUT_OF_CONTEXT) {
- const WeldLoop *wl = &wloop[loop_ctx];
- if (wl->loop_skip_to != OUT_OF_CONTEXT) {
- l_next = wl->loop_skip_to;
- }
- if (wl->flag != ELEM_COLLAPSED) {
- loop_kills--;
- remain--;
- }
- }
- else {
- loop_kills--;
- remain--;
- }
- l = l_next;
- }
- }
-
- BLI_assert(poly_kills == supposed_poly_kill_len);
- BLI_assert(loop_kills == supposed_loop_kill_len);
-}
-
-static void weld_assert_poly_no_vert_repetition(const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map)
-{
- const uint len = wp->len;
- uint *verts = BLI_array_alloca(verts, len);
- WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
- return;
- }
- else {
- uint i = 0;
- while (weld_iter_loop_of_poly_next(&iter)) {
- verts[i++] = iter.v;
- }
- }
- for (uint i = 0; i < len; i++) {
- uint va = verts[i];
- for (uint j = i + 1; j < len; j++) {
- uint vb = verts[j];
- BLI_assert(va != vb);
- }
- }
-}
-
-static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
-{
- if (wp->flag == ELEM_COLLAPSED) {
- return;
- }
-
- uint len = wp->len;
- const WeldLoop *wl = &wloop[wp->loops.ofs];
- BLI_assert(wp->loop_start <= wl->loop_orig);
-
- uint end_wloop = wp->loops.ofs + wp->loops.len;
- const WeldLoop *wl_end = &wloop[end_wloop - 1];
-
- uint min_len = 0;
- for (; wl <= wl_end; wl++) {
- BLI_assert(wl->loop_skip_to == OUT_OF_CONTEXT); /* Not for this case. */
- if (wl->flag != ELEM_COLLAPSED) {
- min_len++;
- }
- }
- BLI_assert(len >= min_len);
-
- uint max_len = wp->loop_end - wp->loop_start + 1;
- BLI_assert(len <= max_len);
-}
-
-#endif /* USE_WELD_DEBUG */
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld Vert API
- * \{ */
-
-static void weld_vert_ctx_alloc_and_setup(const uint mvert_len,
- uint *r_vert_dest_map,
- WeldVert **r_wvert,
- uint *r_wvert_len)
-{
- /* Vert Context. */
- uint wvert_len = 0;
-
- WeldVert *wvert, *wv;
- wvert = MEM_mallocN(sizeof(*wvert) * mvert_len, __func__);
- wv = &wvert[0];
-
- uint *v_dest_iter = &r_vert_dest_map[0];
- for (uint i = 0; i < mvert_len; i++, v_dest_iter++) {
- if (*v_dest_iter != OUT_OF_CONTEXT) {
- wv->vert_dest = *v_dest_iter;
- wv->vert_orig = i;
- wv++;
- wvert_len++;
- }
- }
-
- *r_wvert = MEM_reallocN(wvert, sizeof(*wvert) * wvert_len);
- *r_wvert_len = wvert_len;
-}
-
-static void weld_vert_groups_setup(const uint mvert_len,
- const uint wvert_len,
- const WeldVert *wvert,
- const uint *vert_dest_map,
- uint *r_vert_groups_map,
- uint **r_vert_groups_buffer,
- struct WeldGroup **r_vert_groups)
-{
- /* Get weld vert groups. */
-
- uint wgroups_len = 0;
- const uint *vert_dest_iter = &vert_dest_map[0];
- uint *group_map_iter = &r_vert_groups_map[0];
- for (uint i = 0; i < mvert_len; i++, group_map_iter++, vert_dest_iter++) {
- uint vert_dest = *vert_dest_iter;
- if (vert_dest != OUT_OF_CONTEXT) {
- if (vert_dest != i) {
- *group_map_iter = ELEM_MERGED;
- }
- else {
- *group_map_iter = wgroups_len;
- wgroups_len++;
- }
- }
- else {
- *group_map_iter = OUT_OF_CONTEXT;
- }
- }
-
- struct WeldGroup *wgroups = MEM_callocN(sizeof(*wgroups) * wgroups_len, __func__);
-
- const WeldVert *wv = &wvert[0];
- for (uint i = wvert_len; i--; wv++) {
- uint group_index = r_vert_groups_map[wv->vert_dest];
- wgroups[group_index].len++;
- }
-
- uint ofs = 0;
- struct WeldGroup *wg_iter = &wgroups[0];
- for (uint i = wgroups_len; i--; wg_iter++) {
- wg_iter->ofs = ofs;
- ofs += wg_iter->len;
- }
-
- BLI_assert(ofs == wvert_len);
-
- uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
- wv = &wvert[0];
- for (uint i = wvert_len; i--; wv++) {
- uint group_index = r_vert_groups_map[wv->vert_dest];
- groups_buffer[wgroups[group_index].ofs++] = wv->vert_orig;
- }
-
- wg_iter = &wgroups[0];
- for (uint i = wgroups_len; i--; wg_iter++) {
- wg_iter->ofs -= wg_iter->len;
- }
-
- *r_vert_groups = wgroups;
- *r_vert_groups_buffer = groups_buffer;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld Edge API
- * \{ */
-
-static void weld_edge_ctx_setup(const uint mvert_len,
- const uint wedge_len,
- struct WeldGroup *r_vlinks,
- uint *r_edge_dest_map,
- WeldEdge *r_wedge,
- uint *r_edge_kiil_len)
-{
- WeldEdge *we;
-
- /* Setup Edge Overlap. */
- uint edge_kill_len = 0;
-
- struct WeldGroup *vl_iter, *v_links;
- v_links = r_vlinks;
- vl_iter = &v_links[0];
-
- we = &r_wedge[0];
- for (uint i = wedge_len; i--; we++) {
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
-
- if (dst_vert_a == dst_vert_b) {
- BLI_assert(we->edge_dest == OUT_OF_CONTEXT);
- r_edge_dest_map[we->edge_orig] = ELEM_COLLAPSED;
- we->flag = ELEM_COLLAPSED;
- edge_kill_len++;
- continue;
- }
-
- v_links[dst_vert_a].len++;
- v_links[dst_vert_b].len++;
- }
-
- uint link_len = 0;
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- vl_iter->ofs = link_len;
- link_len += vl_iter->len;
- }
-
- if (link_len) {
- uint *link_edge_buffer = MEM_mallocN(sizeof(*link_edge_buffer) * link_len, __func__);
-
- we = &r_wedge[0];
- for (uint i = 0; i < wedge_len; i++, we++) {
- if (we->flag == ELEM_COLLAPSED) {
- continue;
- }
-
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
-
- link_edge_buffer[v_links[dst_vert_a].ofs++] = i;
- link_edge_buffer[v_links[dst_vert_b].ofs++] = i;
- }
-
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- /* Fix offset */
- vl_iter->ofs -= vl_iter->len;
- }
-
- we = &r_wedge[0];
- for (uint i = 0; i < wedge_len; i++, we++) {
- if (we->edge_dest != OUT_OF_CONTEXT) {
- /* No need to retest edges.
- * (Already includes collapsed edges). */
- continue;
- }
-
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
-
- struct WeldGroup *link_a = &v_links[dst_vert_a];
- struct WeldGroup *link_b = &v_links[dst_vert_b];
-
- uint edges_len_a = link_a->len;
- uint edges_len_b = link_b->len;
-
- if (edges_len_a <= 1 || edges_len_b <= 1) {
- continue;
- }
-
- uint *edges_ctx_a = &link_edge_buffer[link_a->ofs];
- uint *edges_ctx_b = &link_edge_buffer[link_b->ofs];
- uint edge_orig = we->edge_orig;
-
- for (; edges_len_a--; edges_ctx_a++) {
- uint e_ctx_a = *edges_ctx_a;
- if (e_ctx_a == i) {
- continue;
- }
- while (edges_len_b && *edges_ctx_b < e_ctx_a) {
- edges_ctx_b++;
- edges_len_b--;
- }
- if (edges_len_b == 0) {
- break;
- }
- uint e_ctx_b = *edges_ctx_b;
- if (e_ctx_a == e_ctx_b) {
- WeldEdge *we_b = &r_wedge[e_ctx_b];
- BLI_assert(ELEM(we_b->vert_a, dst_vert_a, dst_vert_b));
- BLI_assert(ELEM(we_b->vert_b, dst_vert_a, dst_vert_b));
- BLI_assert(we_b->edge_dest == OUT_OF_CONTEXT);
- BLI_assert(we_b->edge_orig != edge_orig);
- r_edge_dest_map[we_b->edge_orig] = edge_orig;
- we_b->edge_dest = edge_orig;
- edge_kill_len++;
- }
- }
- }
-
-#ifdef USE_WELD_DEBUG
- weld_assert_edge_kill_len(r_wedge, wedge_len, edge_kill_len);
-#endif
-
- MEM_freeN(link_edge_buffer);
- }
-
- *r_edge_kiil_len = edge_kill_len;
-}
-
-static void weld_edge_ctx_alloc(const MEdge *medge,
- const uint medge_len,
- const uint *vert_dest_map,
- uint *r_edge_dest_map,
- uint **r_edge_ctx_map,
- WeldEdge **r_wedge,
- uint *r_wedge_len)
-{
- /* Edge Context. */
- uint *edge_map = MEM_mallocN(sizeof(*edge_map) * medge_len, __func__);
- uint wedge_len = 0;
-
- WeldEdge *wedge, *we;
- wedge = MEM_mallocN(sizeof(*wedge) * medge_len, __func__);
- we = &wedge[0];
-
- const MEdge *me = &medge[0];
- uint *e_dest_iter = &r_edge_dest_map[0];
- uint *iter = &edge_map[0];
- for (uint i = 0; i < medge_len; i++, me++, iter++, e_dest_iter++) {
- uint v1 = me->v1;
- uint v2 = me->v2;
- uint v_dest_1 = vert_dest_map[v1];
- uint v_dest_2 = vert_dest_map[v2];
- if ((v_dest_1 != OUT_OF_CONTEXT) || (v_dest_2 != OUT_OF_CONTEXT)) {
- we->vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1;
- we->vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2;
- we->edge_dest = OUT_OF_CONTEXT;
- we->edge_orig = i;
- we++;
- *e_dest_iter = i;
- *iter = wedge_len++;
- }
- else {
- *e_dest_iter = OUT_OF_CONTEXT;
- *iter = OUT_OF_CONTEXT;
- }
- }
-
- *r_wedge = MEM_reallocN(wedge, sizeof(*wedge) * wedge_len);
- *r_wedge_len = wedge_len;
- *r_edge_ctx_map = edge_map;
-}
-
-static void weld_edge_groups_setup(const uint medge_len,
- const uint edge_kill_len,
- const uint wedge_len,
- WeldEdge *wedge,
- const uint *wedge_map,
- uint *r_edge_groups_map,
- uint **r_edge_groups_buffer,
- struct WeldGroupEdge **r_edge_groups)
-{
-
- /* Get weld edge groups. */
-
- struct WeldGroupEdge *wegroups, *wegrp_iter;
-
- uint wgroups_len = wedge_len - edge_kill_len;
- wegroups = MEM_callocN(sizeof(*wegroups) * wgroups_len, __func__);
- wegrp_iter = &wegroups[0];
-
- wgroups_len = 0;
- const uint *edge_ctx_iter = &wedge_map[0];
- uint *group_map_iter = &r_edge_groups_map[0];
- for (uint i = medge_len; i--; edge_ctx_iter++, group_map_iter++) {
- uint edge_ctx = *edge_ctx_iter;
- if (edge_ctx != OUT_OF_CONTEXT) {
- WeldEdge *we = &wedge[edge_ctx];
- uint edge_dest = we->edge_dest;
- if (edge_dest != OUT_OF_CONTEXT) {
- BLI_assert(edge_dest != we->edge_orig);
- *group_map_iter = ELEM_MERGED;
- }
- else {
- we->edge_dest = we->edge_orig;
- wegrp_iter->v1 = we->vert_a;
- wegrp_iter->v2 = we->vert_b;
- *group_map_iter = wgroups_len;
- wgroups_len++;
- wegrp_iter++;
- }
- }
- else {
- *group_map_iter = OUT_OF_CONTEXT;
- }
- }
-
- BLI_assert(wgroups_len == wedge_len - edge_kill_len);
-
- WeldEdge *we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- if (we->flag == ELEM_COLLAPSED) {
- continue;
- }
- uint group_index = r_edge_groups_map[we->edge_dest];
- wegroups[group_index].group.len++;
- }
-
- uint ofs = 0;
- wegrp_iter = &wegroups[0];
- for (uint i = wgroups_len; i--; wegrp_iter++) {
- wegrp_iter->group.ofs = ofs;
- ofs += wegrp_iter->group.len;
- }
-
- uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
- we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- if (we->flag == ELEM_COLLAPSED) {
- continue;
- }
- uint group_index = r_edge_groups_map[we->edge_dest];
- groups_buffer[wegroups[group_index].group.ofs++] = we->edge_orig;
- }
-
- wegrp_iter = &wegroups[0];
- for (uint i = wgroups_len; i--; wegrp_iter++) {
- wegrp_iter->group.ofs -= wegrp_iter->group.len;
- }
-
- *r_edge_groups_buffer = groups_buffer;
- *r_edge_groups = wegroups;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld Poly and Loop API
- * \{ */
-
-static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
- const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- uint *group_buffer)
-{
- if (wp->flag == ELEM_COLLAPSED) {
- return false;
- }
-
- iter->loop_start = wp->loop_start;
- iter->loop_end = wp->loop_end;
- iter->wloop = wloop;
- iter->mloop = mloop;
- iter->loop_map = loop_map;
- iter->group = group_buffer;
-
- uint group_len = 0;
- if (group_buffer) {
- /* First loop group needs more attention. */
- uint loop_start, loop_end, l;
- loop_start = iter->loop_start;
- loop_end = l = iter->loop_end;
- while (l >= loop_start) {
- const uint loop_ctx = loop_map[l];
- if (loop_ctx != OUT_OF_CONTEXT) {
- const WeldLoop *wl = &wloop[loop_ctx];
- if (wl->flag == ELEM_COLLAPSED) {
- l--;
- continue;
- }
- }
- break;
- }
- if (l != loop_end) {
- group_len = loop_end - l;
- int i = 0;
- while (l < loop_end) {
- iter->group[i++] = ++l;
- }
- }
- }
- iter->group_len = group_len;
-
- iter->l_next = iter->loop_start;
-#ifdef USE_WELD_DEBUG
- iter->v = OUT_OF_CONTEXT;
-#endif
- return true;
-}
-
-static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
-{
- uint loop_end = iter->loop_end;
- const WeldLoop *wloop = iter->wloop;
- const uint *loop_map = iter->loop_map;
- uint l = iter->l_curr = iter->l_next;
- if (l == iter->loop_start) {
- /* `grupo_len` is already calculated in the first loop */
- }
- else {
- iter->group_len = 0;
- }
- while (l <= loop_end) {
- uint l_next = l + 1;
- const uint loop_ctx = loop_map[l];
- if (loop_ctx != OUT_OF_CONTEXT) {
- const WeldLoop *wl = &wloop[loop_ctx];
- if (wl->loop_skip_to != OUT_OF_CONTEXT) {
- l_next = wl->loop_skip_to;
- }
- if (wl->flag == ELEM_COLLAPSED) {
- if (iter->group) {
- iter->group[iter->group_len++] = l;
- }
- l = l_next;
- continue;
- }
-#ifdef USE_WELD_DEBUG
- BLI_assert(iter->v != wl->vert);
-#endif
- iter->v = wl->vert;
- iter->e = wl->edge;
- iter->type = 1;
- }
- else {
- const MLoop *ml = &iter->mloop[l];
-#ifdef USE_WELD_DEBUG
- BLI_assert(iter->v != ml->v);
-#endif
- iter->v = ml->v;
- iter->e = ml->e;
- iter->type = 0;
- }
- if (iter->group) {
- iter->group[iter->group_len++] = l;
- }
- iter->l_next = l_next;
- return true;
- }
-
- return false;
-}
-
-static void weld_poly_loop_ctx_alloc(const MPoly *mpoly,
- const uint mpoly_len,
- const MLoop *mloop,
- const uint mloop_len,
- const uint *vert_dest_map,
- const uint *edge_dest_map,
- WeldMesh *r_weld_mesh)
-{
- /* Loop/Poly Context. */
- uint *loop_map = MEM_mallocN(sizeof(*loop_map) * mloop_len, __func__);
- uint *poly_map = MEM_mallocN(sizeof(*poly_map) * mpoly_len, __func__);
- uint wloop_len = 0;
- uint wpoly_len = 0;
- uint max_ctx_poly_len = 4;
-
- WeldLoop *wloop, *wl;
- wloop = MEM_mallocN(sizeof(*wloop) * mloop_len, __func__);
- wl = &wloop[0];
-
- WeldPoly *wpoly, *wp;
- wpoly = MEM_mallocN(sizeof(*wpoly) * mpoly_len, __func__);
- wp = &wpoly[0];
-
- uint maybe_new_poly = 0;
-
- const MPoly *mp = &mpoly[0];
- uint *iter = &poly_map[0];
- uint *loop_map_iter = &loop_map[0];
- for (uint i = 0; i < mpoly_len; i++, mp++, iter++) {
- const uint loopstart = mp->loopstart;
- const uint totloop = mp->totloop;
-
- uint vert_ctx_len = 0;
-
- uint l = loopstart;
- uint prev_wloop_len = wloop_len;
- const MLoop *ml = &mloop[l];
- for (uint j = totloop; j--; l++, ml++, loop_map_iter++) {
- uint v = ml->v;
- uint e = ml->e;
- uint v_dest = vert_dest_map[v];
- uint e_dest = edge_dest_map[e];
- bool is_vert_ctx = v_dest != OUT_OF_CONTEXT;
- bool is_edge_ctx = e_dest != OUT_OF_CONTEXT;
- if (is_vert_ctx) {
- vert_ctx_len++;
- }
- if (is_vert_ctx || is_edge_ctx) {
- wl->vert = is_vert_ctx ? v_dest : v;
- wl->edge = is_edge_ctx ? e_dest : e;
- wl->loop_orig = l;
- wl->loop_skip_to = OUT_OF_CONTEXT;
- wl++;
-
- *loop_map_iter = wloop_len++;
- }
- else {
- *loop_map_iter = OUT_OF_CONTEXT;
- }
- }
- if (wloop_len != prev_wloop_len) {
- uint loops_len = wloop_len - prev_wloop_len;
-
- wp->poly_dst = OUT_OF_CONTEXT;
- wp->poly_orig = i;
- wp->loops.len = loops_len;
- wp->loops.ofs = prev_wloop_len;
- wp->loop_start = loopstart;
- wp->loop_end = loopstart + totloop - 1;
- wp->len = totloop;
- wp++;
-
- *iter = wpoly_len++;
- if (totloop > 5 && vert_ctx_len > 1) {
- uint max_new = (totloop / 3) - 1;
- vert_ctx_len /= 2;
- maybe_new_poly += MIN2(max_new, vert_ctx_len);
- CLAMP_MIN(max_ctx_poly_len, totloop);
- }
- }
- else {
- *iter = OUT_OF_CONTEXT;
- }
- }
-
- if (mpoly_len < (wpoly_len + maybe_new_poly)) {
- WeldPoly *wpoly_tmp = wpoly;
- wpoly = MEM_mallocN(sizeof(*wpoly) * ((size_t)wpoly_len + maybe_new_poly), __func__);
- memcpy(wpoly, wpoly_tmp, sizeof(*wpoly) * wpoly_len);
- MEM_freeN(wpoly_tmp);
- }
-
- WeldPoly *poly_new = &wpoly[wpoly_len];
-
- r_weld_mesh->wloop = MEM_reallocN(wloop, sizeof(*wloop) * wloop_len);
- r_weld_mesh->wpoly = wpoly;
- r_weld_mesh->wpoly_new = poly_new;
- r_weld_mesh->wloop_len = wloop_len;
- r_weld_mesh->wpoly_len = wpoly_len;
- r_weld_mesh->wpoly_new_len = 0;
- r_weld_mesh->loop_map = loop_map;
- r_weld_mesh->poly_map = poly_map;
- r_weld_mesh->max_poly_len = max_ctx_poly_len;
-}
-
-static void weld_poly_split_recursive(const uint *vert_dest_map,
-#ifdef USE_WELD_DEBUG
- const MLoop *mloop,
-#endif
- uint ctx_verts_len,
- WeldPoly *r_wp,
- WeldMesh *r_weld_mesh,
- uint *r_poly_kill,
- uint *r_loop_kill)
-{
- uint poly_len = r_wp->len;
- if (poly_len > 3 && ctx_verts_len > 1) {
- const uint ctx_loops_len = r_wp->loops.len;
- const uint ctx_loops_ofs = r_wp->loops.ofs;
- WeldLoop *wloop = r_weld_mesh->wloop;
- WeldPoly *wpoly_new = r_weld_mesh->wpoly_new;
-
- uint loop_kill = 0;
-
- WeldLoop *poly_loops = &wloop[ctx_loops_ofs];
- WeldLoop *wla = &poly_loops[0];
- WeldLoop *wla_prev = &poly_loops[ctx_loops_len - 1];
- while (wla_prev->flag == ELEM_COLLAPSED) {
- wla_prev--;
- }
- const uint la_len = ctx_loops_len - 1;
- for (uint la = 0; la < la_len; la++, wla++) {
- wa_continue:
- if (wla->flag == ELEM_COLLAPSED) {
- continue;
- }
- uint vert_a = wla->vert;
- /* Only test vertices that will be merged. */
- if (vert_dest_map[vert_a] != OUT_OF_CONTEXT) {
- uint lb = la + 1;
- WeldLoop *wlb = wla + 1;
- WeldLoop *wlb_prev = wla;
- uint killed_ab = 0;
- ctx_verts_len = 1;
- for (; lb < ctx_loops_len; lb++, wlb++) {
- BLI_assert(wlb->loop_skip_to == OUT_OF_CONTEXT);
- if (wlb->flag == ELEM_COLLAPSED) {
- killed_ab++;
- continue;
- }
- uint vert_b = wlb->vert;
- if (vert_dest_map[vert_b] != OUT_OF_CONTEXT) {
- ctx_verts_len++;
- }
- if (vert_a == vert_b) {
- const uint dist_a = wlb->loop_orig - wla->loop_orig - killed_ab;
- const uint dist_b = poly_len - dist_a;
-
- BLI_assert(dist_a != 0 && dist_b != 0);
- if (dist_a == 1 || dist_b == 1) {
- BLI_assert(dist_a != dist_b);
- BLI_assert((wla->flag == ELEM_COLLAPSED) || (wlb->flag == ELEM_COLLAPSED));
- }
- else {
- WeldLoop *wl_tmp = NULL;
- if (dist_a == 2) {
- wl_tmp = wlb_prev;
- BLI_assert(wla->flag != ELEM_COLLAPSED);
- BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
- wla->flag = ELEM_COLLAPSED;
- wl_tmp->flag = ELEM_COLLAPSED;
- loop_kill += 2;
- poly_len -= 2;
- }
- if (dist_b == 2) {
- if (wl_tmp != NULL) {
- r_wp->flag = ELEM_COLLAPSED;
- *r_poly_kill += 1;
- }
- else {
- wl_tmp = wla_prev;
- BLI_assert(wlb->flag != ELEM_COLLAPSED);
- BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
- wlb->flag = ELEM_COLLAPSED;
- wl_tmp->flag = ELEM_COLLAPSED;
- }
- loop_kill += 2;
- poly_len -= 2;
- }
- if (wl_tmp == NULL) {
- const uint new_loops_len = lb - la;
- const uint new_loops_ofs = ctx_loops_ofs + la;
-
- WeldPoly *new_wp = &wpoly_new[r_weld_mesh->wpoly_new_len++];
- new_wp->poly_dst = OUT_OF_CONTEXT;
- new_wp->poly_orig = r_wp->poly_orig;
- new_wp->loops.len = new_loops_len;
- new_wp->loops.ofs = new_loops_ofs;
- new_wp->loop_start = wla->loop_orig;
- new_wp->loop_end = wlb_prev->loop_orig;
- new_wp->len = dist_a;
- weld_poly_split_recursive(vert_dest_map,
-#ifdef USE_WELD_DEBUG
- mloop,
-#endif
- ctx_verts_len,
- new_wp,
- r_weld_mesh,
- r_poly_kill,
- r_loop_kill);
- BLI_assert(dist_b == poly_len - dist_a);
- poly_len = dist_b;
- if (wla_prev->loop_orig > wla->loop_orig) {
- /* New start. */
- r_wp->loop_start = wlb->loop_orig;
- }
- else {
- /* The `loop_start` doesn't change but some loops must be skipped. */
- wla_prev->loop_skip_to = wlb->loop_orig;
- }
- wla = wlb;
- la = lb;
- goto wa_continue;
- }
- break;
- }
- }
- if (wlb->flag != ELEM_COLLAPSED) {
- wlb_prev = wlb;
- }
- }
- }
- if (wla->flag != ELEM_COLLAPSED) {
- wla_prev = wla;
- }
- }
- r_wp->len = poly_len;
- *r_loop_kill += loop_kill;
-
-#ifdef USE_WELD_DEBUG
- weld_assert_poly_no_vert_repetition(r_wp, wloop, mloop, r_weld_mesh->loop_map);
-#endif
- }
-}
-
-static void weld_poly_loop_ctx_setup(const MLoop *mloop,
-#ifdef USE_WELD_DEBUG
- const MPoly *mpoly,
- const uint mpoly_len,
- const uint mloop_len,
-#endif
- const uint mvert_len,
- const uint *vert_dest_map,
- const uint remain_edge_ctx_len,
- struct WeldGroup *r_vlinks,
- WeldMesh *r_weld_mesh)
-{
- uint poly_kill_len, loop_kill_len, wpoly_len, wpoly_new_len;
-
- WeldPoly *wpoly_new, *wpoly, *wp;
- WeldLoop *wloop, *wl;
-
- wpoly = r_weld_mesh->wpoly;
- wloop = r_weld_mesh->wloop;
- wpoly_new = r_weld_mesh->wpoly_new;
- wpoly_len = r_weld_mesh->wpoly_len;
- wpoly_new_len = 0;
- poly_kill_len = 0;
- loop_kill_len = 0;
-
- const uint *loop_map = r_weld_mesh->loop_map;
-
- if (remain_edge_ctx_len) {
-
- /* Setup Poly/Loop. */
-
- wp = &wpoly[0];
- for (uint i = wpoly_len; i--; wp++) {
- const uint ctx_loops_len = wp->loops.len;
- const uint ctx_loops_ofs = wp->loops.ofs;
-
- uint poly_len = wp->len;
- uint ctx_verts_len = 0;
- wl = &wloop[ctx_loops_ofs];
- for (uint l = ctx_loops_len; l--; wl++) {
- const uint edge_dest = wl->edge;
- if (edge_dest == ELEM_COLLAPSED) {
- wl->flag = ELEM_COLLAPSED;
- if (poly_len == 3) {
- wp->flag = ELEM_COLLAPSED;
- poly_kill_len++;
- loop_kill_len += 3;
- poly_len = 0;
- break;
- }
- loop_kill_len++;
- poly_len--;
- }
- else {
- const uint vert_dst = wl->vert;
- if (vert_dest_map[vert_dst] != OUT_OF_CONTEXT) {
- ctx_verts_len++;
- }
- }
- }
-
- if (poly_len) {
- wp->len = poly_len;
-#ifdef USE_WELD_DEBUG
- weld_assert_poly_len(wp, wloop);
-#endif
-
- weld_poly_split_recursive(vert_dest_map,
-#ifdef USE_WELD_DEBUG
- mloop,
-#endif
- ctx_verts_len,
- wp,
- r_weld_mesh,
- &poly_kill_len,
- &loop_kill_len);
-
- wpoly_new_len = r_weld_mesh->wpoly_new_len;
- }
- }
-
-#ifdef USE_WELD_DEBUG
- weld_assert_poly_and_loop_kill_len(wpoly,
- wpoly_new,
- wpoly_new_len,
- wloop,
- mloop,
- loop_map,
- r_weld_mesh->poly_map,
- mpoly,
- mpoly_len,
- mloop_len,
- poly_kill_len,
- loop_kill_len);
-#endif
-
- /* Setup Polygon Overlap. */
-
- uint wpoly_and_new_len = wpoly_len + wpoly_new_len;
-
- struct WeldGroup *vl_iter, *v_links = r_vlinks;
- memset(v_links, 0, sizeof(*v_links) * mvert_len);
-
- wp = &wpoly[0];
- for (uint i = wpoly_and_new_len; i--; wp++) {
- WeldLoopOfPolyIter iter;
- if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
- while (weld_iter_loop_of_poly_next(&iter)) {
- v_links[iter.v].len++;
- }
- }
- }
-
- uint link_len = 0;
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- vl_iter->ofs = link_len;
- link_len += vl_iter->len;
- }
-
- if (link_len) {
- uint *link_poly_buffer = MEM_mallocN(sizeof(*link_poly_buffer) * link_len, __func__);
-
- wp = &wpoly[0];
- for (uint i = 0; i < wpoly_and_new_len; i++, wp++) {
- WeldLoopOfPolyIter iter;
- if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
- while (weld_iter_loop_of_poly_next(&iter)) {
- link_poly_buffer[v_links[iter.v].ofs++] = i;
- }
- }
- }
-
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- /* Fix offset */
- vl_iter->ofs -= vl_iter->len;
- }
-
- uint polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b;
- polys_len_b = p_ctx_b = 0; /* silence warnings */
-
- wp = &wpoly[0];
- for (uint i = 0; i < wpoly_and_new_len; i++, wp++) {
- if (wp->poly_dst != OUT_OF_CONTEXT) {
- /* No need to retest poly.
- * (Already includes collapsed polygons). */
- continue;
- }
-
- WeldLoopOfPolyIter iter;
- weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL);
- weld_iter_loop_of_poly_next(&iter);
- struct WeldGroup *link_a = &v_links[iter.v];
- polys_len_a = link_a->len;
- if (polys_len_a == 1) {
- BLI_assert(link_poly_buffer[link_a->ofs] == i);
- continue;
- }
- uint wp_len = wp->len;
- polys_ctx_a = &link_poly_buffer[link_a->ofs];
- for (; polys_len_a--; polys_ctx_a++) {
- p_ctx_a = *polys_ctx_a;
- if (p_ctx_a == i) {
- continue;
- }
-
- WeldPoly *wp_tmp = &wpoly[p_ctx_a];
- if (wp_tmp->len != wp_len) {
- continue;
- }
-
- WeldLoopOfPolyIter iter_b = iter;
- while (weld_iter_loop_of_poly_next(&iter_b)) {
- struct WeldGroup *link_b = &v_links[iter_b.v];
- polys_len_b = link_b->len;
- if (polys_len_b == 1) {
- BLI_assert(link_poly_buffer[link_b->ofs] == i);
- polys_len_b = 0;
- break;
- }
-
- polys_ctx_b = &link_poly_buffer[link_b->ofs];
- for (; polys_len_b; polys_len_b--, polys_ctx_b++) {
- p_ctx_b = *polys_ctx_b;
- if (p_ctx_b < p_ctx_a) {
- continue;
- }
- if (p_ctx_b >= p_ctx_a) {
- if (p_ctx_b > p_ctx_a) {
- polys_len_b = 0;
- }
- break;
- }
- }
- if (polys_len_b == 0) {
- break;
- }
- }
- if (polys_len_b == 0) {
- continue;
- }
- BLI_assert(p_ctx_a > i);
- BLI_assert(p_ctx_a == p_ctx_b);
- BLI_assert(wp_tmp->poly_dst == OUT_OF_CONTEXT);
- BLI_assert(wp_tmp != wp);
- wp_tmp->poly_dst = wp->poly_orig;
- loop_kill_len += wp_tmp->len;
- poly_kill_len++;
- }
- }
- MEM_freeN(link_poly_buffer);
- }
- }
- else {
- poly_kill_len = r_weld_mesh->wpoly_len;
- loop_kill_len = r_weld_mesh->wloop_len;
-
- wp = &wpoly[0];
- for (uint i = wpoly_len; i--; wp++) {
- wp->flag = ELEM_COLLAPSED;
- }
- }
-
-#ifdef USE_WELD_DEBUG
- weld_assert_poly_and_loop_kill_len(wpoly,
- wpoly_new,
- wpoly_new_len,
- wloop,
- mloop,
- loop_map,
- r_weld_mesh->poly_map,
- mpoly,
- mpoly_len,
- mloop_len,
- poly_kill_len,
- loop_kill_len);
-#endif
-
- r_weld_mesh->wpoly_new = wpoly_new;
- r_weld_mesh->poly_kill_len = poly_kill_len;
- r_weld_mesh->loop_kill_len = loop_kill_len;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld Mesh API
- * \{ */
-
-static void weld_mesh_context_create(const Mesh *mesh,
- uint *vert_dest_map,
- const uint vert_kill_len,
- WeldMesh *r_weld_mesh)
-{
- const MEdge *medge = mesh->medge;
- const MLoop *mloop = mesh->mloop;
- const MPoly *mpoly = mesh->mpoly;
- const uint mvert_len = mesh->totvert;
- const uint medge_len = mesh->totedge;
- const uint mloop_len = mesh->totloop;
- const uint mpoly_len = mesh->totpoly;
-
- uint *edge_dest_map = MEM_mallocN(sizeof(*edge_dest_map) * medge_len, __func__);
- struct WeldGroup *v_links = MEM_callocN(sizeof(*v_links) * mvert_len, __func__);
-
- WeldVert *wvert;
- uint wvert_len;
- r_weld_mesh->vert_kill_len = vert_kill_len;
- weld_vert_ctx_alloc_and_setup(mvert_len, vert_dest_map, &wvert, &wvert_len);
-
- uint *edge_ctx_map;
- WeldEdge *wedge;
- uint wedge_len;
- weld_edge_ctx_alloc(
- medge, medge_len, vert_dest_map, edge_dest_map, &edge_ctx_map, &wedge, &wedge_len);
-
- weld_edge_ctx_setup(
- mvert_len, wedge_len, v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_len);
-
- weld_poly_loop_ctx_alloc(
- mpoly, mpoly_len, mloop, mloop_len, vert_dest_map, edge_dest_map, r_weld_mesh);
-
- weld_poly_loop_ctx_setup(mloop,
-#ifdef USE_WELD_DEBUG
- mpoly,
- mpoly_len,
- mloop_len,
-#endif
- mvert_len,
- vert_dest_map,
- wedge_len - r_weld_mesh->edge_kill_len,
- v_links,
- r_weld_mesh);
-
- weld_vert_groups_setup(mvert_len,
- wvert_len,
- wvert,
- vert_dest_map,
- vert_dest_map,
- &r_weld_mesh->vert_groups_buffer,
- &r_weld_mesh->vert_groups);
-
- weld_edge_groups_setup(medge_len,
- r_weld_mesh->edge_kill_len,
- wedge_len,
- wedge,
- edge_ctx_map,
- edge_dest_map,
- &r_weld_mesh->edge_groups_buffer,
- &r_weld_mesh->edge_groups);
-
- r_weld_mesh->edge_groups_map = edge_dest_map;
- MEM_freeN(v_links);
- MEM_freeN(wvert);
- MEM_freeN(edge_ctx_map);
- MEM_freeN(wedge);
-}
-
-static void weld_mesh_context_free(WeldMesh *weld_mesh)
-{
- MEM_freeN(weld_mesh->vert_groups);
- MEM_freeN(weld_mesh->vert_groups_buffer);
-
- MEM_freeN(weld_mesh->edge_groups);
- MEM_freeN(weld_mesh->edge_groups_buffer);
- MEM_freeN(weld_mesh->edge_groups_map);
-
- MEM_freeN(weld_mesh->wloop);
- MEM_freeN(weld_mesh->wpoly);
- MEM_freeN(weld_mesh->loop_map);
- MEM_freeN(weld_mesh->poly_map);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld CustomData
- * \{ */
-
-static void customdata_weld(
- const CustomData *source, CustomData *dest, const uint *src_indices, int count, int dest_index)
-{
- if (count == 1) {
- CustomData_copy_data(source, dest, src_indices[0], dest_index, 1);
- return;
- }
-
- CustomData_interp(source, dest, (const int *)src_indices, NULL, NULL, count, dest_index);
-
- int src_i, dest_i;
- int j;
-
- float co[3] = {0.0f, 0.0f, 0.0f};
-#ifdef USE_WELD_NORMALS
- float no[3] = {0.0f, 0.0f, 0.0f};
-#endif
- uint crease = 0;
- uint bweight = 0;
- short flag = 0;
-
- /* interpolates a layer at a time */
- dest_i = 0;
- for (src_i = 0; src_i < source->totlayer; src_i++) {
- const int type = source->layers[src_i].type;
-
- /* find the first dest layer with type >= the source type
- * (this should work because layers are ordered by type)
- */
- while (dest_i < dest->totlayer && dest->layers[dest_i].type < type) {
- dest_i++;
- }
-
- /* if there are no more dest layers, we're done */
- if (dest_i == dest->totlayer) {
- break;
- }
-
- /* if we found a matching layer, add the data */
- if (dest->layers[dest_i].type == type) {
- void *src_data = source->layers[src_i].data;
-
- if (type == CD_MVERT) {
- for (j = 0; j < count; j++) {
- MVert *mv_src = &((MVert *)src_data)[src_indices[j]];
- add_v3_v3(co, mv_src->co);
-#ifdef USE_WELD_NORMALS
- short *mv_src_no = mv_src->no;
- no[0] += mv_src_no[0];
- no[1] += mv_src_no[1];
- no[2] += mv_src_no[2];
-#endif
- bweight += mv_src->bweight;
- flag |= mv_src->flag;
- }
- }
- else if (type == CD_MEDGE) {
- for (j = 0; j < count; j++) {
- MEdge *me_src = &((MEdge *)src_data)[src_indices[j]];
- crease += me_src->crease;
- bweight += me_src->bweight;
- flag |= me_src->flag;
- }
- }
- else if (CustomData_layer_has_interp(dest, dest_i)) {
- /* Already calculated.
- * TODO: Optimize by exposing `typeInfo->interp`. */
- }
- else if (CustomData_layer_has_math(dest, dest_i)) {
- const int size = CustomData_sizeof(type);
- void *dst_data = dest->layers[dest_i].data;
- void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
- for (j = 0; j < count; j++) {
- CustomData_data_add(
- type, v_dst, POINTER_OFFSET(src_data, (size_t)src_indices[j] * size));
- }
- }
- else {
- CustomData_copy_layer_type_data(source, dest, type, src_indices[0], dest_index, 1);
- }
-
- /* if there are multiple source & dest layers of the same type,
- * we don't want to copy all source layers to the same dest, so
- * increment dest_i
- */
- dest_i++;
- }
- }
-
- float fac = 1.0f / count;
-
- for (dest_i = 0; dest_i < dest->totlayer; dest_i++) {
- CustomDataLayer *layer_dst = &dest->layers[dest_i];
- const int type = layer_dst->type;
- if (type == CD_MVERT) {
- MVert *mv = &((MVert *)layer_dst->data)[dest_index];
- mul_v3_fl(co, fac);
- bweight *= fac;
- CLAMP_MAX(bweight, 255);
-
- copy_v3_v3(mv->co, co);
-#ifdef USE_WELD_NORMALS
- mul_v3_fl(no, fac);
- short *mv_no = mv->no;
- mv_no[0] = (short)no[0];
- mv_no[1] = (short)no[1];
- mv_no[2] = (short)no[2];
-#endif
-
- mv->flag = (char)flag;
- mv->bweight = (char)bweight;
- }
- else if (type == CD_MEDGE) {
- MEdge *me = &((MEdge *)layer_dst->data)[dest_index];
- crease *= fac;
- bweight *= fac;
- CLAMP_MAX(crease, 255);
- CLAMP_MAX(bweight, 255);
-
- me->crease = (char)crease;
- me->bweight = (char)bweight;
- me->flag = flag;
- }
- else if (CustomData_layer_has_interp(dest, dest_i)) {
- /* Already calculated. */
- }
- else if (CustomData_layer_has_math(dest, dest_i)) {
- const int size = CustomData_sizeof(type);
- void *dst_data = layer_dst->data;
- void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
- CustomData_data_multiply(type, v_dst, fac);
- }
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Weld Modifier Main
- * \{ */
-
-#ifdef USE_BVHTREEKDOP
-struct WeldOverlapData {
- const MVert *mvert;
- float merge_dist_sq;
-};
-static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
-{
- if (index_a < index_b) {
- struct WeldOverlapData *data = userdata;
- const MVert *mvert = data->mvert;
- const float dist_sq = len_squared_v3v3(mvert[index_a].co, mvert[index_b].co);
- BLI_assert(dist_sq <= ((data->merge_dist_sq + FLT_EPSILON) * 3));
- return dist_sq <= data->merge_dist_sq;
- }
- return false;
-}
-#endif
-
-/** Use for #MOD_WELD_MODE_CONNECTED calculation. */
-struct WeldVertexCluster {
- float co[3];
- uint merged_verts;
-};
-
-static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
- const ModifierEvalContext *UNUSED(ctx),
- Mesh *mesh)
-{
- Mesh *result = mesh;
-
- BLI_bitmap *v_mask = NULL;
- int v_mask_act = 0;
-
- const MVert *mvert;
- const MLoop *mloop;
- const MPoly *mpoly, *mp;
- uint totvert, totedge, totloop, totpoly;
-
- mvert = mesh->mvert;
- totvert = mesh->totvert;
-
- /* Vertex Group. */
- const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name);
- if (defgrp_index != -1) {
- MDeformVert *dvert, *dv;
- dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
- if (dvert) {
- const bool invert_vgroup = (wmd->flag & MOD_WELD_INVERT_VGROUP) != 0;
- dv = &dvert[0];
- v_mask = BLI_BITMAP_NEW(totvert, __func__);
- for (uint i = 0; i < totvert; i++, dv++) {
- const bool found = BKE_defvert_find_weight(dv, defgrp_index) > 0.0f;
- if (found != invert_vgroup) {
- BLI_BITMAP_ENABLE(v_mask, i);
- v_mask_act++;
- }
- }
- }
- }
-
- /* From the original index of the vertex.
- * This indicates which vert it is or is going to be merged. */
- uint *vert_dest_map = MEM_malloc_arrayN(totvert, sizeof(*vert_dest_map), __func__);
- uint vert_kill_len = 0;
- if (wmd->mode == MOD_WELD_MODE_ALL)
-#ifdef USE_BVHTREEKDOP
- {
- /* Get overlap map. */
- struct BVHTreeFromMesh treedata;
- BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata,
- mvert,
- totvert,
- false,
- v_mask,
- v_mask_act,
- wmd->merge_dist / 2,
- 2,
- 6,
- 0,
- NULL,
- NULL);
-
- if (bvhtree) {
- struct WeldOverlapData data;
- data.mvert = mvert;
- data.merge_dist_sq = square_f(wmd->merge_dist);
-
- uint overlap_len;
- BVHTreeOverlap *overlap = BLI_bvhtree_overlap_ex(bvhtree,
- bvhtree,
- &overlap_len,
- bvhtree_weld_overlap_cb,
- &data,
- 1,
- BVH_OVERLAP_RETURN_PAIRS);
-
- free_bvhtree_from_mesh(&treedata);
- if (overlap) {
- range_vn_u(vert_dest_map, totvert, 0);
-
- const BVHTreeOverlap *overlap_iter = &overlap[0];
- for (uint i = 0; i < overlap_len; i++, overlap_iter++) {
- uint indexA = overlap_iter->indexA;
- uint indexB = overlap_iter->indexB;
-
- BLI_assert(indexA < indexB);
-
- uint va_dst = vert_dest_map[indexA];
- while (va_dst != vert_dest_map[va_dst]) {
- va_dst = vert_dest_map[va_dst];
- }
- uint vb_dst = vert_dest_map[indexB];
- while (vb_dst != vert_dest_map[vb_dst]) {
- vb_dst = vert_dest_map[vb_dst];
- }
- if (va_dst == vb_dst) {
- continue;
- }
- if (va_dst > vb_dst) {
- SWAP(uint, va_dst, vb_dst);
- }
- vert_kill_len++;
- vert_dest_map[vb_dst] = va_dst;
- }
-
- /* Fix #r_vert_dest_map for next step. */
- for (uint i = 0; i < totvert; i++) {
- if (i == vert_dest_map[i]) {
- vert_dest_map[i] = OUT_OF_CONTEXT;
- }
- else {
- uint v = i;
- while (v != vert_dest_map[v] && vert_dest_map[v] != OUT_OF_CONTEXT) {
- v = vert_dest_map[v];
- }
- vert_dest_map[v] = v;
- vert_dest_map[i] = v;
- }
- }
-
- MEM_freeN(overlap);
- }
- }
- }
-#else
- {
- KDTree_3d *tree = BLI_kdtree_3d_new(v_mask ? v_mask_act : totvert);
- for (uint i = 0; i < totvert; i++) {
- if (!v_mask || BLI_BITMAP_TEST(v_mask, i)) {
- BLI_kdtree_3d_insert(tree, i, mvert[i].co);
- }
- vert_dest_map[i] = OUT_OF_CONTEXT;
- }
-
- BLI_kdtree_3d_balance(tree);
- vert_kill_len = BLI_kdtree_3d_calc_duplicates_fast(
- tree, wmd->merge_dist, false, (int *)vert_dest_map);
- BLI_kdtree_3d_free(tree);
- }
-#endif
- else {
- BLI_assert(wmd->mode == MOD_WELD_MODE_CONNECTED);
-
- MEdge *medge, *me;
-
- medge = mesh->medge;
- totvert = mesh->totvert;
- totedge = mesh->totedge;
-
- struct WeldVertexCluster *vert_clusters = MEM_malloc_arrayN(
- totvert, sizeof(*vert_clusters), __func__);
- struct WeldVertexCluster *vc = &vert_clusters[0];
- for (uint i = 0; i < totvert; i++, vc++) {
- copy_v3_v3(vc->co, mvert[i].co);
- vc->merged_verts = 0;
- }
- const float merge_dist_sq = square_f(wmd->merge_dist);
-
- range_vn_u(vert_dest_map, totvert, 0);
-
- /* Collapse Edges that are shorter than the threshold. */
- me = &medge[0];
- for (uint i = 0; i < totedge; i++, me++) {
- uint v1 = me->v1;
- uint v2 = me->v2;
-
- if (wmd->flag & MOD_WELD_LOOSE_EDGES && (me->flag & ME_LOOSEEDGE) == 0) {
- continue;
- }
- while (v1 != vert_dest_map[v1]) {
- v1 = vert_dest_map[v1];
- }
- while (v2 != vert_dest_map[v2]) {
- v2 = vert_dest_map[v2];
- }
- if (v1 == v2) {
- continue;
- }
- if (v_mask && (!BLI_BITMAP_TEST(v_mask, v1) || !BLI_BITMAP_TEST(v_mask, v2))) {
- continue;
- }
- if (v1 > v2) {
- SWAP(uint, v1, v2);
- }
- struct WeldVertexCluster *v1_cluster = &vert_clusters[v1];
- struct WeldVertexCluster *v2_cluster = &vert_clusters[v2];
-
- float edgedir[3];
- sub_v3_v3v3(edgedir, v2_cluster->co, v1_cluster->co);
- const float dist_sq = len_squared_v3(edgedir);
- if (dist_sq <= merge_dist_sq) {
- float influence = (v2_cluster->merged_verts + 1) /
- (float)(v1_cluster->merged_verts + v2_cluster->merged_verts + 2);
- madd_v3_v3fl(v1_cluster->co, edgedir, influence);
-
- v1_cluster->merged_verts += v2_cluster->merged_verts + 1;
- vert_dest_map[v2] = v1;
- vert_kill_len++;
- }
- }
-
- MEM_freeN(vert_clusters);
-
- for (uint i = 0; i < totvert; i++) {
- if (i == vert_dest_map[i]) {
- vert_dest_map[i] = OUT_OF_CONTEXT;
- }
- else {
- uint v = i;
- while ((v != vert_dest_map[v]) && (vert_dest_map[v] != OUT_OF_CONTEXT)) {
- v = vert_dest_map[v];
- }
- vert_dest_map[v] = v;
- vert_dest_map[i] = v;
- }
- }
- }
-
- if (v_mask) {
- MEM_freeN(v_mask);
- }
-
- if (vert_kill_len) {
- WeldMesh weld_mesh;
- weld_mesh_context_create(mesh, vert_dest_map, vert_kill_len, &weld_mesh);
-
- mloop = mesh->mloop;
- mpoly = mesh->mpoly;
-
- totedge = mesh->totedge;
- totloop = mesh->totloop;
- totpoly = mesh->totpoly;
-
- const int result_nverts = totvert - weld_mesh.vert_kill_len;
- const int result_nedges = totedge - weld_mesh.edge_kill_len;
- const int result_nloops = totloop - weld_mesh.loop_kill_len;
- const int result_npolys = totpoly - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len;
-
- result = BKE_mesh_new_nomain_from_template(
- mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
-
- /* Vertices */
-
- uint *vert_final = vert_dest_map;
- uint *index_iter = &vert_final[0];
- int dest_index = 0;
- for (uint i = 0; i < totvert; i++, index_iter++) {
- int source_index = i;
- int count = 0;
- while (i < totvert && *index_iter == OUT_OF_CONTEXT) {
- *index_iter = dest_index + count;
- index_iter++;
- count++;
- i++;
- }
- if (count) {
- CustomData_copy_data(&mesh->vdata, &result->vdata, source_index, dest_index, count);
- dest_index += count;
- }
- if (i == totvert) {
- break;
- }
- if (*index_iter != ELEM_MERGED) {
- struct WeldGroup *wgroup = &weld_mesh.vert_groups[*index_iter];
- customdata_weld(&mesh->vdata,
- &result->vdata,
- &weld_mesh.vert_groups_buffer[wgroup->ofs],
- wgroup->len,
- dest_index);
- *index_iter = dest_index;
- dest_index++;
- }
- }
-
- BLI_assert(dest_index == result_nverts);
-
- /* Edges */
-
- uint *edge_final = weld_mesh.edge_groups_map;
- index_iter = &edge_final[0];
- dest_index = 0;
- for (uint i = 0; i < totedge; i++, index_iter++) {
- int source_index = i;
- int count = 0;
- while (i < totedge && *index_iter == OUT_OF_CONTEXT) {
- *index_iter = dest_index + count;
- index_iter++;
- count++;
- i++;
- }
- if (count) {
- CustomData_copy_data(&mesh->edata, &result->edata, source_index, dest_index, count);
- MEdge *me = &result->medge[dest_index];
- dest_index += count;
- for (; count--; me++) {
- me->v1 = vert_final[me->v1];
- me->v2 = vert_final[me->v2];
- }
- }
- if (i == totedge) {
- break;
- }
- if (*index_iter != ELEM_MERGED) {
- struct WeldGroupEdge *wegrp = &weld_mesh.edge_groups[*index_iter];
- customdata_weld(&mesh->edata,
- &result->edata,
- &weld_mesh.edge_groups_buffer[wegrp->group.ofs],
- wegrp->group.len,
- dest_index);
- MEdge *me = &result->medge[dest_index];
- me->v1 = vert_final[wegrp->v1];
- me->v2 = vert_final[wegrp->v2];
- me->flag |= ME_LOOSEEDGE;
-
- *index_iter = dest_index;
- dest_index++;
- }
- }
-
- BLI_assert(dest_index == result_nedges);
-
- /* Polys/Loops */
-
- mp = &mpoly[0];
- MPoly *r_mp = &result->mpoly[0];
- MLoop *r_ml = &result->mloop[0];
- uint r_i = 0;
- int loop_cur = 0;
- uint *group_buffer = BLI_array_alloca(group_buffer, weld_mesh.max_poly_len);
- for (uint i = 0; i < totpoly; i++, mp++) {
- int loop_start = loop_cur;
- uint poly_ctx = weld_mesh.poly_map[i];
- if (poly_ctx == OUT_OF_CONTEXT) {
- uint mp_loop_len = mp->totloop;
- CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart, loop_cur, mp_loop_len);
- loop_cur += mp_loop_len;
- for (; mp_loop_len--; r_ml++) {
- r_ml->v = vert_final[r_ml->v];
- r_ml->e = edge_final[r_ml->e];
- }
- }
- else {
- WeldPoly *wp = &weld_mesh.wpoly[poly_ctx];
- WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(
- &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
- continue;
- }
-
- if (wp->poly_dst != OUT_OF_CONTEXT) {
- continue;
- }
- while (weld_iter_loop_of_poly_next(&iter)) {
- customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
- uint v = vert_final[iter.v];
- uint e = edge_final[iter.e];
- r_ml->v = v;
- r_ml->e = e;
- r_ml++;
- loop_cur++;
- if (iter.type) {
- result->medge[e].flag &= ~ME_LOOSEEDGE;
- }
- BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
- }
- }
-
- CustomData_copy_data(&mesh->pdata, &result->pdata, i, r_i, 1);
- r_mp->loopstart = loop_start;
- r_mp->totloop = loop_cur - loop_start;
- r_mp++;
- r_i++;
- }
-
- WeldPoly *wp = &weld_mesh.wpoly_new[0];
- for (uint i = 0; i < weld_mesh.wpoly_new_len; i++, wp++) {
- int loop_start = loop_cur;
- WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(
- &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
- continue;
- }
-
- if (wp->poly_dst != OUT_OF_CONTEXT) {
- continue;
- }
- while (weld_iter_loop_of_poly_next(&iter)) {
- customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
- uint v = vert_final[iter.v];
- uint e = edge_final[iter.e];
- r_ml->v = v;
- r_ml->e = e;
- r_ml++;
- loop_cur++;
- if (iter.type) {
- result->medge[e].flag &= ~ME_LOOSEEDGE;
- }
- BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
- }
-
- r_mp->loopstart = loop_start;
- r_mp->totloop = loop_cur - loop_start;
- r_mp++;
- r_i++;
- }
-
- BLI_assert((int)r_i == result_npolys);
- BLI_assert(loop_cur == result_nloops);
-
- /* is this needed? */
- BKE_mesh_normals_tag_dirty(result);
-
- weld_mesh_context_free(&weld_mesh);
- }
-
- MEM_freeN(vert_dest_map);
- return result;
-}
-
-static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
-{
- WeldModifierData *wmd = (WeldModifierData *)md;
- return weldModifier_doWeld(wmd, ctx, mesh);
-}
-
-static void initData(ModifierData *md)
-{
- WeldModifierData *wmd = (WeldModifierData *)md;
-
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier));
-
- MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WeldModifierData), modifier);
-}
-
-static void requiredDataMask(Object *UNUSED(ob),
- ModifierData *md,
- CustomData_MeshMasks *r_cddata_masks)
-{
- WeldModifierData *wmd = (WeldModifierData *)md;
-
- /* Ask for vertexgroups if we need them. */
- if (wmd->defgrp_name[0] != '\0') {
- r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
- }
-}
-
-static void panel_draw(const bContext *UNUSED(C), Panel *panel)
-{
- uiLayout *layout = panel->layout;
-
- PointerRNA ob_ptr;
- PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
- int weld_mode = RNA_enum_get(ptr, "mode");
-
- uiLayoutSetPropSep(layout, true);
-
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE);
- if (weld_mode == MOD_WELD_MODE_CONNECTED) {
- uiItemR(layout, ptr, "loose_edges", 0, NULL, ICON_NONE);
- }
- modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
-
- modifier_panel_end(layout, ptr);
-}
-
-static void panelRegister(ARegionType *region_type)
-{
- modifier_panel_register(region_type, eModifierType_Weld, panel_draw);
-}
-
-ModifierTypeInfo modifierType_Weld = {
- /* name */ "Weld",
- /* structName */ "WeldModifierData",
- /* structSize */ sizeof(WeldModifierData),
- /* srna */ &RNA_WeldModifier,
- /* type */ eModifierTypeType_Constructive,
- /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
- eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
- eModifierTypeFlag_AcceptsCVs,
- /* icon */ ICON_AUTOMERGE_OFF, /* TODO: Use correct icon. */
-
- /* copyData */ BKE_modifier_copydata_generic,
-
- /* deformVerts */ NULL,
- /* deformMatrices */ NULL,
- /* deformVertsEM */ NULL,
- /* deformMatricesEM */ NULL,
- /* modifyMesh */ modifyMesh,
- /* modifyHair */ NULL,
- /* modifyGeometrySet */ NULL,
-
- /* initData */ initData,
- /* requiredDataMask */ requiredDataMask,
- /* freeData */ NULL,
- /* isDisabled */ NULL,
- /* updateDepsgraph */ NULL,
- /* dependsOnTime */ NULL,
- /* dependsOnNormals */ NULL,
- /* foreachIDLink */ NULL,
- /* foreachTexLink */ NULL,
- /* freeRuntimeData */ NULL,
- /* panelRegister */ panelRegister,
- /* blendWrite */ NULL,
- /* blendRead */ NULL,
-};
-
-/** \} */
diff --git a/source/blender/modifiers/intern/MOD_weld.cc b/source/blender/modifiers/intern/MOD_weld.cc
new file mode 100644
index 00000000000..64871acabea
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_weld.cc
@@ -0,0 +1,239 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 by the Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup modifiers
+ *
+ * Weld modifier: Remove doubles.
+ */
+
+/* TODOs:
+ * - Review weight and vertex color interpolation.;
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BLI_array.hh"
+#include "BLI_index_range.hh"
+#include "BLI_span.hh"
+#include "BLI_vector.hh"
+
+#include "BLT_translation.h"
+
+#include "DNA_defaults.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_screen_types.h"
+
+#ifdef USE_BVHTREEKDOP
+# include "BKE_bvhutils.h"
+#endif
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_modifier.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_ui_common.h"
+
+#include "GEO_mesh_merge_by_distance.hh"
+
+using blender::Array;
+using blender::IndexMask;
+using blender::Span;
+using blender::Vector;
+
+static Span<MDeformVert> get_vertex_group(const Mesh &mesh, const int defgrp_index)
+{
+ if (defgrp_index == -1) {
+ return {};
+ }
+ const MDeformVert *vertex_group = static_cast<const MDeformVert *>(
+ CustomData_get_layer(&mesh.vdata, CD_MDEFORMVERT));
+ if (!vertex_group) {
+ return {};
+ }
+ return {vertex_group, mesh.totvert};
+}
+
+static Vector<int64_t> selected_indices_from_vertex_group(Span<MDeformVert> vertex_group,
+ const int index,
+ const bool invert)
+{
+ Vector<int64_t> selected_indices;
+ for (const int i : vertex_group.index_range()) {
+ const bool found = BKE_defvert_find_weight(&vertex_group[i], index) > 0.0f;
+ if (found != invert) {
+ selected_indices.append(i);
+ }
+ }
+ return selected_indices;
+}
+
+static Array<bool> selection_array_from_vertex_group(Span<MDeformVert> vertex_group,
+ const int index,
+ const bool invert)
+{
+ Array<bool> selection(vertex_group.size());
+ for (const int i : vertex_group.index_range()) {
+ const bool found = BKE_defvert_find_weight(&vertex_group[i], index) > 0.0f;
+ selection[i] = (found != invert);
+ }
+ return selection;
+}
+
+static std::optional<Mesh *> calculate_weld(const Mesh &mesh, const WeldModifierData &wmd)
+{
+ const int defgrp_index = BKE_id_defgroup_name_index(&mesh.id, wmd.defgrp_name);
+ Span<MDeformVert> vertex_group = get_vertex_group(mesh, defgrp_index);
+ const bool invert = (wmd.flag & MOD_WELD_INVERT_VGROUP) != 0;
+
+ if (wmd.mode == MOD_WELD_MODE_ALL) {
+ if (!vertex_group.is_empty()) {
+ Vector<int64_t> selected_indices = selected_indices_from_vertex_group(
+ vertex_group, defgrp_index, invert);
+ return blender::geometry::mesh_merge_by_distance_all(
+ mesh, IndexMask(selected_indices), wmd.merge_dist);
+ }
+ return blender::geometry::mesh_merge_by_distance_all(
+ mesh, IndexMask(mesh.totvert), wmd.merge_dist);
+ }
+ if (wmd.mode == MOD_WELD_MODE_CONNECTED) {
+ const bool only_loose_edges = (wmd.flag & MOD_WELD_LOOSE_EDGES) != 0;
+ if (!vertex_group.is_empty()) {
+ Array<bool> selection = selection_array_from_vertex_group(
+ vertex_group, defgrp_index, invert);
+ return blender::geometry::mesh_merge_by_distance_connected(
+ mesh, selection, wmd.merge_dist, only_loose_edges);
+ }
+ Array<bool> selection(mesh.totvert, true);
+ return blender::geometry::mesh_merge_by_distance_connected(
+ mesh, selection, wmd.merge_dist, only_loose_edges);
+ }
+
+ BLI_assert_unreachable();
+ return nullptr;
+}
+
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+{
+ const WeldModifierData &wmd = reinterpret_cast<WeldModifierData &>(*md);
+
+ std::optional<Mesh *> result = calculate_weld(*mesh, wmd);
+ if (!result) {
+ return mesh;
+ }
+ return *result;
+}
+
+static void initData(ModifierData *md)
+{
+ WeldModifierData *wmd = (WeldModifierData *)md;
+
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier));
+
+ MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WeldModifierData), modifier);
+}
+
+static void requiredDataMask(Object *UNUSED(ob),
+ ModifierData *md,
+ CustomData_MeshMasks *r_cddata_masks)
+{
+ WeldModifierData *wmd = (WeldModifierData *)md;
+
+ /* Ask for vertexgroups if we need them. */
+ if (wmd->defgrp_name[0] != '\0') {
+ r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
+ }
+}
+
+static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+ int weld_mode = RNA_enum_get(ptr, "mode");
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiItemR(layout, ptr, "mode", 0, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE);
+ if (weld_mode == MOD_WELD_MODE_CONNECTED) {
+ uiItemR(layout, ptr, "loose_edges", 0, nullptr, ICON_NONE);
+ }
+ modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
+
+ modifier_panel_end(layout, ptr);
+}
+
+static void panelRegister(ARegionType *region_type)
+{
+ modifier_panel_register(region_type, eModifierType_Weld, panel_draw);
+}
+
+ModifierTypeInfo modifierType_Weld = {
+ /* name */ "Weld",
+ /* structName */ "WeldModifierData",
+ /* structSize */ sizeof(WeldModifierData),
+ /* srna */ &RNA_WeldModifier,
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */
+ (ModifierTypeFlag)(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
+ eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
+ eModifierTypeFlag_AcceptsCVs),
+ /* icon */ ICON_AUTOMERGE_OFF, /* TODO: Use correct icon. */
+
+ /* copyData */ BKE_modifier_copydata_generic,
+
+ /* deformVerts */ nullptr,
+ /* deformMatrices */ nullptr,
+ /* deformVertsEM */ nullptr,
+ /* deformMatricesEM */ nullptr,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ nullptr,
+ /* modifyGeometrySet */ nullptr,
+
+ /* initData */ initData,
+ /* requiredDataMask */ requiredDataMask,
+ /* freeData */ nullptr,
+ /* isDisabled */ nullptr,
+ /* updateDepsgraph */ nullptr,
+ /* dependsOnTime */ nullptr,
+ /* dependsOnNormals */ nullptr,
+ /* foreachIDLink */ nullptr,
+ /* foreachTexLink */ nullptr,
+ /* freeRuntimeData */ nullptr,
+ /* panelRegister */ panelRegister,
+ /* blendWrite */ nullptr,
+ /* blendRead */ nullptr,
+};
+
+/** \} */
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index e06a3c98016..402a71af27f 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -18,8 +18,11 @@
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
+add_subdirectory(composite)
+add_subdirectory(function)
add_subdirectory(geometry)
add_subdirectory(shader)
+add_subdirectory(texture)
set(INC
.
@@ -45,144 +48,13 @@ set(INC
../windowmanager
../../../intern/glew-mx
../../../intern/guardedalloc
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern
)
set(SRC
- composite/nodes/node_composite_alphaOver.cc
- composite/nodes/node_composite_antialiasing.cc
- composite/nodes/node_composite_bilateralblur.cc
- composite/nodes/node_composite_blur.cc
- composite/nodes/node_composite_bokehblur.cc
- composite/nodes/node_composite_bokehimage.cc
- composite/nodes/node_composite_boxmask.cc
- composite/nodes/node_composite_brightness.cc
- composite/nodes/node_composite_channelMatte.cc
- composite/nodes/node_composite_chromaMatte.cc
- composite/nodes/node_composite_colorMatte.cc
- composite/nodes/node_composite_colorSpill.cc
- composite/nodes/node_composite_colorbalance.cc
- composite/nodes/node_composite_colorcorrection.cc
- composite/nodes/node_composite_common.cc
- composite/nodes/node_composite_composite.cc
- composite/nodes/node_composite_cornerpin.cc
- composite/nodes/node_composite_crop.cc
- composite/nodes/node_composite_cryptomatte.cc
- composite/nodes/node_composite_curves.cc
- composite/nodes/node_composite_defocus.cc
- composite/nodes/node_composite_denoise.cc
- composite/nodes/node_composite_despeckle.cc
- composite/nodes/node_composite_diffMatte.cc
- composite/nodes/node_composite_dilate.cc
- composite/nodes/node_composite_directionalblur.cc
- composite/nodes/node_composite_displace.cc
- composite/nodes/node_composite_distanceMatte.cc
- composite/nodes/node_composite_doubleEdgeMask.cc
- composite/nodes/node_composite_ellipsemask.cc
- composite/nodes/node_composite_exposure.cc
- composite/nodes/node_composite_filter.cc
- composite/nodes/node_composite_flip.cc
- composite/nodes/node_composite_gamma.cc
- composite/nodes/node_composite_glare.cc
- composite/nodes/node_composite_hueSatVal.cc
- composite/nodes/node_composite_huecorrect.cc
- composite/nodes/node_composite_idMask.cc
- composite/nodes/node_composite_image.cc
- composite/nodes/node_composite_inpaint.cc
- composite/nodes/node_composite_invert.cc
- composite/nodes/node_composite_keying.cc
- composite/nodes/node_composite_keyingscreen.cc
- composite/nodes/node_composite_lensdist.cc
- composite/nodes/node_composite_levels.cc
- composite/nodes/node_composite_lummaMatte.cc
- composite/nodes/node_composite_mapRange.cc
- composite/nodes/node_composite_mapUV.cc
- composite/nodes/node_composite_mapValue.cc
- composite/nodes/node_composite_mask.cc
- composite/nodes/node_composite_math.cc
- composite/nodes/node_composite_mixrgb.cc
- composite/nodes/node_composite_movieclip.cc
- composite/nodes/node_composite_moviedistortion.cc
- composite/nodes/node_composite_normal.cc
- composite/nodes/node_composite_normalize.cc
- composite/nodes/node_composite_outputFile.cc
- composite/nodes/node_composite_pixelate.cc
- composite/nodes/node_composite_planetrackdeform.cc
- composite/nodes/node_composite_posterize.cc
- composite/nodes/node_composite_premulkey.cc
- composite/nodes/node_composite_rgb.cc
- composite/nodes/node_composite_rotate.cc
- composite/nodes/node_composite_scale.cc
- composite/nodes/node_composite_sepcombHSVA.cc
- composite/nodes/node_composite_sepcombRGBA.cc
- composite/nodes/node_composite_sepcombYCCA.cc
- composite/nodes/node_composite_sepcombYUVA.cc
- composite/nodes/node_composite_setalpha.cc
- composite/nodes/node_composite_splitViewer.cc
- composite/nodes/node_composite_stabilize2d.cc
- composite/nodes/node_composite_sunbeams.cc
- composite/nodes/node_composite_switch.cc
- composite/nodes/node_composite_switchview.cc
- composite/nodes/node_composite_texture.cc
- composite/nodes/node_composite_tonemap.cc
- composite/nodes/node_composite_trackpos.cc
- composite/nodes/node_composite_transform.cc
- composite/nodes/node_composite_translate.cc
- composite/nodes/node_composite_valToRgb.cc
- composite/nodes/node_composite_value.cc
- composite/nodes/node_composite_vecBlur.cc
- composite/nodes/node_composite_viewer.cc
- composite/nodes/node_composite_zcombine.cc
-
- composite/node_composite_tree.cc
- composite/node_composite_util.cc
-
- function/nodes/legacy/node_fn_random_float.cc
-
- function/nodes/node_fn_align_euler_to_vector.cc
- function/nodes/node_fn_boolean_math.cc
- function/nodes/node_fn_compare.cc
- function/nodes/node_fn_float_to_int.cc
- function/nodes/node_fn_input_bool.cc
- function/nodes/node_fn_input_color.cc
- function/nodes/node_fn_input_int.cc
- function/nodes/node_fn_input_special_characters.cc
- function/nodes/node_fn_input_string.cc
- function/nodes/node_fn_input_vector.cc
- function/nodes/node_fn_random_value.cc
- function/nodes/node_fn_replace_string.cc
- function/nodes/node_fn_rotate_euler.cc
- function/nodes/node_fn_slice_string.cc
- function/nodes/node_fn_string_length.cc
- function/nodes/node_fn_value_to_string.cc
- function/node_function_util.cc
-
- texture/nodes/node_texture_at.c
- texture/nodes/node_texture_bricks.c
- texture/nodes/node_texture_checker.c
- texture/nodes/node_texture_common.c
- texture/nodes/node_texture_compose.c
- texture/nodes/node_texture_coord.c
- texture/nodes/node_texture_curves.c
- texture/nodes/node_texture_decompose.c
- texture/nodes/node_texture_distance.c
- texture/nodes/node_texture_hueSatVal.c
- texture/nodes/node_texture_image.c
- texture/nodes/node_texture_invert.c
- texture/nodes/node_texture_math.c
- texture/nodes/node_texture_mixRgb.c
- texture/nodes/node_texture_output.c
- texture/nodes/node_texture_proc.c
- texture/nodes/node_texture_rotate.c
- texture/nodes/node_texture_scale.c
- texture/nodes/node_texture_texture.c
- texture/nodes/node_texture_translate.c
- texture/nodes/node_texture_valToNor.c
- texture/nodes/node_texture_valToRgb.c
- texture/nodes/node_texture_viewer.c
- texture/node_texture_tree.c
- texture/node_texture_util.c
-
intern/derived_node_tree.cc
intern/geometry_nodes_eval_log.cc
intern/math_functions.cc
@@ -195,10 +67,7 @@ set(SRC
intern/node_socket_declarations.cc
intern/node_tree_ref.cc
intern/node_util.c
-
- composite/node_composite_util.hh
- function/node_function_util.hh
- texture/node_texture_util.h
+ intern/socket_search_link.cc
NOD_common.h
NOD_composite.h
@@ -215,6 +84,7 @@ set(SRC
NOD_socket.h
NOD_socket_declarations.hh
NOD_socket_declarations_geometry.hh
+ NOD_socket_search_link.hh
NOD_static_types.h
NOD_texture.h
intern/node_common.h
@@ -225,19 +95,22 @@ set(SRC
set(LIB
bf_bmesh
bf_functions
+ bf_nodes_composite
+ bf_nodes_function
bf_nodes_geometry
bf_nodes_shader
+ bf_nodes_texture
)
if(WITH_BULLET)
list(APPEND INC_SYS
${BULLET_INCLUDE_DIRS}
- "../../../intern/rigidbody/"
+ ../../../intern/rigidbody
)
if(NOT WITH_SYSTEM_BULLET)
list(APPEND LIB
extern_bullet
- )
+ )
endif()
list(APPEND LIB
@@ -280,13 +153,6 @@ if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)
endif()
-if(WITH_COMPOSITOR)
- list(APPEND INC
- ../compositor
- )
- add_definitions(-DWITH_COMPOSITOR)
-endif()
-
if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
@@ -315,3 +181,6 @@ if(WITH_OPENVDB)
endif()
blender_add_lib(bf_nodes "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_nodes bf_dna)
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index d243577f68d..82faccc2c2d 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -43,6 +43,7 @@ void register_node_type_cmp_texture(void);
void register_node_type_cmp_value(void);
void register_node_type_cmp_rgb(void);
void register_node_type_cmp_curve_time(void);
+void register_node_type_cmp_scene_time(void);
void register_node_type_cmp_movieclip(void);
void register_node_type_cmp_composite(void);
@@ -62,6 +63,7 @@ void register_node_type_cmp_alphaover(void);
void register_node_type_cmp_zcombine(void);
void register_node_type_cmp_colorbalance(void);
void register_node_type_cmp_huecorrect(void);
+void register_node_type_cmp_convert_color_space(void);
void register_node_type_cmp_normal(void);
void register_node_type_cmp_curve_vec(void);
@@ -150,6 +152,75 @@ const char *node_cmp_rlayers_sock_to_pass(int sock_index);
void register_node_type_cmp_custom_group(bNodeType *ntype);
+void ntreeCompositExecTree(struct Scene *scene,
+ struct bNodeTree *ntree,
+ struct RenderData *rd,
+ int rendering,
+ int do_previews,
+ 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 #node_cmp_rlayers_register_pass.
+ */
+void ntreeCompositUpdateRLayers(struct bNodeTree *ntree);
+
+void ntreeCompositClearTags(struct bNodeTree *ntree);
+
+struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree,
+ struct bNode *node,
+ const char *name,
+ struct ImageFormatData *im_format);
+
+int ntreeCompositOutputFileRemoveActiveSocket(struct bNodeTree *ntree, struct bNode *node);
+void ntreeCompositOutputFileSetPath(struct bNode *node,
+ struct bNodeSocket *sock,
+ const char *name);
+void ntreeCompositOutputFileSetLayer(struct bNode *node,
+ struct bNodeSocket *sock,
+ const char *name);
+/* needed in do_versions */
+void ntreeCompositOutputFileUniquePath(struct ListBase *list,
+ struct bNodeSocket *sock,
+ const char defname[],
+ char delim);
+void ntreeCompositOutputFileUniqueLayer(struct ListBase *list,
+ struct bNodeSocket *sock,
+ const char defname[],
+ char delim);
+
+void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
+void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
+
+void ntreeCompositCryptomatteSyncFromAdd(const Scene *scene, bNode *node);
+void ntreeCompositCryptomatteSyncFromRemove(bNode *node);
+bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node);
+int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node);
+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.
+ */
+void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node);
+struct CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *node);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index a0bb47daef2..609d92c09df 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);
@@ -49,6 +49,7 @@ void register_node_type_geo_legacy_select_by_material(void);
void register_node_type_geo_legacy_subdivision_surface(void);
void register_node_type_geo_legacy_volume_to_mesh(void);
+void register_node_type_geo_accumulate_field(void);
void register_node_type_geo_align_rotation_to_vector(void);
void register_node_type_geo_attribute_capture(void);
void register_node_type_geo_attribute_clamp(void);
@@ -76,6 +77,7 @@ 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_primitive_arc(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);
@@ -87,8 +89,8 @@ void register_node_type_geo_curve_resample(void);
void register_node_type_geo_curve_reverse(void);
void register_node_type_geo_curve_sample(void);
void register_node_type_geo_curve_set_handles(void);
-void register_node_type_geo_curve_spline_type(void);
void register_node_type_geo_curve_spline_parameter(void);
+void register_node_type_geo_curve_spline_type(void);
void register_node_type_geo_curve_subdivide(void);
void register_node_type_geo_curve_to_mesh(void);
void register_node_type_geo_curve_to_points(void);
@@ -97,6 +99,9 @@ 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_extrude_mesh(void);
+void register_node_type_geo_field_at_index(void);
+void register_node_type_geo_flip_faces(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);
@@ -105,6 +110,7 @@ void register_node_type_geo_input_id(void);
void register_node_type_geo_input_index(void);
void register_node_type_geo_input_material_index(void);
void register_node_type_geo_input_material(void);
+void register_node_type_geo_input_mesh_edge_angle(void);
void register_node_type_geo_input_mesh_edge_neighbors(void);
void register_node_type_geo_input_mesh_edge_vertices(void);
void register_node_type_geo_input_mesh_face_area(void);
@@ -126,6 +132,7 @@ void register_node_type_geo_is_viewport(void);
void register_node_type_geo_join_geometry(void);
void register_node_type_geo_material_replace(void);
void register_node_type_geo_material_selection(void);
+void register_node_type_geo_merge_by_distance(void);
void register_node_type_geo_mesh_primitive_circle(void);
void register_node_type_geo_mesh_primitive_cone(void);
void register_node_type_geo_mesh_primitive_cube(void);
@@ -151,6 +158,7 @@ void register_node_type_geo_raycast(void);
void register_node_type_geo_realize_instances(void);
void register_node_type_geo_rotate_instances(void);
void register_node_type_geo_sample_texture(void);
+void register_node_type_geo_scale_elements(void);
void register_node_type_geo_scale_instances(void);
void register_node_type_geo_select_by_handle_type(void);
void register_node_type_geo_separate_components(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index f225b3b94b2..7060760237a 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -134,12 +134,8 @@ class GeoNodeExecParams {
}
template<typename T>
- static inline constexpr bool is_field_base_type_v = std::is_same_v<T, float> ||
- std::is_same_v<T, int> ||
- std::is_same_v<T, bool> ||
- std::is_same_v<T, ColorGeometry4f> ||
- std::is_same_v<T, float3> ||
- std::is_same_v<T, std::string>;
+ static inline constexpr bool is_field_base_type_v =
+ is_same_any_v<T, float, int, bool, ColorGeometry4f, float3, std::string>;
/**
* Get the input value for the input socket with the given identifier.
@@ -332,7 +328,7 @@ class GeoNodeExecParams {
*/
GVArray get_input_attribute(const StringRef name,
const GeometryComponent &component,
- const AttributeDomain domain,
+ AttributeDomain domain,
const CustomDataType type,
const void *default_value) const;
@@ -362,7 +358,7 @@ class GeoNodeExecParams {
*/
AttributeDomain get_highest_priority_input_domain(Span<std::string> names,
const GeometryComponent &component,
- const AttributeDomain default_domain) const;
+ AttributeDomain default_domain) const;
std::string attribute_producer_name() const;
diff --git a/source/blender/nodes/NOD_math_functions.hh b/source/blender/nodes/NOD_math_functions.hh
index 54abc754346..6ea89beee2e 100644
--- a/source/blender/nodes/NOD_math_functions.hh
+++ b/source/blender/nodes/NOD_math_functions.hh
@@ -18,9 +18,9 @@
#include "DNA_node_types.h"
-#include "BLI_float3.hh"
#include "BLI_math_base_safe.h"
#include "BLI_math_rotation.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_string_ref.hh"
namespace blender::nodes {
@@ -36,9 +36,9 @@ struct FloatMathOperationInfo {
}
};
-const FloatMathOperationInfo *get_float_math_operation_info(const int operation);
-const FloatMathOperationInfo *get_float3_math_operation_info(const int operation);
-const FloatMathOperationInfo *get_float_compare_operation_info(const int operation);
+const FloatMathOperationInfo *get_float_math_operation_info(int operation);
+const FloatMathOperationInfo *get_float3_math_operation_info(int operation);
+const FloatMathOperationInfo *get_float_compare_operation_info(int operation);
/**
* This calls the `callback` with two arguments:
@@ -240,6 +240,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_fl3_to_fl3(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -259,40 +261,21 @@ inline bool try_dispatch_float_math_fl3_fl3_to_fl3(const NodeVectorMathOperation
case NODE_VECTOR_MATH_MULTIPLY:
return dispatch([](float3 a, float3 b) { return a * b; });
case NODE_VECTOR_MATH_DIVIDE:
- return dispatch([](float3 a, float3 b) {
- return float3(safe_divide(a.x, b.x), safe_divide(a.y, b.y), safe_divide(a.z, b.z));
- });
+ return dispatch([](float3 a, float3 b) { return safe_divide(a, b); });
case NODE_VECTOR_MATH_CROSS_PRODUCT:
- return dispatch([](float3 a, float3 b) { return float3::cross_high_precision(a, b); });
+ return dispatch([](float3 a, float3 b) { return cross_high_precision(a, b); });
case NODE_VECTOR_MATH_PROJECT:
- return dispatch([](float3 a, float3 b) {
- float length_squared = b.length_squared();
- return (length_squared != 0.0) ? (float3::dot(a, b) / length_squared) * b : float3(0.0f);
- });
+ return dispatch([](float3 a, float3 b) { return project(a, b); });
case NODE_VECTOR_MATH_REFLECT:
- return dispatch([](float3 a, float3 b) {
- b.normalize();
- return a.reflected(b);
- });
+ return dispatch([](float3 a, float3 b) { return reflect(a, normalize(b)); });
case NODE_VECTOR_MATH_SNAP:
- return dispatch([](float3 a, float3 b) {
- return float3(floor(safe_divide(a.x, b.x)),
- floor(safe_divide(a.y, b.y)),
- floor(safe_divide(a.z, b.z))) *
- b;
- });
+ return dispatch([](float3 a, float3 b) { return floor(safe_divide(a, b)) * b; });
case NODE_VECTOR_MATH_MODULO:
- return dispatch([](float3 a, float3 b) {
- return float3(safe_modf(a.x, b.x), safe_modf(a.y, b.y), safe_modf(a.z, b.z));
- });
+ return dispatch([](float3 a, float3 b) { return mod(a, b); });
case NODE_VECTOR_MATH_MINIMUM:
- return dispatch([](float3 a, float3 b) {
- return float3(min_ff(a.x, b.x), min_ff(a.y, b.y), min_ff(a.z, b.z));
- });
+ return dispatch([](float3 a, float3 b) { return min(a, b); });
case NODE_VECTOR_MATH_MAXIMUM:
- return dispatch([](float3 a, float3 b) {
- return float3(max_ff(a.x, b.x), max_ff(a.y, b.y), max_ff(a.z, b.z));
- });
+ return dispatch([](float3 a, float3 b) { return max(a, b); });
default:
return false;
}
@@ -306,6 +289,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_fl3_to_fl(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -319,9 +304,9 @@ inline bool try_dispatch_float_math_fl3_fl3_to_fl(const NodeVectorMathOperation
switch (operation) {
case NODE_VECTOR_MATH_DOT_PRODUCT:
- return dispatch([](float3 a, float3 b) { return float3::dot(a, b); });
+ return dispatch([](float3 a, float3 b) { return dot(a, b); });
case NODE_VECTOR_MATH_DISTANCE:
- return dispatch([](float3 a, float3 b) { return float3::distance(a, b); });
+ return dispatch([](float3 a, float3 b) { return distance(a, b); });
default:
return false;
}
@@ -335,6 +320,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_fl3_fl3_to_fl3(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -354,7 +341,7 @@ inline bool try_dispatch_float_math_fl3_fl3_fl3_to_fl3(const NodeVectorMathOpera
return float3(wrapf(a.x, b.x, c.x), wrapf(a.y, b.y, c.y), wrapf(a.z, b.z, c.z));
});
case NODE_VECTOR_MATH_FACEFORWARD:
- return dispatch([](float3 a, float3 b, float3 c) { return float3::faceforward(a, b, c); });
+ return dispatch([](float3 a, float3 b, float3 c) { return faceforward(a, b, c); });
default:
return false;
}
@@ -368,6 +355,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_fl3_fl_to_fl3(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -381,8 +370,7 @@ inline bool try_dispatch_float_math_fl3_fl3_fl_to_fl3(const NodeVectorMathOperat
switch (operation) {
case NODE_VECTOR_MATH_REFRACT:
- return dispatch(
- [](float3 a, float3 b, float c) { return float3::refract(a, b.normalized(), c); });
+ return dispatch([](float3 a, float3 b, float c) { return refract(a, normalize(b), c); });
default:
return false;
}
@@ -396,6 +384,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_to_fl(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -409,7 +399,7 @@ inline bool try_dispatch_float_math_fl3_to_fl(const NodeVectorMathOperation oper
switch (operation) {
case NODE_VECTOR_MATH_LENGTH:
- return dispatch([](float3 in) { return in.length(); });
+ return dispatch([](float3 in) { return length(in); });
default:
return false;
}
@@ -450,6 +440,8 @@ template<typename Callback>
inline bool try_dispatch_float_math_fl3_to_fl3(const NodeVectorMathOperation operation,
Callback &&callback)
{
+ using namespace blender::math;
+
const FloatMathOperationInfo *info = get_float3_math_operation_info(operation);
if (info == nullptr) {
return false;
@@ -463,20 +455,15 @@ inline bool try_dispatch_float_math_fl3_to_fl3(const NodeVectorMathOperation ope
switch (operation) {
case NODE_VECTOR_MATH_NORMALIZE:
- return dispatch([](float3 in) {
- float3 out = in;
- out.normalize();
- return out;
- }); /* Should be safe. */
+ return dispatch([](float3 in) { return normalize(in); }); /* Should be safe. */
case NODE_VECTOR_MATH_FLOOR:
- return dispatch([](float3 in) { return float3(floor(in.x), floor(in.y), floor(in.z)); });
+ return dispatch([](float3 in) { return floor(in); });
case NODE_VECTOR_MATH_CEIL:
- return dispatch([](float3 in) { return float3(ceil(in.x), ceil(in.y), ceil(in.z)); });
+ return dispatch([](float3 in) { return ceil(in); });
case NODE_VECTOR_MATH_FRACTION:
- return dispatch(
- [](float3 in) { return in - float3(floor(in.x), floor(in.y), floor(in.z)); });
+ return dispatch([](float3 in) { return fract(in); });
case NODE_VECTOR_MATH_ABSOLUTE:
- return dispatch([](float3 in) { return float3::abs(in); });
+ return dispatch([](float3 in) { return abs(in); });
case NODE_VECTOR_MATH_SINE:
return dispatch([](float3 in) { return float3(sinf(in.x), sinf(in.y), sinf(in.z)); });
case NODE_VECTOR_MATH_COSINE:
diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh
index cccaf93a7d7..113e8ffc93d 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,30 +87,51 @@ 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_unavailable_ = false;
bool is_attribute_name_ = false;
bool is_default_link_socket_ = false;
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;
@@ -162,12 +186,23 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
decl_->description_ = std::move(value);
return *(Self *)this;
}
+
Self &no_muted_links(bool value = true)
{
decl_->no_mute_links_ = value;
return *(Self *)this;
}
+ /**
+ * Used for sockets that are always unavailable and should not be seen by the user.
+ * Ideally, no new calls to this method should be added over time.
+ */
+ Self &unavailable(bool value = true)
+ {
+ decl_->is_unavailable_ = value;
+ return *(Self *)this;
+ }
+
Self &is_attribute_name(bool value = true)
{
decl_->is_attribute_name_ = value;
@@ -216,6 +251,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>;
@@ -233,6 +280,7 @@ class NodeDeclaration {
Span<SocketDeclarationPtr> inputs() const;
Span<SocketDeclarationPtr> outputs() const;
+ Span<SocketDeclarationPtr> sockets(eNodeSocketInOut in_out) const;
bool is_function_node() const
{
@@ -252,10 +300,13 @@ class NodeDeclarationBuilder {
/**
* All inputs support fields, and all outputs are fields if any of the inputs is a field.
- * Calling field status definitions on each socket is unnecessary.
+ * Calling field status definitions on each socket is unnecessary. Must be called before adding
+ * any sockets.
*/
void is_function_node(bool value = true)
{
+ BLI_assert_msg(declaration_.inputs().is_empty() && declaration_.outputs().is_empty(),
+ "is_function_node() must be called before any socket is created");
declaration_.is_function_node_ = value;
}
@@ -268,7 +319,7 @@ class NodeDeclarationBuilder {
template<typename DeclType>
typename DeclType::Builder &add_socket(StringRef name,
StringRef identifier,
- Vector<SocketDeclarationPtr> &r_decls);
+ eNodeSocketInOut in_out);
};
/* -------------------------------------------------------------------- */
@@ -361,6 +412,11 @@ inline StringRefNull SocketDeclaration::identifier() const
return identifier_;
}
+inline eNodeSocketInOut SocketDeclaration::in_out() const
+{
+ return in_out_;
+}
+
inline StringRefNull SocketDeclaration::description() const
{
return description_;
@@ -386,6 +442,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);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -401,28 +464,38 @@ 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;
+ if (declaration_.is_function_node()) {
+ socket_decl->input_field_type_ = InputSocketFieldType::IsSupported;
+ socket_decl->output_field_dependency_ = OutputFieldDependency::ForDependentField();
+ }
+ declarations.append(std::move(socket_decl));
Builder &socket_decl_builder_ref = *socket_decl_builder;
builders_.append(std::move(socket_decl_builder));
return socket_decl_builder_ref;
@@ -444,6 +517,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 65789069231..ebbec20a139 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -262,6 +262,7 @@ class NodeTreeRef : NonCopyable, NonMovable {
Vector<LinkRef *> links_;
MultiValueMap<const bNodeType *, NodeRef *> nodes_by_type_;
Vector<std::unique_ptr<SocketIndexByIdentifierMap>> owned_identifier_maps_;
+ const NodeRef *group_output_node_ = nullptr;
public:
NodeTreeRef(bNodeTree *btree);
@@ -280,6 +281,11 @@ class NodeTreeRef : NonCopyable, NonMovable {
const NodeRef *find_node(const bNode &bnode) const;
/**
+ * This is the active group output node if there are multiple.
+ */
+ const NodeRef *group_output_node() const;
+
+ /**
* \return True when there is a link cycle. Unavailable sockets are ignored.
*/
bool has_link_cycles() const;
@@ -759,6 +765,11 @@ inline Span<const LinkRef *> NodeTreeRef::links() const
return links_;
}
+inline const NodeRef *NodeTreeRef::group_output_node() const
+{
+ return group_output_node_;
+}
+
inline bNodeTree *NodeTreeRef::btree() const
{
return btree_;
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 76c174201e8..57740ce3ad9 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -85,6 +85,7 @@ void register_node_type_sh_layer_weight(void);
void register_node_type_sh_tex_coord(void);
void register_node_type_sh_particle_info(void);
void register_node_type_sh_hair_info(void);
+void register_node_type_sh_point_info(void);
void register_node_type_sh_volume_info(void);
void register_node_type_sh_script(void);
void register_node_type_sh_normal_map(void);
@@ -143,6 +144,27 @@ void register_node_type_sh_tex_white_noise(void);
void register_node_type_sh_custom_group(bNodeType *ntype);
+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.
+ */
+void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
+ struct GPUMaterial *mat,
+ bool *has_surface_output,
+ bool *has_volume_output);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh
index 1b78a09d6a8..a1972c66ca2 100644
--- a/source/blender/nodes/NOD_socket_declarations.hh
+++ b/source/blender/nodes/NOD_socket_declarations.hh
@@ -21,7 +21,7 @@
#include "RNA_types.h"
#include "BLI_color.hh"
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
namespace blender::nodes::decl {
@@ -39,16 +39,17 @@ 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> {
public:
- FloatBuilder &min(const float value);
- FloatBuilder &max(const float value);
- FloatBuilder &default_value(const float value);
+ FloatBuilder &min(float value);
+ FloatBuilder &max(float value);
+ FloatBuilder &default_value(float value);
FloatBuilder &subtype(PropertySubType subtype);
};
@@ -66,16 +67,17 @@ 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> {
public:
- IntBuilder &min(const int value);
- IntBuilder &max(const int value);
- IntBuilder &default_value(const int value);
+ IntBuilder &min(int value);
+ IntBuilder &max(int value);
+ IntBuilder &default_value(int value);
IntBuilder &subtype(PropertySubType subtype);
};
@@ -93,17 +95,18 @@ 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> {
public:
VectorBuilder &default_value(const float3 value);
VectorBuilder &subtype(PropertySubType subtype);
- VectorBuilder &min(const float min);
- VectorBuilder &max(const float max);
+ VectorBuilder &min(float min);
+ VectorBuilder &max(float max);
VectorBuilder &compact();
};
@@ -117,13 +120,14 @@ 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> {
public:
- BoolBuilder &default_value(const bool value);
+ BoolBuilder &default_value(bool value);
};
class ColorBuilder;
@@ -137,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> {
@@ -157,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> {
@@ -173,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 {
@@ -222,8 +229,9 @@ class Shader : public SocketDeclaration {
public:
using Builder = ShaderBuilder;
- 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 ShaderBuilder : public SocketDeclarationBuilder<Shader> {
diff --git a/source/blender/nodes/NOD_socket_declarations_geometry.hh b/source/blender/nodes/NOD_socket_declarations_geometry.hh
index 3c919729da9..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;
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 84bc7bf0ceb..8cbde6adcad 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -96,6 +96,7 @@ DefNode(ShaderNode, SH_NODE_LIGHT_FALLOFF, 0, "LIG
DefNode(ShaderNode, SH_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "" )
DefNode(ShaderNode, SH_NODE_PARTICLE_INFO, 0, "PARTICLE_INFO", ParticleInfo, "Particle Info", "" )
DefNode(ShaderNode, SH_NODE_HAIR_INFO, 0, "HAIR_INFO", HairInfo, "Hair Info", "" )
+DefNode(ShaderNode, SH_NODE_POINT_INFO, 0, "POINT_INFO", PointInfo, "Point Info", "" )
DefNode(ShaderNode, SH_NODE_VOLUME_INFO, 0, "VOLUME_INFO", VolumeInfo, "Volume Info", "" )
DefNode(ShaderNode, SH_NODE_WIREFRAME, def_sh_tex_wireframe, "WIREFRAME", Wireframe, "Wireframe", "" )
DefNode(ShaderNode, SH_NODE_WAVELENGTH, 0, "WAVELENGTH", Wavelength, "Wavelength", "" )
@@ -148,7 +149,7 @@ DefNode(CompositorNode, CMP_NODE_BLUR, def_cmp_blur, "BLUR",
DefNode(CompositorNode, CMP_NODE_FILTER, def_cmp_filter, "FILTER", Filter, "Filter", "" )
DefNode(CompositorNode, CMP_NODE_MAP_VALUE, def_cmp_map_value, "MAP_VALUE", MapValue, "Map Value", "" )
DefNode(CompositorNode, CMP_NODE_MAP_RANGE, def_cmp_map_range, "MAP_RANGE", MapRange, "Map Range", "" )
-DefNode(CompositorNode, CMP_NODE_TIME, def_time, "TIME", Time, "Time", "" )
+DefNode(CompositorNode, CMP_NODE_TIME, def_time, "TIME", Time, "Time Curve", "" )
DefNode(CompositorNode, CMP_NODE_VECBLUR, def_cmp_vector_blur, "VECBLUR", VecBlur, "Vector Blur", "" )
DefNode(CompositorNode, CMP_NODE_SEPRGBA, 0, "SEPRGBA", SepRGBA, "Separate RGBA", "" )
DefNode(CompositorNode, CMP_NODE_SEPHSVA, 0, "SEPHSVA", SepHSVA, "Separate HSVA", "" )
@@ -227,6 +228,8 @@ DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOIS
DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" )
DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIALIASING", AntiAliasing, "Anti-Aliasing", "" )
DefNode(CompositorNode, CMP_NODE_POSTERIZE, 0, "POSTERIZE", Posterize, "Posterize", "" )
+DefNode(CompositorNode, CMP_NODE_CONVERT_COLOR_SPACE,def_cmp_convert_color_space, "CONVERT_COLORSPACE", ConvertColorSpace, "Color Space","" )
+DefNode(CompositorNode, CMP_NODE_SCENE_TIME, 0, "SCENE_TIME", SceneTime, "Scene Time", "" )
DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
@@ -323,9 +326,9 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, 0, "LEGACY_SELECT_BY_M
DefNode(GeometryNode, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "LEGACY_SUBDIVISION_SURFACE", LegacySubdivisionSurface, "Subdivision Surface", "")
DefNode(GeometryNode, GEO_NODE_LEGACY_VOLUME_TO_MESH, def_geo_volume_to_mesh, "LEGACY_VOLUME_TO_MESH", LegacyVolumeToMesh, "Volume to Mesh", "")
+DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "")
-DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "")
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
@@ -333,7 +336,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_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_ARC, def_geo_curve_primitive_arc, "CURVE_PRIMITIVE_ARC", CurveArc, "Arc", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "")
@@ -342,14 +345,19 @@ DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, def_geo_curve_prim
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "")
DefNode(GeometryNode, GEO_NODE_CURVE_SET_HANDLES, def_geo_curve_set_handles, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "")
DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "CURVE_SPLINE_TYPE", CurveSplineType, "Set Spline Type", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "")
DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "")
+DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, def_geo_accumulate_field, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "")
DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh", "")
+DefNode(GeometryNode, GEO_NODE_EXTRUDE_MESH, def_geo_extrude_mesh, "EXTRUDE_MESH", ExtrudeMesh, "Extrude Mesh", "")
+DefNode(GeometryNode, GEO_NODE_FIELD_AT_INDEX, def_geo_field_at_index, "FIELD_AT_INDEX", FieldAtIndex, "Field at Index", "")
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_FLIP_FACES, 0, "FLIP_FACES", FlipFaces, "Flip Faces", "")
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", "")
@@ -358,6 +366,7 @@ DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "")
DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL_INDEX, 0, "INPUT_MATERIAL_INDEX", InputMaterialIndex, "Material Index", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_ANGLE, 0, "MESH_EDGE_ANGLE", InputMeshEdgeAngle, "Edge Angle", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, 0, "MESH_EDGE_NEIGHBORS", InputMeshEdgeNeighbors, "Edge Neighbors", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_VERTICES, 0, "MESH_EDGE_VERTICES", InputMeshEdgeVertices, "Edge Vertices", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_AREA, 0, "MESH_FACE_AREA", InputMeshFaceArea, "Face Area", "")
@@ -378,6 +387,7 @@ DefNode(GeometryNode, GEO_NODE_INSTANCES_TO_POINTS, 0, "INSTANCES_TO_POINTS", In
DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "")
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
DefNode(GeometryNode, GEO_NODE_MATERIAL_SELECTION, 0, "MATERIAL_SELECTION", MaterialSelection, "Material Selection", "")
+DefNode(GeometryNode, GEO_NODE_MERGE_BY_DISTANCE, 0, "MERGE_BY_DISTANCE", MergeByDistance, "Merge by Distance", "")
DefNode(GeometryNode, GEO_NODE_MESH_BOOLEAN, def_geo_boolean, "MESH_BOOLEAN", MeshBoolean, "Mesh Boolean", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Mesh Circle", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "")
@@ -400,6 +410,7 @@ DefNode(GeometryNode, GEO_NODE_RESAMPLE_CURVE, def_geo_curve_resample, "RESAMPLE
DefNode(GeometryNode, GEO_NODE_REVERSE_CURVE, 0, "REVERSE_CURVE", ReverseCurve, "Reverse Curve", "")
DefNode(GeometryNode, GEO_NODE_ROTATE_INSTANCES, 0, "ROTATE_INSTANCES", RotateInstances, "Rotate Instances", "")
DefNode(GeometryNode, GEO_NODE_SAMPLE_CURVE, def_geo_curve_sample, "SAMPLE_CURVE", SampleCurve, "Sample Curve", "")
+DefNode(GeometryNode, GEO_NODE_SCALE_ELEMENTS, def_geo_scale_elements, "SCALE_ELEMENTS", ScaleElements, "Scale Elements", "")
DefNode(GeometryNode, GEO_NODE_SCALE_INSTANCES, 0, "SCALE_INSTANCES", ScaleInstances, "Scale Instances", "")
DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS", SeparateComponents, "Separate Components", "")
DefNode(GeometryNode, GEO_NODE_SEPARATE_GEOMETRY, def_geo_separate_geometry, "SEPARATE_GEOMETRY", SeparateGeometry, "Separate Geometry", "")
diff --git a/source/blender/nodes/NOD_texture.h b/source/blender/nodes/NOD_texture.h
index af59fefd925..c08bc814915 100644
--- a/source/blender/nodes/NOD_texture.h
+++ b/source/blender/nodes/NOD_texture.h
@@ -74,6 +74,22 @@ void register_node_type_tex_proc_noise(void);
void register_node_type_tex_proc_stucci(void);
void register_node_type_tex_proc_distnoise(void);
+void ntreeTexCheckCyclics(struct bNodeTree *ntree);
+struct bNodeTreeExec *ntreeTexBeginExecTree(struct bNodeTree *ntree);
+void ntreeTexEndExecTree(struct bNodeTreeExec *exec);
+int ntreeTexExecTree(struct bNodeTree *ntree,
+ struct TexResult *target,
+ const float co[3],
+ float dxt[3],
+ float dyt[3],
+ int osatex,
+ short thread,
+ const struct Tex *tex,
+ short which_output,
+ int cfra,
+ int preview,
+ struct MTex *mtex);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt
new file mode 100644
index 00000000000..8d2b2befd1a
--- /dev/null
+++ b/source/blender/nodes/composite/CMakeLists.txt
@@ -0,0 +1,163 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2021, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ..
+ ../intern
+ ../../editors/include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../depsgraph
+ ../../imbuf
+ ../../makesdna
+ ../../makesrna
+ ../../render
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+
+ # dna_type_offsets.h
+ ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern
+)
+
+
+set(SRC
+ nodes/node_composite_alpha_over.cc
+ nodes/node_composite_antialiasing.cc
+ nodes/node_composite_bilateralblur.cc
+ nodes/node_composite_blur.cc
+ nodes/node_composite_bokehblur.cc
+ nodes/node_composite_bokehimage.cc
+ nodes/node_composite_boxmask.cc
+ nodes/node_composite_brightness.cc
+ nodes/node_composite_channel_matte.cc
+ nodes/node_composite_chroma_matte.cc
+ nodes/node_composite_color_matte.cc
+ nodes/node_composite_color_spill.cc
+ nodes/node_composite_colorbalance.cc
+ nodes/node_composite_colorcorrection.cc
+ nodes/node_composite_common.cc
+ nodes/node_composite_composite.cc
+ nodes/node_composite_convert_color_space.cc
+ nodes/node_composite_cornerpin.cc
+ nodes/node_composite_crop.cc
+ nodes/node_composite_cryptomatte.cc
+ nodes/node_composite_curves.cc
+ nodes/node_composite_defocus.cc
+ nodes/node_composite_denoise.cc
+ nodes/node_composite_despeckle.cc
+ nodes/node_composite_diff_matte.cc
+ nodes/node_composite_dilate.cc
+ nodes/node_composite_directionalblur.cc
+ nodes/node_composite_displace.cc
+ nodes/node_composite_distance_matte.cc
+ nodes/node_composite_double_edge_mask.cc
+ nodes/node_composite_ellipsemask.cc
+ nodes/node_composite_exposure.cc
+ nodes/node_composite_filter.cc
+ nodes/node_composite_flip.cc
+ nodes/node_composite_gamma.cc
+ nodes/node_composite_glare.cc
+ nodes/node_composite_hue_sat_val.cc
+ nodes/node_composite_huecorrect.cc
+ nodes/node_composite_id_mask.cc
+ nodes/node_composite_image.cc
+ nodes/node_composite_inpaint.cc
+ nodes/node_composite_invert.cc
+ nodes/node_composite_keying.cc
+ nodes/node_composite_keyingscreen.cc
+ nodes/node_composite_lensdist.cc
+ nodes/node_composite_levels.cc
+ nodes/node_composite_luma_matte.cc
+ nodes/node_composite_map_range.cc
+ nodes/node_composite_map_uv.cc
+ nodes/node_composite_map_value.cc
+ nodes/node_composite_mask.cc
+ nodes/node_composite_math.cc
+ nodes/node_composite_mixrgb.cc
+ nodes/node_composite_movieclip.cc
+ nodes/node_composite_moviedistortion.cc
+ nodes/node_composite_normal.cc
+ nodes/node_composite_normalize.cc
+ nodes/node_composite_output_file.cc
+ nodes/node_composite_pixelate.cc
+ nodes/node_composite_planetrackdeform.cc
+ nodes/node_composite_posterize.cc
+ nodes/node_composite_premulkey.cc
+ nodes/node_composite_rgb.cc
+ nodes/node_composite_rotate.cc
+ nodes/node_composite_scale.cc
+ nodes/node_composite_scene_time.cc
+ nodes/node_composite_sepcomb_hsva.cc
+ nodes/node_composite_sepcomb_rgba.cc
+ nodes/node_composite_sepcomb_ycca.cc
+ nodes/node_composite_sepcomb_yuva.cc
+ nodes/node_composite_setalpha.cc
+ nodes/node_composite_split_viewer.cc
+ nodes/node_composite_stabilize2d.cc
+ nodes/node_composite_sunbeams.cc
+ nodes/node_composite_switch.cc
+ nodes/node_composite_switchview.cc
+ nodes/node_composite_texture.cc
+ nodes/node_composite_tonemap.cc
+ nodes/node_composite_trackpos.cc
+ nodes/node_composite_transform.cc
+ nodes/node_composite_translate.cc
+ nodes/node_composite_val_to_rgb.cc
+ nodes/node_composite_value.cc
+ nodes/node_composite_vec_blur.cc
+ nodes/node_composite_viewer.cc
+ nodes/node_composite_zcombine.cc
+
+ node_composite_tree.cc
+ node_composite_util.cc
+
+ node_composite_util.hh
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+if(WITH_IMAGE_OPENEXR)
+ add_definitions(-DWITH_OPENEXR)
+endif()
+
+if(WITH_COMPOSITOR)
+ list(APPEND INC
+ ../../compositor
+ )
+ add_definitions(-DWITH_COMPOSITOR)
+endif()
+
+if(WITH_OPENIMAGEDENOISE)
+ add_definitions(-DWITH_OPENIMAGEDENOISE)
+endif()
+
+blender_add_lib(bf_nodes_composite "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_nodes_composite PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_nodes_composite PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
+
+# Needed so we can use dna_type_offsets.h for defaults initialization.
+add_dependencies(bf_nodes_composite bf_dna)
diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc
index 1326c9edab1..c54382cc1ad 100644
--- a/source/blender/nodes/composite/node_composite_tree.cc
+++ b/source/blender/nodes/composite/node_composite_tree.cc
@@ -33,8 +33,11 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
+#include "UI_resources.h"
+
#include "node_common.h"
#include "node_util.h"
@@ -117,29 +120,11 @@ static void localize(bNodeTree *localtree, bNodeTree *ntree)
}
}
- bNodeSocket *output_sock = (bNodeSocket *)node->outputs.first;
- bNodeSocket *local_output_sock = (bNodeSocket *)local_node->outputs.first;
- while (output_sock != nullptr) {
- local_output_sock->cache = output_sock->cache;
- output_sock->cache = nullptr;
- /* This is actually link to original: someone was just lazy enough and tried to save few
- * bytes in the cost of readability. */
- local_output_sock->new_sock = output_sock;
-
- output_sock = output_sock->next;
- local_output_sock = local_output_sock->next;
- }
-
node = node->next;
local_node = local_node->next;
}
}
-static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_sync_tree(ntree, localtree);
-}
-
static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
{
bNode *lnode;
@@ -149,11 +134,11 @@ static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
BKE_node_preview_merge_tree(ntree, localtree, true);
for (lnode = (bNode *)localtree->nodes.first; lnode; lnode = lnode->next) {
- if (ntreeNodeExists(ntree, lnode->new_node)) {
+ if (bNode *orig_node = nodeFindNodebyName(ntree, lnode->name)) {
if (ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
if (lnode->id && (lnode->flag & NODE_DO_OUTPUT)) {
/* image_merge does sanity check for pointers */
- BKE_image_merge(bmain, (Image *)lnode->new_node->id, (Image *)lnode->id);
+ BKE_image_merge(bmain, (Image *)orig_node->id, (Image *)lnode->id);
}
}
else if (lnode->type == CMP_NODE_MOVIEDISTORTION) {
@@ -161,20 +146,19 @@ static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
* and to achieve much better performance on further calls this context should be
* copied back to original node */
if (lnode->storage) {
- if (lnode->new_node->storage) {
- BKE_tracking_distortion_free((MovieDistortion *)lnode->new_node->storage);
+ if (orig_node->storage) {
+ BKE_tracking_distortion_free((MovieDistortion *)orig_node->storage);
}
- lnode->new_node->storage = BKE_tracking_distortion_copy(
- (MovieDistortion *)lnode->storage);
+ orig_node->storage = BKE_tracking_distortion_copy((MovieDistortion *)lnode->storage);
}
}
for (lsock = (bNodeSocket *)lnode->outputs.first; lsock; lsock = lsock->next) {
- if (ntreeOutputExists(lnode->new_node, lsock->new_sock)) {
- lsock->new_sock->cache = lsock->cache;
+ if (bNodeSocket *orig_socket = nodeFindSocket(orig_node, SOCK_OUT, lsock->identifier)) {
+ orig_socket->cache = lsock->cache;
lsock->cache = nullptr;
- lsock->new_sock = nullptr;
+ orig_socket = nullptr;
}
}
}
@@ -186,11 +170,6 @@ static void update(bNodeTree *ntree)
ntreeSetOutput(ntree);
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
static void composite_node_add_init(bNodeTree *UNUSED(bnodetree), bNode *bnode)
@@ -214,20 +193,18 @@ bNodeTreeType *ntreeType_Composite;
void register_node_tree_type_cmp()
{
- bNodeTreeType *tt = ntreeType_Composite = (bNodeTreeType *)MEM_callocN(
- sizeof(bNodeTreeType), "compositor node tree type");
+ bNodeTreeType *tt = ntreeType_Composite = MEM_cnew<bNodeTreeType>(__func__);
tt->type = NTREE_COMPOSIT;
strcpy(tt->idname, "CompositorNodeTree");
strcpy(tt->ui_name, N_("Compositor"));
- tt->ui_icon = 0; /* Defined in `drawnode.c`. */
+ tt->ui_icon = ICON_NODE_COMPOSITING;
strcpy(tt->ui_description, N_("Compositing nodes"));
tt->free_cache = free_cache;
tt->free_node_cache = free_node_cache;
tt->foreach_nodeclass = foreach_nodeclass;
tt->localize = localize;
- tt->local_sync = local_sync;
tt->local_merge = local_merge;
tt->update = update;
tt->get_from_context = composite_get_from_context;
@@ -272,23 +249,6 @@ void ntreeCompositUpdateRLayers(bNodeTree *ntree)
}
}
-void ntreeCompositRegisterPass(bNodeTree *ntree,
- Scene *scene,
- ViewLayer *view_layer,
- const char *name,
- eNodeSocketDatatype type)
-{
- if (ntree == nullptr) {
- return;
- }
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == CMP_NODE_R_LAYERS) {
- node_cmp_rlayers_register_pass(ntree, node, scene, view_layer, name, type);
- }
- }
-}
-
void ntreeCompositTagRender(Scene *scene)
{
/* XXX Think using G_MAIN here is valid, since you want to update current file's scene nodes,
@@ -301,14 +261,15 @@ void ntreeCompositTagRender(Scene *scene)
if (sce_iter->nodetree) {
LISTBASE_FOREACH (bNode *, node, &sce_iter->nodetree->nodes) {
if (node->id == (ID *)scene || node->type == CMP_NODE_COMPOSITE) {
- nodeUpdate(sce_iter->nodetree, node);
+ BKE_ntree_update_tag_node_property(sce_iter->nodetree, node);
}
else if (node->type == CMP_NODE_TEXTURE) /* uses scene size_x/size_y */ {
- nodeUpdate(sce_iter->nodetree, node);
+ BKE_ntree_update_tag_node_property(sce_iter->nodetree, node);
}
}
}
}
+ BKE_ntree_update_main(G_MAIN, nullptr);
}
/* XXX after render animation system gets a refresh, this call allows composite to end clean */
diff --git a/source/blender/nodes/composite/node_composite_util.cc b/source/blender/nodes/composite/node_composite_util.cc
index 9ea98d2a867..1f892c1c9e2 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),
@@ -45,11 +47,12 @@ void cmp_node_update_default(bNodeTree *UNUSED(ntree), bNode *node)
node->need_exec = 1;
}
-void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = cmp_node_poll_default;
ntype->updatefunc = cmp_node_update_default;
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 04708d0d854..65dbc2065ef 100644
--- a/source/blender/nodes/composite/node_composite_util.hh
+++ b/source/blender/nodes/composite/node_composite_util.hh
@@ -52,5 +52,4 @@ bool cmp_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
void cmp_node_update_default(struct bNodeTree *ntree, struct bNode *node);
-void cmp_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void cmp_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
diff --git a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc b/source/blender/nodes/composite/nodes/node_composite_alpha_over.cc
index b971b26aa6f..a080b7d4840 100644
--- a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_alpha_over.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** ALPHAOVER ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_alpha_over_cc {
static void cmp_node_alphaover_declare(NodeDeclarationBuilder &b)
{
@@ -35,20 +38,32 @@ static void cmp_node_alphaover_declare(NodeDeclarationBuilder &b)
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");
+ node->storage = MEM_cnew<NodeTwoFloats>(__func__);
+}
+
+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);
}
+} // namespace blender::nodes::node_composite_alpha_over_cc
+
void register_node_type_cmp_alphaover()
{
+ namespace file_ns = blender::nodes::node_composite_alpha_over_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_ALPHAOVER, "Alpha Over", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_alphaover_declare;
- node_type_init(&ntype, node_alphaover_init);
+ cmp_node_type_base(&ntype, CMP_NODE_ALPHAOVER, "Alpha Over", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_alphaover_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_alphaover;
+ node_type_init(&ntype, file_ns::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 a498033733f..fcc04a85b38 100644
--- a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
@@ -23,11 +23,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Anti-Aliasing (SMAA 1x) ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_antialiasing_cc {
static void cmp_node_antialiasing_declare(NodeDeclarationBuilder &b)
{
@@ -35,12 +38,9 @@ static void cmp_node_antialiasing_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAntiAliasingData *data = (NodeAntiAliasingData *)MEM_callocN(sizeof(NodeAntiAliasingData),
- "node antialiasing data");
+ NodeAntiAliasingData *data = MEM_cnew<NodeAntiAliasingData>(__func__);
data->threshold = CMP_DEFAULT_SMAA_THRESHOLD;
data->contrast_limit = CMP_DEFAULT_SMAA_CONTRAST_LIMIT;
@@ -49,15 +49,31 @@ static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = data;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_antialiasing_cc
+
void register_node_type_cmp_antialiasing()
{
+ namespace file_ns = blender::nodes::node_composite_antialiasing_cc;
+
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_antialiasing_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_antialiasing_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_antialiasing;
+ ntype.flag |= NODE_PREVIEW;
node_type_size(&ntype, 170, 140, 200);
- node_type_init(&ntype, node_composit_init_antialiasing);
+ node_type_init(&ntype, file_ns::node_composit_init_antialiasing);
node_type_storage(
&ntype, "NodeAntiAliasingData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
index 7ec28fba460..1c3303103f8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** BILATERALBLUR ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_bilateralblur_cc {
static void cmp_node_bilateralblur_declare(NodeDeclarationBuilder &b)
{
@@ -34,25 +37,39 @@ static void cmp_node_bilateralblur_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBilateralBlurData *nbbd = (NodeBilateralBlurData *)MEM_callocN(sizeof(NodeBilateralBlurData),
- "node bilateral blur data");
+ NodeBilateralBlurData *nbbd = MEM_cnew<NodeBilateralBlurData>(__func__);
node->storage = nbbd;
nbbd->iter = 1;
nbbd->sigma_color = 0.3;
nbbd->sigma_space = 5.0;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_bilateralblur_cc
+
void register_node_type_cmp_bilateralblur()
{
+ namespace file_ns = blender::nodes::node_composite_bilateralblur_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER, 0);
- ntype.declare = blender::nodes::cmp_node_bilateralblur_declare;
- node_type_init(&ntype, node_composit_init_bilateralblur);
+ cmp_node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_bilateralblur_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_bilateralblur;
+ node_type_init(&ntype, file_ns::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 274c2567749..dd0a6db74c1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_blur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_blur.cc
@@ -22,11 +22,16 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** BLUR ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_blur_cc {
static void cmp_node_blur_declare(NodeDeclarationBuilder &b)
{
@@ -35,22 +40,67 @@ static void cmp_node_blur_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBlurData *data = (NodeBlurData *)MEM_callocN(sizeof(NodeBlurData), "node blur data");
+ NodeBlurData *data = MEM_cnew<NodeBlurData>(__func__);
data->filtertype = R_FILTER_GAUSS;
node->storage = data;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_blur_cc
+
void register_node_type_cmp_blur()
{
+ namespace file_ns = blender::nodes::node_composite_blur_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_blur_declare;
- node_type_init(&ntype, node_composit_init_blur);
+ cmp_node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_blur_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_blur;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::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 b5f3f7c9a1e..282328b5e10 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
@@ -22,11 +22,14 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
/* **************** BLUR ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_bokehblur_cc {
static void cmp_node_bokehblur_declare(NodeDeclarationBuilder &b)
{
@@ -37,21 +40,32 @@ static void cmp_node_bokehblur_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_bokehblur(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom3 = 4.0f;
node->custom4 = 16.0f;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_bokehblur_cc
+
void register_node_type_cmp_bokehblur()
{
+ namespace file_ns = blender::nodes::node_composite_bokehblur_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER, 0);
- ntype.declare = blender::nodes::cmp_node_bokehblur_declare;
- node_type_init(&ntype, node_composit_init_bokehblur);
+ cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_bokehblur_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_bokehblur;
+ node_type_init(&ntype, file_ns::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 ad4cbb47a77..df502bc625f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
@@ -21,22 +21,23 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
/* **************** Bokeh image Tools ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_bokehimage_cc {
static void cmp_node_bokehimage_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBokehImage *data = (NodeBokehImage *)MEM_callocN(sizeof(NodeBokehImage), "NodeBokehImage");
+ NodeBokehImage *data = MEM_cnew<NodeBokehImage>(__func__);
data->angle = 0.0f;
data->flaps = 5;
data->rounding = 0.0f;
@@ -45,13 +46,34 @@ static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_bokehimage_cc
+
void register_node_type_cmp_bokehimage()
{
+ namespace file_ns = blender::nodes::node_composite_bokehimage_cc;
+
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;
- node_type_init(&ntype, node_composit_init_bokehimage);
+ cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_bokehimage_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_bokehimage;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::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 e423bd051fe..499942725c2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_boxmask_cc {
static void cmp_node_boxmask_declare(NodeDeclarationBuilder &b)
{
@@ -34,11 +37,9 @@ static void cmp_node_boxmask_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Mask"));
}
-} // namespace blender::nodes
-
static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBoxMask *data = (NodeBoxMask *)MEM_callocN(sizeof(NodeBoxMask), "NodeBoxMask");
+ NodeBoxMask *data = MEM_cnew<NodeBoxMask>(__func__);
data->x = 0.5;
data->y = 0.5;
data->width = 0.2;
@@ -47,13 +48,34 @@ static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_boxmask_cc
+
void register_node_type_cmp_boxmask()
{
+ namespace file_ns = blender::nodes::node_composite_boxmask_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MASK_BOX, "Box Mask", NODE_CLASS_MATTE, 0);
- ntype.declare = blender::nodes::cmp_node_boxmask_declare;
- node_type_init(&ntype, node_composit_init_boxmask);
+ cmp_node_type_base(&ntype, CMP_NODE_MASK_BOX, "Box Mask", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_boxmask_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_boxmask;
+ node_type_init(&ntype, file_ns::node_composit_init_boxmask);
node_type_storage(&ntype, "NodeBoxMask", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.cc b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
index 69af3fdca10..7f60187dddf 100644
--- a/source/blender/nodes/composite/nodes/node_composite_brightness.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Bright and Contrast ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_brightness_cc {
static void cmp_node_brightcontrast_declare(NodeDeclarationBuilder &b)
{
@@ -35,20 +38,30 @@ static void cmp_node_brightcontrast_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_brightcontrast(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_brightness_cc
+
void register_node_type_cmp_brightcontrast()
{
+ namespace file_ns = blender::nodes::node_composite_brightness_cc;
+
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;
- node_type_init(&ntype, node_composit_init_brightcontrast);
+ cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_brightcontrast_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_brightcontrast;
+ node_type_init(&ntype, file_ns::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
deleted file mode 100644
index ec569a27bf8..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* ******************* Channel Matte Node ********************************* */
-
-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)
-{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
- node->storage = c;
- c->t1 = 1.0f;
- c->t2 = 0.0f;
- c->t3 = 0.0f;
- c->fsize = 0.0f;
- c->fstrength = 0.0f;
- c->algorithm = 1; /* Max channel limiting. */
- c->channel = 1; /* Limit by red. */
- node->custom1 = 1; /* RGB channel. */
- node->custom2 = 2; /* Green Channel. */
-}
-
-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);
- ntype.declare = blender::nodes::cmp_node_channel_matte_declare;
- node_type_init(&ntype, node_composit_init_channel_matte);
- node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_channel_matte.cc b/source/blender/nodes/composite/nodes/node_composite_channel_matte.cc
new file mode 100644
index 00000000000..a53e6a97dae
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_channel_matte.cc
@@ -0,0 +1,114 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* ******************* Channel Matte Node ********************************* */
+
+namespace blender::nodes::node_composite_channel_matte_cc {
+
+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"));
+}
+
+static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
+ node->storage = c;
+ c->t1 = 1.0f;
+ c->t2 = 0.0f;
+ c->t3 = 0.0f;
+ c->fsize = 0.0f;
+ c->fstrength = 0.0f;
+ c->algorithm = 1; /* Max channel limiting. */
+ c->channel = 1; /* Limit by red. */
+ node->custom1 = 1; /* RGB channel. */
+ node->custom2 = 2; /* Green Channel. */
+}
+
+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);
+}
+
+} // namespace blender::nodes::node_composite_channel_matte_cc
+
+void register_node_type_cmp_channel_matte()
+{
+ namespace file_ns = blender::nodes::node_composite_channel_matte_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_CHANNEL_MATTE, "Channel Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_channel_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_channel_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_channel_matte);
+ node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_chroma_matte.cc
index 02e2a24989b..a85cdd05b14 100644
--- a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_chroma_matte.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Chroma Key ********************************************************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_chroma_matte_cc {
static void cmp_node_chroma_matte_declare(NodeDeclarationBuilder &b)
{
@@ -35,11 +38,9 @@ static void cmp_node_chroma_matte_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Matte"));
}
-} // namespace blender::nodes
-
static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->t1 = DEG2RADF(30.0f);
c->t2 = DEG2RADF(10.0f);
@@ -48,13 +49,35 @@ static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *nod
c->fstrength = 1.0f;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_chroma_matte_cc
+
void register_node_type_cmp_chroma_matte()
{
+ namespace file_ns = blender::nodes::node_composite_chroma_matte_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_chroma_matte_declare;
- node_type_init(&ntype, node_composit_init_chroma_matte);
+ cmp_node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_chroma_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_chroma_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_chroma_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
deleted file mode 100644
index 2e5735414bd..00000000000
--- a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup cmpnodes
- */
-
-#include "node_composite_util.hh"
-
-/* ******************* Color Spill Suppression ********************************* */
-
-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)
-{
- NodeColorspill *ncs = (NodeColorspill *)MEM_callocN(sizeof(NodeColorspill), "node colorspill");
- node->storage = ncs;
- node->custom1 = 2; /* green channel */
- node->custom2 = 0; /* simple limit algorithm */
- ncs->limchan = 0; /* limit by red */
- ncs->limscale = 1.0f; /* limit scaling factor */
- ncs->unspill = 0; /* do not use unspill */
-}
-
-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);
- ntype.declare = blender::nodes::cmp_node_color_spill_declare;
- node_type_init(&ntype, node_composit_init_color_spill);
- node_type_storage(
- &ntype, "NodeColorspill", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc b/source/blender/nodes/composite/nodes/node_composite_color_matte.cc
index 564e9dbbff4..58bd0bd7d69 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_color_matte.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Color Matte ********************************************************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_color_matte_cc {
static void cmp_node_color_matte_declare(NodeDeclarationBuilder &b)
{
@@ -35,11 +38,9 @@ static void cmp_node_color_matte_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Matte"));
}
-} // namespace blender::nodes
-
static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node color");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->t1 = 0.01f;
c->t2 = 0.1f;
@@ -48,13 +49,36 @@ static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node
c->fstrength = 1.0f;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_color_matte_cc
+
void register_node_type_cmp_color_matte()
{
+ namespace file_ns = blender::nodes::node_composite_color_matte_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_color_matte_declare;
- node_type_init(&ntype, node_composit_init_color_matte);
+ cmp_node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_color_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_color_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_color_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_color_spill.cc b/source/blender/nodes/composite/nodes/node_composite_color_spill.cc
new file mode 100644
index 00000000000..1ee7686a8b1
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_color_spill.cc
@@ -0,0 +1,115 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
+
+/* ******************* Color Spill Suppression ********************************* */
+
+namespace blender::nodes::node_composite_color_spill_cc {
+
+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"));
+}
+
+static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeColorspill *ncs = MEM_cnew<NodeColorspill>(__func__);
+ node->storage = ncs;
+ node->custom1 = 2; /* green channel */
+ node->custom2 = 0; /* simple limit algorithm */
+ ncs->limchan = 0; /* limit by red */
+ ncs->limscale = 1.0f; /* limit scaling factor */
+ ncs->unspill = 0; /* do not use unspill */
+}
+
+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);
+ }
+}
+
+} // namespace blender::nodes::node_composite_color_spill_cc
+
+void register_node_type_cmp_color_spill()
+{
+ namespace file_ns = blender::nodes::node_composite_color_spill_cc;
+
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_color_spill_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_color_spill;
+ node_type_init(&ntype, file_ns::node_composit_init_color_spill);
+ node_type_storage(
+ &ntype, "NodeColorspill", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
index 1de8c486afb..809641ec147 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
@@ -21,20 +21,14 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
-/* ******************* Color Balance ********************************* */
+#include "RNA_access.h"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
-static void cmp_node_colorbalance_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"));
-}
+#include "node_composite_util.hh"
-} // namespace blender::nodes
+/* ******************* Color Balance ********************************* */
/* 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
@@ -64,10 +58,18 @@ void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *UNUSED(ntree), bNode *node)
}
}
+namespace blender::nodes::node_composite_colorbalance_cc {
+
+static void cmp_node_colorbalance_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"));
+}
+
static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorBalance *n = (NodeColorBalance *)MEM_callocN(sizeof(NodeColorBalance),
- "node colorbalance");
+ NodeColorBalance *n = MEM_cnew<NodeColorBalance>(__func__);
n->lift[0] = n->lift[1] = n->lift[2] = 1.0f;
n->gamma[0] = n->gamma[1] = n->gamma[2] = 1.0f;
@@ -79,14 +81,94 @@ static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = n;
}
+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);
+ }
+}
+
+} // namespace blender::nodes::node_composite_colorbalance_cc
+
void register_node_type_cmp_colorbalance()
{
+ namespace file_ns = blender::nodes::node_composite_colorbalance_cc;
+
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;
+ cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_colorbalance_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_colorbalance;
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_colorbalance_ex;
node_type_size(&ntype, 400, 200, 400);
- node_type_init(&ntype, node_composit_init_colorbalance);
+ node_type_init(&ntype, file_ns::node_composit_init_colorbalance);
node_type_storage(
&ntype, "NodeColorBalance", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
index 32f4a7dc1ae..9f1dcf24de9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Color Correction ********************************* */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_colorcorrection_cc {
static void cmp_node_colorcorrection_declare(NodeDeclarationBuilder &b)
{
@@ -34,12 +37,9 @@ static void cmp_node_colorcorrection_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_colorcorrection(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorCorrection *n = (NodeColorCorrection *)MEM_callocN(sizeof(NodeColorCorrection),
- "node colorcorrection");
+ NodeColorCorrection *n = MEM_cnew<NodeColorCorrection>(__func__);
n->startmidtones = 0.2f;
n->endmidtones = 0.7f;
n->master.contrast = 1.0f;
@@ -66,14 +66,236 @@ static void node_composit_init_colorcorrection(bNodeTree *UNUSED(ntree), bNode *
node->storage = n;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_colorcorrection_cc
+
void register_node_type_cmp_colorcorrection()
{
+ namespace file_ns = blender::nodes::node_composite_colorcorrection_cc;
+
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;
+ cmp_node_type_base(&ntype, CMP_NODE_COLORCORRECTION, "Color Correction", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_colorcorrection_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_colorcorrection;
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_colorcorrection_ex;
node_type_size(&ntype, 400, 200, 600);
- node_type_init(&ntype, node_composit_init_colorcorrection);
+ node_type_init(&ntype, file_ns::node_composit_init_colorcorrection);
node_type_storage(
&ntype, "NodeColorCorrection", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_common.cc b/source/blender/nodes/composite/nodes/node_composite_common.cc
index aa81cecc3e2..d5f7279398e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_common.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_common.cc
@@ -38,7 +38,7 @@ void register_node_type_cmp_group()
/* NOTE: Cannot use sh_node_type_base for node group, because it would map the node type
* to the shared NODE_GROUP integer type id. */
- node_type_base_custom(&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, 0);
+ node_type_base_custom(&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP);
ntype.type = NODE_GROUP;
ntype.poll = cmp_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
@@ -47,7 +47,6 @@ void register_node_type_cmp_group()
BLI_assert(ntype.rna_ext.srna != nullptr);
RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
- node_type_socket_templates(&ntype, nullptr, nullptr);
node_type_size(&ntype, 140, 60, 400);
ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc
index d4558d717e8..b3b0e5bf432 100644
--- a/source/blender/nodes/composite/nodes/node_composite_composite.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** COMPOSITE ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_composite_cc {
static void cmp_node_composite_declare(NodeDeclarationBuilder &b)
{
@@ -34,15 +37,23 @@ static void cmp_node_composite_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.0f).max(1.0f);
}
-} // namespace blender::nodes
+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);
+}
+
+} // namespace blender::nodes::node_composite_composite_cc
void register_node_type_cmp_composite()
{
- static bNodeType ntype;
+ namespace file_ns = blender::nodes::node_composite_composite_cc;
- cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_composite_declare;
+ static bNodeType ntype;
+ cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::cmp_node_composite_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_composite;
+ ntype.flag |= NODE_PREVIEW;
ntype.no_muting = true;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc b/source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc
new file mode 100644
index 00000000000..75af21ab9a2
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.hh"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "IMB_colormanagement.h"
+
+namespace blender::nodes::node_composite_convert_color_space_cc {
+
+static void CMP_NODE_CONVERT_COLOR_SPACE_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 void node_composit_init_convert_colorspace(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeConvertColorSpace *ncs = static_cast<NodeConvertColorSpace *>(
+ MEM_callocN(sizeof(NodeConvertColorSpace), "node colorspace"));
+ const char *first_colorspace = IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_SCENE_LINEAR);
+ if (first_colorspace && first_colorspace[0]) {
+ STRNCPY(ncs->from_color_space, first_colorspace);
+ STRNCPY(ncs->to_color_space, first_colorspace);
+ }
+ else {
+ ncs->from_color_space[0] = 0;
+ ncs->to_color_space[0] = 0;
+ }
+ node->storage = ncs;
+}
+
+static void node_composit_buts_convert_colorspace(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "from_color_space", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "to_color_space", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_composite_convert_color_space_cc
+
+void register_node_type_cmp_convert_color_space(void)
+{
+ namespace file_ns = blender::nodes::node_composite_convert_color_space_cc;
+ static bNodeType ntype;
+
+ cmp_node_type_base(
+ &ntype, CMP_NODE_CONVERT_COLOR_SPACE, "Convert Colorspace", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::CMP_NODE_CONVERT_COLOR_SPACE_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_convert_colorspace;
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_init(&ntype, file_ns::node_composit_init_convert_colorspace);
+ node_type_storage(
+ &ntype, "NodeConvertColorSpace", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
index 2e7a87a576d..e4abc8106e2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
@@ -23,7 +23,7 @@
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_cornerpin_cc {
static void cmp_node_cornerpin_declare(NodeDeclarationBuilder &b)
{
@@ -48,14 +48,16 @@ static void cmp_node_cornerpin_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Plane"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_cornerpin_cc
void register_node_type_cmp_cornerpin()
{
+ namespace file_ns = blender::nodes::node_composite_cornerpin_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_cornerpin_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::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 73c4eb85259..e14b7d04ea6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_crop.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_crop.cc
@@ -21,11 +21,16 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Crop ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_crop_cc {
static void cmp_node_crop_declare(NodeDeclarationBuilder &b)
{
@@ -33,11 +38,9 @@ static void cmp_node_crop_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTwoXYs *nxy = (NodeTwoXYs *)MEM_callocN(sizeof(NodeTwoXYs), "node xy data");
+ NodeTwoXYs *nxy = MEM_cnew<NodeTwoXYs>(__func__);
node->storage = nxy;
nxy->x1 = 0;
nxy->x2 = 0;
@@ -45,13 +48,40 @@ static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node)
nxy->y2 = 0;
}
+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);
+ }
+}
+
+} // namespace blender::nodes::node_composite_crop_cc
+
void register_node_type_cmp_crop()
{
+ namespace file_ns = blender::nodes::node_composite_crop_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_crop_declare;
- node_type_init(&ntype, node_composit_init_crop);
+ cmp_node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_crop_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_crop;
+ node_type_init(&ntype, file_ns::node_composit_init_crop);
node_type_storage(&ntype, "NodeTwoXYs", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
index 65b1f6799d7..40b467d608a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -136,8 +136,7 @@ static void cryptomatte_add(const Scene &scene,
return;
}
- CryptomatteEntry *entry = static_cast<CryptomatteEntry *>(
- MEM_callocN(sizeof(CryptomatteEntry), __func__));
+ CryptomatteEntry *entry = MEM_cnew<CryptomatteEntry>(__func__);
entry->encoded_hash = encoded_hash;
blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
scene, node, true);
@@ -158,16 +157,6 @@ static void cryptomatte_remove(NodeCryptomatte &n, float encoded_hash)
MEM_freeN(entry);
}
-static bNodeSocketTemplate cmp_node_cryptomatte_in[] = {
- {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f}, {-1, ""}};
-
-static bNodeSocketTemplate cmp_node_cryptomatte_out[] = {
- {SOCK_RGBA, N_("Image")},
- {SOCK_FLOAT, N_("Matte")},
- {SOCK_RGBA, N_("Pick")},
- {-1, ""},
-};
-
void ntreeCompositCryptomatteSyncFromAdd(const Scene *scene, bNode *node)
{
BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
@@ -199,8 +188,7 @@ void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node)
if (session) {
for (blender::StringRef layer_name :
blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) {
- CryptomatteLayer *layer = static_cast<CryptomatteLayer *>(
- MEM_callocN(sizeof(CryptomatteLayer), __func__));
+ CryptomatteLayer *layer = MEM_cnew<CryptomatteLayer>(__func__);
layer_name.copy(layer->name);
BLI_addtail(&n->runtime.layers, layer);
}
@@ -243,10 +231,21 @@ CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *n
return session_ptr.release();
}
+namespace blender::nodes::node_composite_cryptomatte_cc {
+
+static bNodeSocketTemplate cmp_node_cryptomatte_in[] = {
+ {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f}, {-1, ""}};
+
+static bNodeSocketTemplate cmp_node_cryptomatte_out[] = {
+ {SOCK_RGBA, N_("Image")},
+ {SOCK_FLOAT, N_("Matte")},
+ {SOCK_RGBA, N_("Pick")},
+ {-1, ""},
+};
+
static void node_init_cryptomatte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeCryptomatte *user = static_cast<NodeCryptomatte *>(
- MEM_callocN(sizeof(NodeCryptomatte), __func__));
+ NodeCryptomatte *user = MEM_cnew<NodeCryptomatte>(__func__);
node->storage = user;
}
@@ -308,17 +307,23 @@ static bool node_poll_cryptomatte(bNodeType *UNUSED(ntype),
return false;
}
+} // namespace blender::nodes::node_composite_cryptomatte_cc
+
void register_node_type_cmp_cryptomatte()
{
+ namespace file_ns = blender::nodes::node_composite_cryptomatte_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, cmp_node_cryptomatte_in, cmp_node_cryptomatte_out);
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE);
+ node_type_socket_templates(
+ &ntype, file_ns::cmp_node_cryptomatte_in, file_ns::cmp_node_cryptomatte_out);
node_type_size(&ntype, 240, 100, 700);
- node_type_init(&ntype, node_init_cryptomatte);
- ntype.initfunc_api = node_init_api_cryptomatte;
- ntype.poll = node_poll_cryptomatte;
- node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
+ node_type_init(&ntype, file_ns::node_init_cryptomatte);
+ ntype.initfunc_api = file_ns::node_init_api_cryptomatte;
+ ntype.poll = file_ns::node_poll_cryptomatte;
+ node_type_storage(
+ &ntype, "NodeCryptomatte", file_ns::node_free_cryptomatte, file_ns::node_copy_cryptomatte);
nodeRegisterType(&ntype);
}
@@ -328,18 +333,6 @@ void register_node_type_cmp_cryptomatte()
/** \name Cryptomatte Legacy
* \{ */
-static void node_init_cryptomatte_legacy(bNodeTree *ntree, bNode *node)
-{
- node_init_cryptomatte(ntree, node);
-
- nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
-
- /* Add three inputs by default, as recommended by the Cryptomatte specification. */
- ntreeCompositCryptomatteAddSocket(ntree, node);
- ntreeCompositCryptomatteAddSocket(ntree, node);
- ntreeCompositCryptomatteAddSocket(ntree, node);
-}
-
bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
{
BLI_assert(node->type == CMP_NODE_CRYPTOMATTE_LEGACY);
@@ -365,14 +358,35 @@ int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
return 1;
}
+namespace blender::nodes::node_composite_cryptomatte_cc {
+
+static void node_init_cryptomatte_legacy(bNodeTree *ntree, bNode *node)
+{
+ namespace file_ns = blender::nodes::node_composite_cryptomatte_cc;
+ file_ns::node_init_cryptomatte(ntree, node);
+
+ nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
+
+ /* Add three inputs by default, as recommended by the Cryptomatte specification. */
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+}
+
+} // namespace blender::nodes::node_composite_cryptomatte_cc
+
void register_node_type_cmp_cryptomatte_legacy()
{
+ namespace legacy_file_ns = blender::nodes::node_composite_cryptomatte_cc;
+ namespace file_ns = blender::nodes::node_composite_cryptomatte_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE, 0);
- node_type_socket_templates(&ntype, nullptr, cmp_node_cryptomatte_out);
- node_type_init(&ntype, node_init_cryptomatte_legacy);
- node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE);
+ node_type_socket_templates(&ntype, nullptr, file_ns::cmp_node_cryptomatte_out);
+ node_type_init(&ntype, file_ns::node_init_cryptomatte_legacy);
+ node_type_storage(
+ &ntype, "NodeCryptomatte", file_ns::node_free_cryptomatte, file_ns::node_copy_cryptomatte);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.cc b/source/blender/nodes/composite/nodes/node_composite_curves.cc
index 53d721ce616..12390a8549d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_curves.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc
@@ -21,19 +21,20 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** CURVE Time ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_curves_cc {
static void cmp_node_time_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Fac"));
}
-} // namespace blender::nodes
-
/* custom1 = start_frame, custom2 = end_frame */
static void node_composit_init_curves_time(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -42,14 +43,18 @@ 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);
}
+} // namespace blender::nodes::node_composite_curves_cc
+
void register_node_type_cmp_curve_time()
{
+ namespace file_ns = blender::nodes::node_composite_curves_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TIME, "Time", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::cmp_node_time_declare;
- node_type_size(&ntype, 140, 100, 320);
- node_type_init(&ntype, node_composit_init_curves_time);
+ cmp_node_type_base(&ntype, CMP_NODE_TIME, "Time Curve", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_time_declare;
+ node_type_size(&ntype, 200, 140, 320);
+ node_type_init(&ntype, file_ns::node_composit_init_curves_time);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
nodeRegisterType(&ntype);
@@ -57,7 +62,7 @@ void register_node_type_cmp_curve_time()
/* **************** CURVE VEC ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_curves_cc {
static void cmp_node_curve_vec_declare(NodeDeclarationBuilder &b)
{
@@ -65,21 +70,29 @@ static void cmp_node_curve_vec_declare(NodeDeclarationBuilder &b)
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);
}
+static void node_buts_curvevec(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false, false);
+}
+
+} // namespace blender::nodes::node_composite_curves_cc
+
void register_node_type_cmp_curve_vec()
{
+ namespace file_ns = blender::nodes::node_composite_curves_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::cmp_node_curve_vec_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::cmp_node_curve_vec_declare;
+ ntype.draw_buttons = file_ns::node_buts_curvevec;
node_type_size(&ntype, 200, 140, 320);
- node_type_init(&ntype, node_composit_init_curve_vec);
+ node_type_init(&ntype, file_ns::node_composit_init_curve_vec);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
nodeRegisterType(&ntype);
@@ -87,7 +100,7 @@ void register_node_type_cmp_curve_vec()
/* **************** CURVE RGB ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_curves_cc {
static void cmp_node_rgbcurves_declare(NodeDeclarationBuilder &b)
{
@@ -99,21 +112,23 @@ static void cmp_node_rgbcurves_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
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);
}
+} // namespace blender::nodes::node_composite_curves_cc
+
void register_node_type_cmp_curve_rgb()
{
+ namespace file_ns = blender::nodes::node_composite_curves_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_rgbcurves_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_rgbcurves_declare;
node_type_size(&ntype, 200, 140, 320);
- node_type_init(&ntype, node_composit_init_curve_rgb);
+ node_type_init(&ntype, file_ns::node_composit_init_curve_rgb);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_defocus.cc b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
index 1d8a02e463c..41200c97b06 100644
--- a/source/blender/nodes/composite/nodes/node_composite_defocus.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
@@ -21,13 +21,18 @@
* \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 ****************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_defocus_cc {
static void cmp_node_defocus_declare(NodeDeclarationBuilder &b)
{
@@ -36,12 +41,10 @@ static void cmp_node_defocus_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node)
{
/* defocus node */
- NodeDefocus *nbd = (NodeDefocus *)MEM_callocN(sizeof(NodeDefocus), "node defocus data");
+ NodeDefocus *nbd = MEM_cnew<NodeDefocus>(__func__);
nbd->bktype = 0;
nbd->rotation = 0.0f;
nbd->preview = 1;
@@ -55,13 +58,57 @@ static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = nbd;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_defocus_cc
+
void register_node_type_cmp_defocus()
{
+ namespace file_ns = blender::nodes::node_composite_defocus_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER, 0);
- ntype.declare = blender::nodes::cmp_node_defocus_declare;
- node_type_init(&ntype, node_composit_init_defocus);
+ cmp_node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_defocus_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_defocus;
+ node_type_init(&ntype, file_ns::node_composit_init_defocus);
node_type_storage(&ntype, "NodeDefocus", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.cc b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
index 2c07dbb3d81..d407bcbde63 100644
--- a/source/blender/nodes/composite/nodes/node_composite_denoise.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
@@ -23,9 +23,14 @@
* \ingroup cmpnodes
*/
+#include "BLI_system.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_denoise_cc {
static void cmp_node_denoise_declare(NodeDeclarationBuilder &b)
{
@@ -39,23 +44,44 @@ static void cmp_node_denoise_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDenoise *ndg = (NodeDenoise *)MEM_callocN(sizeof(NodeDenoise), "node denoise data");
+ NodeDenoise *ndg = MEM_cnew<NodeDenoise>(__func__);
ndg->hdr = true;
ndg->prefilter = CMP_NODE_DENOISE_PREFILTER_ACCURATE;
node->storage = ndg;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_denoise_cc
+
void register_node_type_cmp_denoise()
{
+ namespace file_ns = blender::nodes::node_composite_denoise_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER, 0);
- ntype.declare = blender::nodes::cmp_node_denoise_declare;
- node_type_init(&ntype, node_composit_init_denonise);
+ cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_denoise_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_denoise;
+ node_type_init(&ntype, file_ns::node_composit_init_denonise);
node_type_storage(&ntype, "NodeDenoise", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
index 070c38feaa8..ef9c760622c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** FILTER ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_despeckle_cc {
static void cmp_node_despeckle_declare(NodeDeclarationBuilder &b)
{
@@ -34,21 +37,34 @@ static void cmp_node_despeckle_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_despeckle(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom3 = 0.5f;
node->custom4 = 0.5f;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_despeckle_cc
+
void register_node_type_cmp_despeckle()
{
+ namespace file_ns = blender::nodes::node_composite_despeckle_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DESPECKLE, "Despeckle", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_despeckle_declare;
- node_type_init(&ntype, node_composit_init_despeckle);
+ cmp_node_type_base(&ntype, CMP_NODE_DESPECKLE, "Despeckle", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_despeckle_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_despeckle;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::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_diff_matte.cc
index bfec3dadd09..9b3360c9e7d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* channel Difference Matte ********************************* */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_diff_matte_cc {
static void cmp_node_diff_matte_declare(NodeDeclarationBuilder &b)
{
@@ -35,24 +38,37 @@ static void cmp_node_diff_matte_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Matte"));
}
-} // namespace blender::nodes
-
static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->t1 = 0.1f;
c->t2 = 0.1f;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_diff_matte_cc
+
void register_node_type_cmp_diff_matte()
{
+ namespace file_ns = blender::nodes::node_composite_diff_matte_cc;
+
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_diff_matte_declare;
- node_type_init(&ntype, node_composit_init_diff_matte);
+ cmp_node_type_base(&ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_diff_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_diff_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_diff_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.cc b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
index 14e618435d1..efd06ce8fd4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_dilate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
@@ -21,11 +21,16 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Dilate/Erode ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_dilate_cc {
static void cmp_node_dilate_declare(NodeDeclarationBuilder &b)
{
@@ -33,23 +38,39 @@ static void cmp_node_dilate_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Mask"));
}
-} // namespace blender::nodes
-
static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDilateErode *data = (NodeDilateErode *)MEM_callocN(sizeof(NodeDilateErode),
- "NodeDilateErode");
+ NodeDilateErode *data = MEM_cnew<NodeDilateErode>(__func__);
data->falloff = PROP_SMOOTH;
node->storage = data;
}
+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;
+ }
+}
+
+} // namespace blender::nodes::node_composite_dilate_cc
+
void register_node_type_cmp_dilateerode()
{
+ namespace file_ns = blender::nodes::node_composite_dilate_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER, 0);
- ntype.declare = blender::nodes::cmp_node_dilate_declare;
- node_type_init(&ntype, node_composit_init_dilateerode);
+ cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER);
+ ntype.draw_buttons = file_ns::node_composit_buts_dilateerode;
+ ntype.declare = file_ns::cmp_node_dilate_declare;
+ node_type_init(&ntype, file_ns::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 cbc2484ceb8..2215e62659b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
@@ -21,9 +21,12 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_directionalblur_cc {
static void cmp_node_directional_blur_declare(NodeDeclarationBuilder &b)
{
@@ -31,24 +34,51 @@ static void cmp_node_directional_blur_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDBlurData *ndbd = (NodeDBlurData *)MEM_callocN(sizeof(NodeDBlurData), "node dblur data");
+ NodeDBlurData *ndbd = MEM_cnew<NodeDBlurData>(__func__);
node->storage = ndbd;
ndbd->iter = 1;
ndbd->center_x = 0.5;
ndbd->center_y = 0.5;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_directionalblur_cc
+
void register_node_type_cmp_dblur()
{
+ namespace file_ns = blender::nodes::node_composite_directionalblur_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER, 0);
- ntype.declare = blender::nodes::cmp_node_directional_blur_declare;
- node_type_init(&ntype, node_composit_init_dblur);
+ cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_directional_blur_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_dblur;
+ node_type_init(&ntype, file_ns::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 0137c1f7da8..819680e1967 100644
--- a/source/blender/nodes/composite/nodes/node_composite_displace.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_displace.cc
@@ -25,7 +25,7 @@
/* **************** Displace ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_displace_cc {
static void cmp_node_displace_declare(NodeDeclarationBuilder &b)
{
@@ -40,14 +40,16 @@ static void cmp_node_displace_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_displace_cc
void register_node_type_cmp_displace()
{
+ namespace file_ns = blender::nodes::node_composite_displace_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_displace_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::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_distance_matte.cc
index 302170081bb..82781588c9d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_distance_matte.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* channel Distance Matte ********************************* */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_distance_matte_cc {
static void cmp_node_distance_matte_declare(NodeDeclarationBuilder &b)
{
@@ -35,24 +38,45 @@ static void cmp_node_distance_matte_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Matte"));
}
-} // namespace blender::nodes
-
static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->channel = 1;
c->t1 = 0.1f;
c->t2 = 0.1f;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_distance_matte_cc
+
void register_node_type_cmp_distance_matte()
{
+ namespace file_ns = blender::nodes::node_composite_distance_matte_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_distance_matte_declare;
- node_type_init(&ntype, node_composit_init_distance_matte);
+ cmp_node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_distance_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_distance_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_distance_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc b/source/blender/nodes/composite/nodes/node_composite_double_edge_mask.cc
index ce4532366a3..959d4ecf69e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_double_edge_mask.cc
@@ -20,11 +20,15 @@
/** \file
* \ingroup cmpnodes
*/
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Double Edge Mask ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_double_edge_mask_cc {
static void cmp_node_double_edge_mask_declare(NodeDeclarationBuilder &b)
{
@@ -33,14 +37,31 @@ static void cmp_node_double_edge_mask_declare(NodeDeclarationBuilder &b)
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);
+}
+
+} // namespace blender::nodes::node_composite_double_edge_mask_cc
void register_node_type_cmp_doubleedgemask()
{
+ namespace file_ns = blender::nodes::node_composite_double_edge_mask_cc;
+
static bNodeType ntype; /* Allocate a node type data structure. */
- cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE, 0);
- ntype.declare = blender::nodes::cmp_node_double_edge_mask_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_double_edge_mask_declare;
+ ntype.draw_buttons = file_ns::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 5f49357107c..b2be8abf0cd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_ellipsemask_cc {
static void cmp_node_ellipsemask_declare(NodeDeclarationBuilder &b)
{
@@ -34,12 +37,9 @@ static void cmp_node_ellipsemask_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Mask"));
}
-} // namespace blender::nodes
-
static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeEllipseMask *data = (NodeEllipseMask *)MEM_callocN(sizeof(NodeEllipseMask),
- "NodeEllipseMask");
+ NodeEllipseMask *data = MEM_cnew<NodeEllipseMask>(__func__);
data->x = 0.5;
data->y = 0.5;
data->width = 0.2;
@@ -48,14 +48,33 @@ static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node
node->storage = data;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_ellipsemask_cc
+
void register_node_type_cmp_ellipsemask()
{
+ namespace file_ns = blender::nodes::node_composite_ellipsemask_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MASK_ELLIPSE, "Ellipse Mask", NODE_CLASS_MATTE, 0);
- ntype.declare = blender::nodes::cmp_node_ellipsemask_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_MASK_ELLIPSE, "Ellipse Mask", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_ellipsemask_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_ellipsemask;
node_type_size(&ntype, 260, 110, 320);
- node_type_init(&ntype, node_composit_init_ellipsemask);
+ node_type_init(&ntype, file_ns::node_composit_init_ellipsemask);
node_type_storage(
&ntype, "NodeEllipseMask", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_exposure.cc b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
index b696db41a3c..2798f4a46e8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_exposure.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
@@ -25,7 +25,7 @@
/* **************** Exposure ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_exposure_cc {
static void cmp_node_exposure_declare(NodeDeclarationBuilder &b)
{
@@ -34,14 +34,16 @@ static void cmp_node_exposure_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_exposure_cc
void register_node_type_cmp_exposure()
{
+ namespace file_ns = blender::nodes::node_composite_exposure_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_EXPOSURE, "Exposure", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_exposure_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_EXPOSURE, "Exposure", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_exposure_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_filter.cc b/source/blender/nodes/composite/nodes/node_composite_filter.cc
index 4258bd977e0..cd51e0d3c85 100644
--- a/source/blender/nodes/composite/nodes/node_composite_filter.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_filter.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** FILTER ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_filter_cc {
static void cmp_node_filter_declare(NodeDeclarationBuilder &b)
{
@@ -34,15 +37,24 @@ static void cmp_node_filter_declare(NodeDeclarationBuilder &b)
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);
+}
+
+} // namespace blender::nodes::node_composite_filter_cc
void register_node_type_cmp_filter()
{
+ namespace file_ns = blender::nodes::node_composite_filter_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_filter_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_filter_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_filter;
ntype.labelfunc = node_filter_label;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_flip.cc b/source/blender/nodes/composite/nodes/node_composite_flip.cc
index 95a00dd58da..dba98a42e93 100644
--- a/source/blender/nodes/composite/nodes/node_composite_flip.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_flip.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Flip ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_flip_cc {
static void cmp_node_flip_declare(NodeDeclarationBuilder &b)
{
@@ -33,14 +36,22 @@ static void cmp_node_flip_declare(NodeDeclarationBuilder &b)
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);
+}
+
+} // namespace blender::nodes::node_composite_flip_cc
void register_node_type_cmp_flip()
{
+ namespace file_ns = blender::nodes::node_composite_flip_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_flip_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_flip_declare;
+ ntype.draw_buttons = file_ns::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 438770865ae..aafd558f0df 100644
--- a/source/blender/nodes/composite/nodes/node_composite_gamma.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
@@ -25,7 +25,7 @@
/* **************** Gamma Tools ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_gamma_cc {
static void cmp_node_gamma_declare(NodeDeclarationBuilder &b)
{
@@ -38,14 +38,16 @@ static void cmp_node_gamma_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_gamma_cc
void register_node_type_cmp_gamma()
{
+ namespace file_ns = blender::nodes::node_composite_gamma_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_gamma_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_gamma_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.cc b/source/blender/nodes/composite/nodes/node_composite_glare.cc
index d3a5fff0b68..479eeef3808 100644
--- a/source/blender/nodes/composite/nodes/node_composite_glare.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_glare.cc
@@ -21,9 +21,14 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_glare_cc {
static void cmp_node_glare_declare(NodeDeclarationBuilder &b)
{
@@ -31,11 +36,9 @@ static void cmp_node_glare_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGlare *ndg = (NodeGlare *)MEM_callocN(sizeof(NodeGlare), "node glare data");
+ NodeGlare *ndg = MEM_cnew<NodeGlare>(__func__);
ndg->quality = 1;
ndg->type = 2;
ndg->iter = 3;
@@ -50,13 +53,56 @@ static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = ndg;
}
+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);
+ }
+}
+
+} // namespace blender::nodes::node_composite_glare_cc
+
void register_node_type_cmp_glare()
{
+ namespace file_ns = blender::nodes::node_composite_glare_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER, 0);
- ntype.declare = blender::nodes::cmp_node_glare_declare;
- node_type_init(&ntype, node_composit_init_glare);
+ cmp_node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_glare_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_glare;
+ node_type_init(&ntype, file_ns::node_composit_init_glare);
node_type_storage(&ntype, "NodeGlare", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc b/source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc
index 47fbaa4d384..c98cfcdba02 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_hue_sat_val.cc
@@ -25,7 +25,7 @@
/* **************** Hue Saturation ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_hue_sat_val_cc {
static void cmp_node_huesatval_declare(NodeDeclarationBuilder &b)
{
@@ -45,14 +45,16 @@ static void cmp_node_huesatval_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_hue_sat_val_cc
void register_node_type_cmp_hue_sat()
{
+ namespace file_ns = blender::nodes::node_composite_hue_sat_val_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_huesatval_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_huesatval_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
index e78ba0c7f9c..347c1588af3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
@@ -23,7 +23,7 @@
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_huecorrect_cc {
static void cmp_node_huecorrect_declare(NodeDeclarationBuilder &b)
{
@@ -32,8 +32,6 @@ static void cmp_node_huecorrect_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
@@ -51,14 +49,18 @@ static void node_composit_init_huecorrect(bNodeTree *UNUSED(ntree), bNode *node)
cumapping->cur = 1;
}
+} // namespace blender::nodes::node_composite_huecorrect_cc
+
void register_node_type_cmp_huecorrect()
{
+ namespace file_ns = blender::nodes::node_composite_huecorrect_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_HUECORRECT, "Hue Correct", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_huecorrect_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_HUECORRECT, "Hue Correct", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_huecorrect_declare;
node_type_size(&ntype, 320, 140, 500);
- node_type_init(&ntype, node_composit_init_huecorrect);
+ node_type_init(&ntype, file_ns::node_composit_init_huecorrect);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_idMask.cc b/source/blender/nodes/composite/nodes/node_composite_id_mask.cc
index be7d4e22aba..4b7674286dd 100644
--- a/source/blender/nodes/composite/nodes/node_composite_idMask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_id_mask.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** ID Mask ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_id_mask_cc {
static void cmp_node_idmask_declare(NodeDeclarationBuilder &b)
{
@@ -33,14 +36,23 @@ static void cmp_node_idmask_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Alpha"));
}
-} // namespace blender::nodes
+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);
+}
+
+} // namespace blender::nodes::node_composite_id_mask_cc
void register_node_type_cmp_idmask()
{
+ namespace file_ns = blender::nodes::node_composite_id_mask_cc;
+
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;
+ cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_idmask_declare;
+ ntype.draw_buttons = file_ns::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 18f919edbe9..f2b9fbc2215 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[] = {
@@ -103,8 +108,7 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree,
sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, name, name);
}
/* extra socket info */
- NodeImageLayer *sockdata = (NodeImageLayer *)MEM_callocN(sizeof(NodeImageLayer),
- "node image layer");
+ NodeImageLayer *sockdata = MEM_cnew<NodeImageLayer>(__func__);
sock->storage = sockdata;
}
@@ -265,7 +269,12 @@ void node_cmp_rlayers_register_pass(bNodeTree *ntree,
}
}
-static void cmp_node_rlayer_create_outputs_cb(void *UNUSED(userdata),
+struct CreateOutputUserData {
+ bNodeTree &ntree;
+ bNode &node;
+};
+
+static void cmp_node_rlayer_create_outputs_cb(void *userdata,
Scene *scene,
ViewLayer *view_layer,
const char *name,
@@ -273,18 +282,8 @@ static void cmp_node_rlayer_create_outputs_cb(void *UNUSED(userdata),
const char *UNUSED(chanid),
eNodeSocketDatatype type)
{
- /* Register the pass in all scenes that have a render layer node for this layer.
- * Since multiple scenes can be used in the compositor, the code must loop over all scenes
- * and check whether their nodetree has a node that needs to be updated. */
- /* NOTE: using G_MAIN seems valid here,
- * unless we want to register that for every other temp Main we could generate??? */
- ntreeCompositRegisterPass(scene->nodetree, scene, view_layer, name, type);
-
- for (Scene *sce = (Scene *)G_MAIN->scenes.first; sce; sce = (Scene *)sce->id.next) {
- if (sce->nodetree && sce != scene) {
- ntreeCompositRegisterPass(sce->nodetree, scene, view_layer, name, type);
- }
- }
+ CreateOutputUserData &data = *(CreateOutputUserData *)userdata;
+ node_cmp_rlayers_register_pass(&data.ntree, &data.node, scene, view_layer, name, type);
}
static void cmp_node_rlayer_create_outputs(bNodeTree *ntree,
@@ -304,14 +303,17 @@ static void cmp_node_rlayer_create_outputs(bNodeTree *ntree,
data->prev_index = -1;
node->storage = data;
+ CreateOutputUserData userdata = {*ntree, *node};
+
RenderEngine *engine = RE_engine_create(engine_type);
RE_engine_update_render_passes(
- engine, scene, view_layer, cmp_node_rlayer_create_outputs_cb, nullptr);
+ engine, scene, view_layer, cmp_node_rlayer_create_outputs_cb, &userdata);
RE_engine_free(engine);
if ((scene->r.mode & R_EDGE_FRS) &&
(view_layer->freestyle_config.flags & FREESTYLE_AS_RENDER_PASS)) {
- ntreeCompositRegisterPass(ntree, scene, view_layer, RE_PASSNAME_FREESTYLE, SOCK_RGBA);
+ node_cmp_rlayers_register_pass(
+ ntree, node, scene, view_layer, RE_PASSNAME_FREESTYLE, SOCK_RGBA);
}
MEM_freeN(data);
@@ -395,6 +397,8 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl
BLI_linklist_free(available_sockets.list, nullptr);
}
+namespace blender::nodes::node_composite_image_cc {
+
static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
{
/* avoid unnecessary updates, only changes to the image/image user data are of interest */
@@ -407,7 +411,7 @@ static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
static void node_composit_init_image(bNodeTree *ntree, bNode *node)
{
- ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = MEM_cnew<ImageUser>(__func__);
node->storage = iuser;
iuser->frames = 1;
iuser->sfra = 1;
@@ -443,15 +447,21 @@ static void node_composit_copy_image(bNodeTree *UNUSED(dest_ntree),
}
}
+} // namespace blender::nodes::node_composite_image_cc
+
void register_node_type_cmp_image()
{
+ namespace file_ns = blender::nodes::node_composite_image_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW);
- 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);
+ cmp_node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT);
+ node_type_init(&ntype, file_ns::node_composit_init_image);
+ node_type_storage(
+ &ntype, "ImageUser", file_ns::node_composit_free_image, file_ns::node_composit_copy_image);
+ node_type_update(&ntype, file_ns::cmp_node_image_update);
ntype.labelfunc = node_image_label;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
@@ -473,6 +483,8 @@ const char *node_cmp_rlayers_sock_to_pass(int sock_index)
return (STREQ(name, "Alpha")) ? RE_PASSNAME_COMBINED : name;
}
+namespace blender::nodes::node_composite_image_cc {
+
static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
@@ -484,8 +496,7 @@ static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
for (bNodeSocket *sock = (bNodeSocket *)node->outputs.first; sock;
sock = sock->next, sock_index++) {
- NodeImageLayer *sockdata = (NodeImageLayer *)MEM_callocN(sizeof(NodeImageLayer),
- "node image layer");
+ NodeImageLayer *sockdata = MEM_cnew<NodeImageLayer>(__func__);
sock->storage = sockdata;
BLI_strncpy(sockdata->pass_name,
@@ -555,16 +566,66 @@ static void cmp_node_rlayers_update(bNodeTree *ntree, bNode *node)
cmp_node_update_default(ntree, node);
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_image_cc
+
void register_node_type_cmp_rlayers()
{
+ namespace file_ns = blender::nodes::node_composite_image_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, nullptr, cmp_node_rlayers_out);
- ntype.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);
- node_type_update(&ntype, cmp_node_rlayers_update);
+ ntype.draw_buttons = file_ns::node_composit_buts_viewlayers;
+ ntype.initfunc_api = file_ns::node_composit_init_rlayers;
+ ntype.poll = file_ns::node_composit_poll_rlayers;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_storage(
+ &ntype, nullptr, file_ns::node_composit_free_rlayers, file_ns::node_composit_copy_rlayers);
+ node_type_update(&ntype, file_ns::cmp_node_rlayers_update);
node_type_init(&ntype, node_cmp_rlayers_outputs);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
diff --git a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
index c7674263b68..f470038ad39 100644
--- a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Inpaint/ ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_inpaint_cc {
static void cmp_node_inpaint_declare(NodeDeclarationBuilder &b)
{
@@ -33,14 +36,22 @@ static void cmp_node_inpaint_declare(NodeDeclarationBuilder &b)
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);
+}
+
+} // namespace blender::nodes::node_composite_inpaint_cc
void register_node_type_cmp_inpaint()
{
+ namespace file_ns = blender::nodes::node_composite_inpaint_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER, 0);
- ntype.declare = blender::nodes::cmp_node_inpaint_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_inpaint_declare;
+ ntype.draw_buttons = file_ns::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 caf28d24b44..c5435f5fb92 100644
--- a/source/blender/nodes/composite/nodes/node_composite_invert.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** INVERT ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_invert_cc {
static void cmp_node_invert_declare(NodeDeclarationBuilder &b)
{
@@ -34,21 +37,32 @@ static void cmp_node_invert_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Color"));
}
-} // namespace blender::nodes
-
static void node_composit_init_invert(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 |= CMP_CHAN_RGB;
}
-/* custom1 = mix type */
+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);
+}
+
+} // namespace blender::nodes::node_composite_invert_cc
+
void register_node_type_cmp_invert()
{
+ namespace file_ns = blender::nodes::node_composite_invert_cc;
+
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;
- node_type_init(&ntype, node_composit_init_invert);
+ cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_invert_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_invert;
+ node_type_init(&ntype, file_ns::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 6286c61b292..26a7297acd5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keying.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_keying.cc
@@ -21,17 +21,20 @@
* \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"
/* **************** Keying ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_keying_cc {
static void cmp_node_keying_declare(NodeDeclarationBuilder &b)
{
@@ -44,11 +47,9 @@ static void cmp_node_keying_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Edges"));
}
-} // namespace blender::nodes
-
static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeKeyingData *data = (NodeKeyingData *)MEM_callocN(sizeof(NodeKeyingData), "node keying data");
+ NodeKeyingData *data = MEM_cnew<NodeKeyingData>(__func__);
data->screen_balance = 0.5f;
data->despill_balance = 0.5f;
@@ -60,13 +61,36 @@ static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = 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", 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);
+}
+
+} // namespace blender::nodes::node_composite_keying_cc
+
void register_node_type_cmp_keying()
{
+ namespace file_ns = blender::nodes::node_composite_keying_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_KEYING, "Keying", NODE_CLASS_MATTE, 0);
- ntype.declare = blender::nodes::cmp_node_keying_declare;
- node_type_init(&ntype, node_composit_init_keying);
+ cmp_node_type_base(&ntype, CMP_NODE_KEYING, "Keying", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_keying_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_keying;
+ node_type_init(&ntype, file_ns::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 f0423497bed..4862fcaa2e0 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
@@ -26,33 +26,67 @@
#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"
/* **************** Keying Screen ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_keyingscreen_cc {
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)
{
- NodeKeyingScreenData *data = (NodeKeyingScreenData *)MEM_callocN(sizeof(NodeKeyingScreenData),
- "node keyingscreen data");
+ NodeKeyingScreenData *data = MEM_cnew<NodeKeyingScreenData>(__func__);
node->storage = data;
}
+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);
+ }
+}
+
+} // namespace blender::nodes::node_composite_keyingscreen_cc
+
void register_node_type_cmp_keyingscreen()
{
+ namespace file_ns = blender::nodes::node_composite_keyingscreen_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE, 0);
- ntype.declare = blender::nodes::cmp_node_keyingscreen_declare;
- node_type_init(&ntype, node_composit_init_keyingscreen);
+ cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_keyingscreen_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_keyingscreen;
+ node_type_init(&ntype, file_ns::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 bd52328db0f..2d85e53016d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
@@ -21,9 +21,14 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_lensdist_cc {
static void cmp_node_lensdist_declare(NodeDeclarationBuilder &b)
{
@@ -33,22 +38,38 @@ static void cmp_node_lensdist_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeLensDist *nld = (NodeLensDist *)MEM_callocN(sizeof(NodeLensDist), "node lensdist data");
+ NodeLensDist *nld = MEM_cnew<NodeLensDist>(__func__);
nld->jit = nld->proj = nld->fit = 0;
node->storage = nld;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_lensdist_cc
+
void register_node_type_cmp_lensdist()
{
+ namespace file_ns = blender::nodes::node_composite_lensdist_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_lensdist_declare;
- node_type_init(&ntype, node_composit_init_lensdist);
+ cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_lensdist_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_lensdist;
+ node_type_init(&ntype, file_ns::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 c36e0153991..57202d95cb7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_levels.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_levels.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** LEVELS ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_levels_cc {
static void cmp_node_levels_declare(NodeDeclarationBuilder &b)
{
@@ -34,20 +37,29 @@ static void cmp_node_levels_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Std Dev"));
}
-} // namespace blender::nodes
-
static void node_composit_init_view_levels(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1; /* All channels. */
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_levels_cc
+
void register_node_type_cmp_view_levels()
{
+ namespace file_ns = blender::nodes::node_composite_levels_cc;
+
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;
- node_type_init(&ntype, node_composit_init_view_levels);
+ cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::cmp_node_levels_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_view_levels;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::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_luma_matte.cc
index c951dfbcf37..851b218b617 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_luma_matte.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* ******************* Luma Matte Node ********************************* */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_luma_matte_cc {
static void cmp_node_luma_matte_declare(NodeDeclarationBuilder &b)
{
@@ -34,23 +37,38 @@ static void cmp_node_luma_matte_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Matte"));
}
-} // namespace blender::nodes
-
static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->t1 = 1.0f;
c->t2 = 0.0f;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_luma_matte_cc
+
void register_node_type_cmp_luma_matte()
{
+ namespace file_ns = blender::nodes::node_composite_luma_matte_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_luma_matte_declare;
- node_type_init(&ntype, node_composit_init_luma_matte);
+ cmp_node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE);
+ ntype.declare = file_ns::cmp_node_luma_matte_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_luma_matte;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_luma_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc b/source/blender/nodes/composite/nodes/node_composite_map_range.cc
index 8eefc9beb18..93622236c73 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_map_range.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Map Range ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_map_range_cc {
static void cmp_node_map_range_declare(NodeDeclarationBuilder &b)
{
@@ -37,14 +40,25 @@ static void cmp_node_map_range_declare(NodeDeclarationBuilder &b)
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);
+}
+
+} // namespace blender::nodes::node_composite_map_range_cc
void register_node_type_cmp_map_range()
{
+ namespace file_ns = blender::nodes::node_composite_map_range_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MAP_RANGE, "Map Range", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::cmp_node_map_range_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_MAP_RANGE, "Map Range", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::cmp_node_map_range_declare;
+ ntype.draw_buttons = file_ns::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_map_uv.cc
index 80e4db4bdf0..92573a362e4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_map_uv.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Map UV ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_map_uv_cc {
static void cmp_node_map_uv_declare(NodeDeclarationBuilder &b)
{
@@ -34,14 +37,22 @@ static void cmp_node_map_uv_declare(NodeDeclarationBuilder &b)
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);
+}
+
+} // namespace blender::nodes::node_composite_map_uv_cc
void register_node_type_cmp_mapuv()
{
+ namespace file_ns = blender::nodes::node_composite_map_uv_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_map_uv_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_map_uv_declare;
+ ntype.draw_buttons = file_ns::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_map_value.cc
index 1b34f987168..79f25dcee5f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_map_value.cc
@@ -21,11 +21,16 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** MAP VALUE ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_map_value_cc {
static void cmp_node_map_value_declare(NodeDeclarationBuilder &b)
{
@@ -33,20 +38,44 @@ static void cmp_node_map_value_declare(NodeDeclarationBuilder &b)
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);
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_map_value_cc
+
void register_node_type_cmp_map_value()
{
+ namespace file_ns = blender::nodes::node_composite_map_value_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::cmp_node_map_value_declare;
- node_type_init(&ntype, node_composit_init_map_value);
+ cmp_node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::cmp_node_map_value_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_map_value;
+ node_type_init(&ntype, file_ns::node_composit_init_map_value);
node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.cc b/source/blender/nodes/composite/nodes/node_composite_mask.cc
index a1b76d8a423..b74c7341ce3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mask.cc
@@ -23,22 +23,23 @@
#include "DNA_mask_types.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Mask ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_mask_cc {
static void cmp_node_mask_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Mask"));
}
-} // namespace blender::nodes
-
static void node_composit_init_mask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeMask *data = (NodeMask *)MEM_callocN(sizeof(NodeMask), "NodeMask");
+ NodeMask *data = MEM_cnew<NodeMask>(__func__);
data->size_x = data->size_y = 256;
node->storage = data;
@@ -59,14 +60,49 @@ static void node_mask_label(const bNodeTree *UNUSED(ntree),
}
}
+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);
+ }
+}
+
+} // namespace blender::nodes::node_composite_mask_cc
+
void register_node_type_cmp_mask()
{
+ namespace file_ns = blender::nodes::node_composite_mask_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::cmp_node_mask_declare;
- node_type_init(&ntype, node_composit_init_mask);
- ntype.labelfunc = node_mask_label;
+ cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_mask_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_mask;
+ node_type_init(&ntype, file_ns::node_composit_init_mask);
+ ntype.labelfunc = file_ns::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 b34cfab5eb5..1083d85ba7c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_math.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_math.cc
@@ -25,7 +25,7 @@
/* **************** SCALAR MATH ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_math_cc {
static void cmp_node_math_declare(NodeDeclarationBuilder &b)
{
@@ -41,14 +41,16 @@ static void cmp_node_math_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Value"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_math_cc
void register_node_type_cmp_math()
{
+ namespace file_ns = blender::nodes::node_composite_math_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::cmp_node_math_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_math_declare;
ntype.labelfunc = node_math_label;
node_type_update(&ntype, node_math_update);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
index 4432b031ee7..7a10fa599de 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
@@ -25,7 +25,7 @@
/* **************** MIX RGB ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_mixrgb_cc {
static void cmp_node_mixrgb_declare(NodeDeclarationBuilder &b)
{
@@ -35,15 +35,17 @@ static void cmp_node_mixrgb_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_mixrgb_cc
-/* custom1 = mix type */
void register_node_type_cmp_mix_rgb()
{
+ namespace file_ns = blender::nodes::node_composite_mixrgb_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_mixrgb_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR);
+ ntype.flag |= NODE_PREVIEW;
+ ntype.declare = file_ns::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 0d44671897b..f6f00864839 100644
--- a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
@@ -21,12 +21,18 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
-
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "DNA_defaults.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_movieclip_cc {
static void cmp_node_movieclip_declare(NodeDeclarationBuilder &b)
{
@@ -38,14 +44,11 @@ static void cmp_node_movieclip_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Angle"));
}
-} // namespace blender::nodes
-
static void init(const bContext *C, PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
Scene *scene = CTX_data_scene(C);
- MovieClipUser *user = (MovieClipUser *)MEM_callocN(sizeof(MovieClipUser),
- "node movie clip user");
+ MovieClipUser *user = DNA_struct_default_alloc(MovieClipUser);
node->id = (ID *)scene->clip;
id_us_plus(node->id);
@@ -53,13 +56,59 @@ static void init(const bContext *C, PointerRNA *ptr)
user->framenr = 1;
}
+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");
+}
+
+} // namespace blender::nodes::node_composite_movieclip_cc
+
void register_node_type_cmp_movieclip()
{
+ namespace file_ns = blender::nodes::node_composite_movieclip_cc;
+
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.initfunc_api = init;
+ cmp_node_type_base(&ntype, CMP_NODE_MOVIECLIP, "Movie Clip", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_movieclip_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_movieclip;
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_movieclip_ex;
+ ntype.initfunc_api = file_ns::init;
+ ntype.flag |= NODE_PREVIEW;
node_type_storage(
&ntype, "MovieClipUser", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
index b859d19c4a4..396c6fa7a13 100644
--- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
@@ -21,14 +21,17 @@
* \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 ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_moviedistortion_cc {
static void cmp_node_moviedistortion_declare(NodeDeclarationBuilder &b)
{
@@ -36,8 +39,6 @@ static void cmp_node_moviedistortion_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void label(const bNodeTree *UNUSED(ntree), const bNode *node, char *label, int maxlen)
{
if (node->custom1 == 0) {
@@ -73,16 +74,42 @@ static void storage_copy(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const
}
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_moviedistortion_cc
+
void register_node_type_cmp_moviedistortion()
{
- static bNodeType ntype;
+ namespace file_ns = blender::nodes::node_composite_moviedistortion_cc;
- cmp_node_type_base(&ntype, CMP_NODE_MOVIEDISTORTION, "Movie Distortion", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_moviedistortion_declare;
- ntype.labelfunc = label;
+ static bNodeType ntype;
- ntype.initfunc_api = init;
- node_type_storage(&ntype, nullptr, storage_free, storage_copy);
+ cmp_node_type_base(&ntype, CMP_NODE_MOVIEDISTORTION, "Movie Distortion", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_moviedistortion_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_moviedistortion;
+ ntype.labelfunc = file_ns::label;
+ ntype.initfunc_api = file_ns::init;
+ node_type_storage(&ntype, nullptr, file_ns::storage_free, file_ns::storage_copy);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.cc b/source/blender/nodes/composite/nodes/node_composite_normal.cc
index b541761a8cc..da44d355966 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normal.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_normal.cc
@@ -25,7 +25,7 @@
/* **************** NORMAL ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_normal_cc {
static void cmp_node_normal_declare(NodeDeclarationBuilder &b)
{
@@ -38,14 +38,16 @@ static void cmp_node_normal_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Dot"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_normal_cc
void register_node_type_cmp_normal()
{
+ namespace file_ns = blender::nodes::node_composite_normal_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::cmp_node_normal_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::cmp_node_normal_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.cc b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
index dd3939fa6e2..3d25187e5e6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normalize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
@@ -25,7 +25,7 @@
/* **************** NORMALIZE single channel, useful for Z buffer ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_normalize_cc {
static void cmp_node_normalize_declare(NodeDeclarationBuilder &b)
{
@@ -33,14 +33,16 @@ static void cmp_node_normalize_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Value"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_normalize_cc
void register_node_type_cmp_normalize()
{
+ namespace file_ns = blender::nodes::node_composite_normalize_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::cmp_node_normalize_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::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_output_file.cc
index 6a1b83f657e..544c8437394 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_output_file.cc
@@ -31,6 +31,11 @@
#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"
@@ -130,8 +135,7 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree,
ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, name);
/* create format data for the input socket */
- NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)MEM_callocN(
- sizeof(NodeImageMultiFileSocket), "socket image format");
+ NodeImageMultiFileSocket *sockdata = MEM_cnew<NodeImageMultiFileSocket>(__func__);
sock->storage = sockdata;
BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path));
@@ -192,14 +196,15 @@ void ntreeCompositOutputFileSetLayer(bNode *node, bNodeSocket *sock, const char
ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_');
}
+namespace blender::nodes::node_composite_output_file_cc {
+
/* XXX uses initfunc_api callback, regular initfunc does not support context yet */
static void init_output_file(const bContext *C, PointerRNA *ptr)
{
Scene *scene = CTX_data_scene(C);
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- NodeImageMultiFile *nimf = (NodeImageMultiFile *)MEM_callocN(sizeof(NodeImageMultiFile),
- "node image multi file");
+ NodeImageMultiFile *nimf = MEM_cnew<NodeImageMultiFile>(__func__);
ImageFormatData *format = nullptr;
node->storage = nimf;
@@ -277,15 +282,177 @@ static void update_output_file(bNodeTree *ntree, bNode *node)
}
}
+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);
+ }
+ }
+ }
+}
+
+} // namespace blender::nodes::node_composite_output_file_cc
+
void register_node_type_cmp_output_file()
{
+ namespace file_ns = blender::nodes::node_composite_output_file_cc;
+
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.initfunc_api = init_output_file;
- node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file);
- node_type_update(&ntype, update_output_file);
+ cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT);
+ ntype.draw_buttons = file_ns::node_composit_buts_file_output;
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_file_output_ex;
+ ntype.initfunc_api = file_ns::init_output_file;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_storage(
+ &ntype, "NodeImageMultiFile", file_ns::free_output_file, file_ns::copy_output_file);
+ node_type_update(&ntype, file_ns::update_output_file);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
index 3679aada759..baded2186d3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
@@ -25,7 +25,7 @@
/* **************** Pixelate ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_pixelate_cc {
static void cmp_node_pixelate_declare(NodeDeclarationBuilder &b)
{
@@ -33,14 +33,16 @@ static void cmp_node_pixelate_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Color"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_pixelate_cc
void register_node_type_cmp_pixelate()
{
+ namespace file_ns = blender::nodes::node_composite_pixelate_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER, 0);
- ntype.declare = blender::nodes::cmp_node_pixelate_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::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 82738d70531..453501b6ab1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
@@ -21,9 +21,14 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_planetrackdeform_cc {
static void cmp_node_planetrackdeform_declare(NodeDeclarationBuilder &b)
{
@@ -32,25 +37,75 @@ static void cmp_node_planetrackdeform_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Plane"));
}
-} // namespace blender::nodes
-
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)MEM_callocN(
- sizeof(NodePlaneTrackDeformData), "node plane track deform data");
+ NodePlaneTrackDeformData *data = MEM_cnew<NodePlaneTrackDeformData>(__func__);
data->motion_blur_samples = 16;
data->motion_blur_shutter = 0.5f;
node->storage = data;
}
+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);
+ }
+}
+
+} // namespace blender::nodes::node_composite_planetrackdeform_cc
+
void register_node_type_cmp_planetrackdeform()
{
+ namespace file_ns = blender::nodes::node_composite_planetrackdeform_cc;
+
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_planetrackdeform_declare;
- node_type_init(&ntype, init);
+ cmp_node_type_base(&ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_planetrackdeform_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_planetrackdeform;
+ node_type_init(&ntype, file_ns::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 8437c72e76c..f05ed3d80b7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_posterize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
@@ -25,7 +25,7 @@
/* **************** Posterize ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_posterize_cc {
static void cmp_node_posterize_declare(NodeDeclarationBuilder &b)
{
@@ -34,14 +34,16 @@ static void cmp_node_posterize_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_posterize_cc
void register_node_type_cmp_posterize()
{
+ namespace file_ns = blender::nodes::node_composite_posterize_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_posterize_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::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 8dec90c875a..aec005ee25a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Premul and Key Alpha Convert ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_premulkey_cc {
static void cmp_node_premulkey_declare(NodeDeclarationBuilder &b)
{
@@ -33,14 +36,22 @@ static void cmp_node_premulkey_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+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);
+}
+
+} // namespace blender::nodes::node_composite_premulkey_cc
void register_node_type_cmp_premulkey()
{
+ namespace file_ns = blender::nodes::node_composite_premulkey_cc;
+
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;
+ cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_premulkey_declare;
+ ntype.draw_buttons = file_ns::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 54f152d1cd0..feaa3ee8c19 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
@@ -25,21 +25,23 @@
/* **************** RGB ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_rgb_cc {
static void cmp_node_rgb_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Color>(N_("RGBA")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_rgb_cc
void register_node_type_cmp_rgb()
{
+ namespace file_ns = blender::nodes::node_composite_rgb_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_RGB, "RGB", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::cmp_node_rgb_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_RGB, "RGB", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_rgb_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_rotate.cc b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
index 8ddd62a6226..96ac4f3db5b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rotate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Rotate ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_rotate_cc {
static void cmp_node_rotate_declare(NodeDeclarationBuilder &b)
{
@@ -38,20 +41,28 @@ static void cmp_node_rotate_declare(NodeDeclarationBuilder &b)
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. */
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_rotate_cc
+
void register_node_type_cmp_rotate()
{
+ namespace file_ns = blender::nodes::node_composite_rotate_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_rotate_declare;
- node_type_init(&ntype, node_composit_init_rotate);
+ cmp_node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_rotate_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_rotate;
+ node_type_init(&ntype, file_ns::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 14890146818..dba08dd7eb1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_scale.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc
@@ -21,11 +21,16 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Scale ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_scale_cc {
static void cmp_node_scale_declare(NodeDeclarationBuilder &b)
{
@@ -35,8 +40,6 @@ static void cmp_node_scale_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock;
@@ -50,13 +53,36 @@ static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
}
}
+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);
+ }
+}
+
+} // namespace blender::nodes::node_composite_scale_cc
+
void register_node_type_cmp_scale()
{
+ namespace file_ns = blender::nodes::node_composite_scale_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_scale_declare;
- node_type_update(&ntype, node_composite_update_scale);
+ cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_scale_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_scale;
+ node_type_update(&ntype, file_ns::node_composite_update_scale);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_scene_time.cc b/source/blender/nodes/composite/nodes/node_composite_scene_time.cc
new file mode 100644
index 00000000000..5c53c1df237
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_scene_time.cc
@@ -0,0 +1,39 @@
+/*
+ * 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 cmpnodes
+ */
+
+#include "node_composite_util.hh"
+
+namespace blender::nodes {
+
+static void cmp_node_scene_time_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Seconds"));
+ b.add_output<decl::Float>(N_("Frame"));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_cmp_scene_time()
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT);
+ ntype.declare = blender::nodes::cmp_node_scene_time_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
index 9eafc0e3594..41d0668dbf2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_hsva.cc
@@ -25,7 +25,7 @@
/* **************** SEPARATE HSVA ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_sepcomb_hsva_cc {
static void cmp_node_sephsva_declare(NodeDeclarationBuilder &b)
{
@@ -36,20 +36,22 @@ static void cmp_node_sephsva_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("A"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_sepcomb_hsva_cc
void register_node_type_cmp_sephsva()
{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_hsva_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::cmp_node_sephsva_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_sephsva_declare;
nodeRegisterType(&ntype);
}
/* **************** COMBINE HSVA ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_sepcomb_hsva_cc {
static void cmp_node_combhsva_declare(NodeDeclarationBuilder &b)
{
@@ -60,14 +62,16 @@ static void cmp_node_combhsva_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_sepcomb_hsva_cc
void register_node_type_cmp_combhsva()
{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_hsva_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::cmp_node_combhsva_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_combhsva_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
index e81ea6f31be..bd200b0886f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_rgba.cc
@@ -24,7 +24,7 @@
#include "node_composite_util.hh"
/* **************** SEPARATE RGBA ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_sepcomb_rgba_cc {
static void cmp_node_seprgba_declare(NodeDeclarationBuilder &b)
{
@@ -35,21 +35,23 @@ static void cmp_node_seprgba_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("A"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_sepcomb_rgba_cc
void register_node_type_cmp_seprgba()
{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_rgba_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::cmp_node_seprgba_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_seprgba_declare;
nodeRegisterType(&ntype);
}
/* **************** COMBINE RGBA ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_sepcomb_rgba_cc {
static void cmp_node_combrgba_declare(NodeDeclarationBuilder &b)
{
@@ -60,14 +62,16 @@ static void cmp_node_combrgba_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_sepcomb_rgba_cc
void register_node_type_cmp_combrgba()
{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_rgba_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::cmp_node_combrgba_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_combrgba_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
index 15c8efc2ef8..79cb379806c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_ycca.cc
@@ -25,7 +25,7 @@
/* **************** SEPARATE YCCA ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_sepcomb_ycca_cc {
static void cmp_node_sepycca_declare(NodeDeclarationBuilder &b)
{
@@ -36,27 +36,29 @@ static void cmp_node_sepycca_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("A"));
}
-} // namespace blender::nodes
-
static void node_composit_init_mode_sepycca(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1; /* BLI_YCC_ITU_BT709 */
}
+} // namespace blender::nodes::node_composite_sepcomb_ycca_cc
+
void register_node_type_cmp_sepycca()
{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_ycca_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::cmp_node_sepycca_declare;
- node_type_init(&ntype, node_composit_init_mode_sepycca);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_sepycca_declare;
+ node_type_init(&ntype, file_ns::node_composit_init_mode_sepycca);
nodeRegisterType(&ntype);
}
/* **************** COMBINE YCCA ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_sepcomb_ycca_cc {
static void cmp_node_combycca_declare(NodeDeclarationBuilder &b)
{
@@ -67,20 +69,22 @@ static void cmp_node_combycca_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_mode_combycca(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 1; /* BLI_YCC_ITU_BT709 */
}
+} // namespace blender::nodes::node_composite_sepcomb_ycca_cc
+
void register_node_type_cmp_combycca()
{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_ycca_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::cmp_node_combycca_declare;
- node_type_init(&ntype, node_composit_init_mode_combycca);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_combycca_declare;
+ node_type_init(&ntype, file_ns::node_composit_init_mode_combycca);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
index 4d4b01c2fb3..29c0f753e00 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcomb_yuva.cc
@@ -25,7 +25,7 @@
/* **************** SEPARATE YUVA ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_sepcomb_yuva_cc {
static void cmp_node_sepyuva_declare(NodeDeclarationBuilder &b)
{
@@ -36,21 +36,23 @@ static void cmp_node_sepyuva_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("A"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_sepcomb_yuva_cc
void register_node_type_cmp_sepyuva()
{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_yuva_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::cmp_node_sepyuva_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_sepyuva_declare;
nodeRegisterType(&ntype);
}
/* **************** COMBINE YUVA ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_sepcomb_yuva_cc {
static void cmp_node_combyuva_declare(NodeDeclarationBuilder &b)
{
@@ -61,14 +63,16 @@ static void cmp_node_combyuva_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_sepcomb_yuva_cc
void register_node_type_cmp_combyuva()
{
+ namespace file_ns = blender::nodes::node_composite_sepcomb_yuva_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::cmp_node_combyuva_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_combyuva_declare;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
index 04eb055f3b2..18f8fe45833 100644
--- a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** SET ALPHA ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_setalpha_cc {
static void cmp_node_setalpha_declare(NodeDeclarationBuilder &b)
{
@@ -34,22 +37,30 @@ static void cmp_node_setalpha_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_setalpha(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeSetAlpha *settings = (NodeSetAlpha *)MEM_callocN(sizeof(NodeSetAlpha), __func__);
+ NodeSetAlpha *settings = MEM_cnew<NodeSetAlpha>(__func__);
node->storage = settings;
settings->mode = CMP_NODE_SETALPHA_MODE_APPLY;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_setalpha_cc
+
void register_node_type_cmp_setalpha()
{
+ namespace file_ns = blender::nodes::node_composite_setalpha_cc;
+
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;
- node_type_init(&ntype, node_composit_init_setalpha);
+ cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_setalpha_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_set_alpha;
+ node_type_init(&ntype, file_ns::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_split_viewer.cc
index ad8dcd0d8e9..68a6c8c2943 100644
--- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_split_viewer.cc
@@ -21,14 +21,17 @@
* \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 ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_split_viewer_cc {
static void cmp_node_split_viewer_declare(NodeDeclarationBuilder &b)
{
@@ -36,11 +39,9 @@ static void cmp_node_split_viewer_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Color>(N_("Image"), "Image_001");
}
-} // namespace blender::nodes
-
static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node)
{
- ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = MEM_cnew<ImageUser>(__func__);
node->storage = iuser;
iuser->sfra = 1;
node->custom1 = 50; /* default 50% split */
@@ -48,14 +49,29 @@ 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");
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_split_viewer_cc
+
void register_node_type_cmp_splitviewer()
{
+ namespace file_ns = blender::nodes::node_composite_split_viewer_cc;
+
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_split_viewer_declare;
- node_type_init(&ntype, node_composit_init_splitviewer);
+ cmp_node_type_base(&ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::cmp_node_split_viewer_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_splitviewer;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_splitviewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
ntype.no_muting = true;
diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
index 841cc6a5da3..5fe057f4f2e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
@@ -21,14 +21,17 @@
* \ingroup cmpnodes
*/
-#include "node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "node_composite_util.hh"
+
/* **************** Stabilize 2D ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_stabilize2d_cc {
static void cmp_node_stabilize2d_declare(NodeDeclarationBuilder &b)
{
@@ -36,8 +39,6 @@ static void cmp_node_stabilize2d_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void init(const bContext *C, PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
@@ -50,13 +51,41 @@ static void init(const bContext *C, PointerRNA *ptr)
node->custom1 = 1;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_stabilize2d_cc
+
void register_node_type_cmp_stabilize2d()
{
+ namespace file_ns = blender::nodes::node_composite_stabilize2d_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_STABILIZE2D, "Stabilize 2D", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_stabilize2d_declare;
- ntype.initfunc_api = init;
+ cmp_node_type_base(&ntype, CMP_NODE_STABILIZE2D, "Stabilize 2D", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_stabilize2d_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_stabilize2d;
+ ntype.initfunc_api = file_ns::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 06d32569b0b..34433e2bf40 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
@@ -21,9 +21,12 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_sunbeams_cc {
static void cmp_node_sunbeams_declare(NodeDeclarationBuilder &b)
{
@@ -31,24 +34,38 @@ static void cmp_node_sunbeams_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeSunBeams *data = (NodeSunBeams *)MEM_callocN(sizeof(NodeSunBeams), "sun beams node");
+ NodeSunBeams *data = MEM_cnew<NodeSunBeams>(__func__);
data->source[0] = 0.5f;
data->source[1] = 0.5f;
node->storage = data;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_sunbeams_cc
+
void register_node_type_cmp_sunbeams()
{
+ namespace file_ns = blender::nodes::node_composite_sunbeams_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER, 0);
- ntype.declare = blender::nodes::cmp_node_sunbeams_declare;
- node_type_init(&ntype, init);
+ cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_sunbeams_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_sunbeams;
+ node_type_init(&ntype, file_ns::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 e8e7e7eb941..342813f8d67 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switch.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_switch.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
-#include "../node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
/* **************** Switch ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_switch_cc {
static void cmp_node_switch_declare(NodeDeclarationBuilder &b)
{
@@ -34,15 +37,22 @@ static void cmp_node_switch_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
+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);
+}
+
+} // namespace blender::nodes::node_composite_switch_cc
-/* custom1 = mix type */
void register_node_type_cmp_switch()
{
+ namespace file_ns = blender::nodes::node_composite_switch_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SWITCH, "Switch", NODE_CLASS_LAYOUT, 0);
- ntype.declare = blender::nodes::cmp_node_switch_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_SWITCH, "Switch", NODE_CLASS_LAYOUT);
+ ntype.declare = file_ns::cmp_node_switch_declare;
+ ntype.draw_buttons = file_ns::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 b452a894e7c..678d7fe1a9b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switchview.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_switchview.cc
@@ -25,9 +25,15 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
-#include "../node_composite_util.hh"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_composite_util.hh"
/* **************** SWITCH VIEW ******************** */
+
+namespace blender::nodes::node_composite_switchview_cc {
+
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,16 +143,33 @@ static void init_switch_view(const bContext *C, PointerRNA *ptr)
cmp_node_switch_view_sanitycheck(ntree, node);
}
-void register_node_type_cmp_switch_view()
+static void node_composit_buts_switch_view_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr))
{
- static bNodeType ntype;
+ uiItemFullO(layout,
+ "NODE_OT_switch_view_update",
+ "Update Views",
+ ICON_FILE_REFRESH,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ nullptr);
+}
- 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);
+} // namespace blender::nodes::node_composite_switchview_cc
- ntype.initfunc_api = init_switch_view;
+void register_node_type_cmp_switch_view()
+{
+ namespace file_ns = blender::nodes::node_composite_switchview_cc;
+
+ static bNodeType ntype;
- node_type_update(&ntype, cmp_node_switch_view_update);
+ cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER);
+ node_type_socket_templates(&ntype, nullptr, file_ns::cmp_node_switch_view_out);
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_switch_view_ex;
+ ntype.initfunc_api = file_ns::init_switch_view;
+ node_type_update(&ntype, file_ns::cmp_node_switch_view_update);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.cc b/source/blender/nodes/composite/nodes/node_composite_texture.cc
index 5e5fca755b2..5c2446d4f2c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_texture.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_texture.cc
@@ -25,7 +25,7 @@
/* **************** TEXTURE ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_texture_cc {
static void cmp_node_texture_declare(NodeDeclarationBuilder &b)
{
@@ -39,14 +39,17 @@ static void cmp_node_texture_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Color"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_texture_cc
void register_node_type_cmp_texture()
{
+ namespace file_ns = blender::nodes::node_composite_texture_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW);
- ntype.declare = blender::nodes::cmp_node_texture_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_texture_declare;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
index e23243e9bee..08ec998dfa2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
@@ -21,9 +21,14 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_tonemap_cc {
static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b)
{
@@ -31,11 +36,9 @@ static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_tonemap(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTonemap *ntm = (NodeTonemap *)MEM_callocN(sizeof(NodeTonemap), "node tonemap data");
+ NodeTonemap *ntm = MEM_cnew<NodeTonemap>(__func__);
ntm->type = 1;
ntm->key = 0.18;
ntm->offset = 1;
@@ -49,13 +52,40 @@ static void node_composit_init_tonemap(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = ntm;
}
+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);
+ }
+}
+
+} // namespace blender::nodes::node_composite_tonemap_cc
+
void register_node_type_cmp_tonemap()
{
+ namespace file_ns = blender::nodes::node_composite_tonemap_cc;
+
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;
- node_type_init(&ntype, node_composit_init_tonemap);
+ cmp_node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_tonemap_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_tonemap;
+ node_type_init(&ntype, file_ns::node_composit_init_tonemap);
node_type_storage(&ntype, "NodeTonemap", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
index 3780a7e1aa1..3a45319d0ad 100644
--- a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
@@ -21,9 +21,14 @@
* \ingroup cmpnodes
*/
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_composite_trackpos_cc {
static void cmp_node_trackpos_declare(NodeDeclarationBuilder &b)
{
@@ -32,23 +37,73 @@ static void cmp_node_trackpos_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Speed")).subtype(PROP_VELOCITY);
}
-} // namespace blender::nodes
-
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTrackPosData *data = (NodeTrackPosData *)MEM_callocN(sizeof(NodeTrackPosData),
- "node track position data");
+ NodeTrackPosData *data = MEM_cnew<NodeTrackPosData>(__func__);
node->storage = data;
}
+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);
+ }
+ }
+}
+
+} // namespace blender::nodes::node_composite_trackpos_cc
+
void register_node_type_cmp_trackpos()
{
+ namespace file_ns = blender::nodes::node_composite_trackpos_cc;
+
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;
- node_type_init(&ntype, init);
+ cmp_node_type_base(&ntype, CMP_NODE_TRACKPOS, "Track Position", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_trackpos_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_trackpos;
+ node_type_init(&ntype, file_ns::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 1acc671626a..6afc173df04 100644
--- a/source/blender/nodes/composite/nodes/node_composite_transform.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_transform.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Transform ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_transform_cc {
static void cmp_node_transform_declare(NodeDeclarationBuilder &b)
{
@@ -41,14 +44,22 @@ static void cmp_node_transform_declare(NodeDeclarationBuilder &b)
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);
+}
+
+} // namespace blender::nodes::node_composite_transform_cc
void register_node_type_cmp_transform()
{
+ namespace file_ns = blender::nodes::node_composite_transform_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TRANSFORM, "Transform", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_transform_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_TRANSFORM, "Transform", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_transform_declare;
+ ntype.draw_buttons = file_ns::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 2ad70b4a0e5..6666d161b4a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_translate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_translate.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Translate ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_translate_cc {
static void cmp_node_translate_declare(NodeDeclarationBuilder &b)
{
@@ -35,22 +38,30 @@ static void cmp_node_translate_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
static void node_composit_init_translate(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTranslateData *data = (NodeTranslateData *)MEM_callocN(sizeof(NodeTranslateData),
- "node translate data");
+ NodeTranslateData *data = MEM_cnew<NodeTranslateData>(__func__);
node->storage = data;
}
+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);
+}
+
+} // namespace blender::nodes::node_composite_translate_cc
+
void register_node_type_cmp_translate()
{
+ namespace file_ns = blender::nodes::node_composite_translate_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0);
- ntype.declare = blender::nodes::cmp_node_translate_declare;
- node_type_init(&ntype, node_composit_init_translate);
+ cmp_node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT);
+ ntype.declare = file_ns::cmp_node_translate_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_translate;
+ node_type_init(&ntype, file_ns::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_val_to_rgb.cc
index dca6c9c141c..797bd931577 100644
--- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc
@@ -25,7 +25,7 @@
/* **************** VALTORGB ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_val_to_rgb_cc {
static void cmp_node_valtorgb_declare(NodeDeclarationBuilder &b)
{
@@ -34,21 +34,23 @@ static void cmp_node_valtorgb_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Alpha"));
}
-} // namespace blender::nodes
-
static void node_composit_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = BKE_colorband_add(true);
}
+} // namespace blender::nodes::node_composite_val_to_rgb_cc
+
void register_node_type_cmp_valtorgb()
{
+ namespace file_ns = blender::nodes::node_composite_val_to_rgb_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::cmp_node_valtorgb_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_valtorgb_declare;
node_type_size(&ntype, 240, 200, 320);
- node_type_init(&ntype, node_composit_init_valtorgb);
+ node_type_init(&ntype, file_ns::node_composit_init_valtorgb);
node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
@@ -56,7 +58,7 @@ void register_node_type_cmp_valtorgb()
/* **************** RGBTOBW ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_val_to_rgb_cc {
static void cmp_node_rgbtobw_declare(NodeDeclarationBuilder &b)
{
@@ -64,14 +66,16 @@ static void cmp_node_rgbtobw_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Val"));
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_val_to_rgb_cc
void register_node_type_cmp_rgbtobw()
{
+ namespace file_ns = blender::nodes::node_composite_val_to_rgb_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::cmp_node_rgbtobw_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::cmp_node_rgbtobw_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_value.cc b/source/blender/nodes/composite/nodes/node_composite_value.cc
index d2274d2d82a..076adc1c01c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_value.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_value.cc
@@ -25,21 +25,23 @@
/* **************** VALUE ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_value_cc {
static void cmp_node_value_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Value")).default_value(0.5f);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_composite_value_cc
void register_node_type_cmp_value()
{
+ namespace file_ns = blender::nodes::node_composite_value_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::cmp_node_value_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_VALUE, "Value", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::cmp_node_value_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc b/source/blender/nodes/composite/nodes/node_composite_vec_blur.cc
index 7c82001210d..a461688641d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_vec_blur.cc
@@ -21,11 +21,14 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** VECTOR BLUR ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_vec_blur_cc {
static void cmp_node_vec_blur_declare(NodeDeclarationBuilder &b)
{
@@ -39,24 +42,43 @@ static void cmp_node_vec_blur_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
}
-} // namespace blender::nodes
-
+/* custom1: iterations, custom2: max_speed (0 = no_limit). */
static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBlurData *nbd = (NodeBlurData *)MEM_callocN(sizeof(NodeBlurData), "node blur data");
+ NodeBlurData *nbd = MEM_cnew<NodeBlurData>(__func__);
node->storage = nbd;
nbd->samples = 32;
nbd->fac = 1.0f;
}
-/* custom1: iterations, custom2: max_speed (0 = no_limit). */
+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);
+}
+
+} // namespace blender::nodes::node_composite_vec_blur_cc
+
void register_node_type_cmp_vecblur()
{
+ namespace file_ns = blender::nodes::node_composite_vec_blur_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER, 0);
- ntype.declare = blender::nodes::cmp_node_vec_blur_declare;
- node_type_init(&ntype, node_composit_init_vecblur);
+ cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER);
+ ntype.declare = file_ns::cmp_node_vec_blur_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_vecblur;
+ node_type_init(&ntype, file_ns::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 ebac7d31c52..a57f1fbb8ef 100644
--- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
@@ -21,14 +21,19 @@
* \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 {
+namespace blender::nodes::node_composite_viewer_cc {
static void cmp_node_viewer_declare(NodeDeclarationBuilder &b)
{
@@ -37,11 +42,9 @@ static void cmp_node_viewer_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Z")).default_value(1.0f).min(0.0f).max(1.0f);
}
-} // namespace blender::nodes
-
static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode *node)
{
- ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = MEM_cnew<ImageUser>(__func__);
node->storage = iuser;
iuser->sfra = 1;
node->custom3 = 0.5f;
@@ -50,13 +53,38 @@ 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");
}
+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);
+ }
+}
+
+} // namespace blender::nodes::node_composite_viewer_cc
+
void register_node_type_cmp_viewer()
{
+ namespace file_ns = blender::nodes::node_composite_viewer_cc;
+
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;
- node_type_init(&ntype, node_composit_init_viewer);
+ cmp_node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::cmp_node_viewer_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_viewer;
+ ntype.draw_buttons_ex = file_ns::node_composit_buts_viewer_ex;
+ ntype.flag |= NODE_PREVIEW;
+ node_type_init(&ntype, file_ns::node_composit_init_viewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
ntype.no_muting = true;
diff --git a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
index 982714e030e..7a6d5b3af5f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
@@ -21,30 +21,45 @@
* \ingroup cmpnodes
*/
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "node_composite_util.hh"
/* **************** Z COMBINE ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_composite_zcombine_cc {
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::Float>(N_("Z")).default_value(1.0f).min(0.0f).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_input<decl::Float>(N_("Z"), "Z_001").default_value(1.0f).min(0.0f).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);
+}
+
+} // namespace blender::nodes::node_composite_zcombine_cc
void register_node_type_cmp_zcombine()
{
+ namespace file_ns = blender::nodes::node_composite_zcombine_cc;
+
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::cmp_node_zcombine_declare;
+ cmp_node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::cmp_node_zcombine_declare;
+ ntype.draw_buttons = file_ns::node_composit_buts_zcombine;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt
new file mode 100644
index 00000000000..0c3c6a34995
--- /dev/null
+++ b/source/blender/nodes/function/CMakeLists.txt
@@ -0,0 +1,75 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2021, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ..
+ ../intern
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../editors/include
+ ../../functions
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+
+set(SRC
+ nodes/legacy/node_fn_random_float.cc
+
+ nodes/node_fn_align_euler_to_vector.cc
+ nodes/node_fn_boolean_math.cc
+ nodes/node_fn_compare.cc
+ nodes/node_fn_float_to_int.cc
+ nodes/node_fn_input_bool.cc
+ nodes/node_fn_input_color.cc
+ nodes/node_fn_input_int.cc
+ nodes/node_fn_input_special_characters.cc
+ nodes/node_fn_input_string.cc
+ nodes/node_fn_input_vector.cc
+ nodes/node_fn_random_value.cc
+ nodes/node_fn_replace_string.cc
+ nodes/node_fn_rotate_euler.cc
+ nodes/node_fn_slice_string.cc
+ nodes/node_fn_string_length.cc
+ nodes/node_fn_value_to_string.cc
+
+ node_function_util.cc
+
+ node_function_util.hh
+)
+
+set(LIB
+ bf_functions
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+blender_add_lib(bf_nodes_function "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_nodes_function PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_nodes_function PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc
index ac48322c269..0137b298f45 100644
--- a/source/blender/nodes/function/node_function_util.cc
+++ b/source/blender/nodes/function/node_function_util.cc
@@ -17,6 +17,8 @@
#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)
@@ -29,9 +31,10 @@ static bool fn_node_poll_default(bNodeType *UNUSED(ntype),
return true;
}
-void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = fn_node_poll_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/function/node_function_util.hh b/source/blender/nodes/function/node_function_util.hh
index 46b485298e3..69c617b4f01 100644
--- a/source/blender/nodes/function/node_function_util.hh
+++ b/source/blender/nodes/function/node_function_util.hh
@@ -18,7 +18,7 @@
#include <string.h>
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
@@ -37,5 +37,4 @@
#include "FN_multi_function_builder.hh"
-void fn_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
diff --git a/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
index d98d49c7273..9470b82a8eb 100644
--- a/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
+++ b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
@@ -18,7 +18,7 @@
#include "BLI_hash.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_random_float_cc {
static void fn_node_legacy_random_float_declare(NodeDeclarationBuilder &b)
{
@@ -27,9 +27,7 @@ static void fn_node_legacy_random_float_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Max")).default_value(1.0f).min(-10000.0f).max(10000.0f);
b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
b.add_output<decl::Float>(N_("Value"));
-};
-
-} // namespace blender::nodes
+}
class RandomFloatFunction : public blender::fn::MultiFunction {
public:
@@ -75,12 +73,16 @@ static void fn_node_legacy_random_float_build_multi_function(
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_fn_random_float_cc
+
void register_node_type_fn_legacy_random_float()
{
+ namespace file_ns = blender::nodes::node_fn_random_float_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_LEGACY_RANDOM_FLOAT, "Random Float", 0, 0);
- ntype.declare = blender::nodes::fn_node_legacy_random_float_declare;
- ntype.build_multi_function = fn_node_legacy_random_float_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_LEGACY_RANDOM_FLOAT, "Random Float", 0);
+ ntype.declare = file_ns::fn_node_legacy_random_float_declare;
+ ntype.build_multi_function = file_ns::fn_node_legacy_random_float_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
index 4088fa24ca7..bcc035e6ede 100644
--- a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
+++ b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
@@ -23,7 +23,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_align_euler_to_vector_cc {
static void fn_node_align_euler_to_vector_declare(NodeDeclarationBuilder &b)
{
@@ -69,14 +69,14 @@ static void align_rotations_auto_pivot(IndexMask mask,
float3 old_axis;
mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
- const float3 new_axis = vector.normalized();
- float3 rotation_axis = float3::cross_high_precision(old_axis, new_axis);
+ const float3 new_axis = math::normalize(vector);
+ float3 rotation_axis = math::cross_high_precision(old_axis, new_axis);
if (is_zero_v3(rotation_axis)) {
/* The vectors are linearly dependent, so we fall back to another axis. */
- rotation_axis = float3::cross_high_precision(old_axis, float3(1, 0, 0));
+ rotation_axis = math::cross_high_precision(old_axis, float3(1, 0, 0));
if (is_zero_v3(rotation_axis)) {
/* This is now guaranteed to not be zero. */
- rotation_axis = float3::cross_high_precision(old_axis, float3(0, 1, 0));
+ rotation_axis = math::cross_high_precision(old_axis, float3(0, 1, 0));
}
}
@@ -207,16 +207,18 @@ static void fn_node_align_euler_to_vector_build_multi_function(NodeMultiFunction
builder.construct_and_set_matching_fn<MF_AlignEulerToVector>(node.custom1, node.custom2);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_align_euler_to_vector_cc
void register_node_type_fn_align_euler_to_vector()
{
+ namespace file_ns = blender::nodes::node_fn_align_euler_to_vector_cc;
+
static bNodeType ntype;
fn_node_type_base(
- &ntype, FN_NODE_ALIGN_EULER_TO_VECTOR, "Align Euler to Vector", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_align_euler_to_vector_declare;
- ntype.draw_buttons = blender::nodes::fn_node_align_euler_to_vector_layout;
- ntype.build_multi_function = blender::nodes::fn_node_align_euler_to_vector_build_multi_function;
+ &ntype, FN_NODE_ALIGN_EULER_TO_VECTOR, "Align Euler to Vector", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_align_euler_to_vector_declare;
+ ntype.draw_buttons = file_ns::fn_node_align_euler_to_vector_layout;
+ ntype.build_multi_function = file_ns::fn_node_align_euler_to_vector_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
index 4b59b49c632..9425c4ff328 100644
--- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -22,9 +22,11 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_boolean_math_cc {
static void fn_node_boolean_math_declare(NodeDeclarationBuilder &b)
{
@@ -32,7 +34,7 @@ static void fn_node_boolean_math_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Bool>(N_("Boolean"), "Boolean");
b.add_input<decl::Bool>(N_("Boolean"), "Boolean_001");
b.add_output<decl::Bool>(N_("Boolean"));
-};
+}
static void fn_node_boolean_math_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
@@ -43,8 +45,7 @@ static void node_boolean_math_update(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
- nodeSetSocketAvailability(
- ntree, sockB, ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR));
+ nodeSetSocketAvailability(ntree, sockB, !ELEM(node->custom1, NODE_BOOLEAN_MATH_NOT));
}
static void node_boolean_math_label(const bNodeTree *UNUSED(ntree),
@@ -60,6 +61,27 @@ static void node_boolean_math_label(const bNodeTree *UNUSED(ntree),
BLI_strncpy(label, IFACE_(name), maxlen);
}
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ if (!params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_BOOLEAN)) {
+ return;
+ }
+
+ for (const EnumPropertyItem *item = rna_enum_node_boolean_math_items;
+ item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ NodeBooleanMathOperation operation = static_cast<NodeBooleanMathOperation>(item->value);
+ params.add_item(IFACE_(item->name), [operation](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("FunctionNodeBooleanMath");
+ node.custom1 = operation;
+ params.update_and_connect_available_socket(node, "Boolean");
+ });
+ }
+ }
+}
+
static const fn::MultiFunction *get_multi_function(bNode &bnode)
{
static fn::CustomMF_SI_SI_SO<bool, bool, bool> and_fn{"And",
@@ -67,6 +89,18 @@ static const fn::MultiFunction *get_multi_function(bNode &bnode)
static fn::CustomMF_SI_SI_SO<bool, bool, bool> or_fn{"Or",
[](bool a, bool b) { return a || b; }};
static fn::CustomMF_SI_SO<bool, bool> not_fn{"Not", [](bool a) { return !a; }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> nand_fn{"Not And",
+ [](bool a, bool b) { return !(a && b); }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> nor_fn{"Nor",
+ [](bool a, bool b) { return !(a || b); }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> xnor_fn{"Equal",
+ [](bool a, bool b) { return a == b; }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> xor_fn{"Not Equal",
+ [](bool a, bool b) { return a != b; }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> imply_fn{"Imply",
+ [](bool a, bool b) { return !a || b; }};
+ static fn::CustomMF_SI_SI_SO<bool, bool, bool> nimply_fn{"Subtract",
+ [](bool a, bool b) { return a && !b; }};
switch (bnode.custom1) {
case NODE_BOOLEAN_MATH_AND:
@@ -75,6 +109,18 @@ static const fn::MultiFunction *get_multi_function(bNode &bnode)
return &or_fn;
case NODE_BOOLEAN_MATH_NOT:
return &not_fn;
+ case NODE_BOOLEAN_MATH_NAND:
+ return &nand_fn;
+ case NODE_BOOLEAN_MATH_NOR:
+ return &nor_fn;
+ case NODE_BOOLEAN_MATH_XNOR:
+ return &xnor_fn;
+ case NODE_BOOLEAN_MATH_XOR:
+ return &xor_fn;
+ case NODE_BOOLEAN_MATH_IMPLY:
+ return &imply_fn;
+ case NODE_BOOLEAN_MATH_NIMPLY:
+ return &nimply_fn;
}
BLI_assert_unreachable();
@@ -87,17 +133,20 @@ static void fn_node_boolean_math_build_multi_function(NodeMultiFunctionBuilder &
builder.set_matching_fn(fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_boolean_math_cc
void register_node_type_fn_boolean_math()
{
+ namespace file_ns = blender::nodes::node_fn_boolean_math_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_boolean_math_declare;
- ntype.labelfunc = blender::nodes::node_boolean_math_label;
- node_type_update(&ntype, blender::nodes::node_boolean_math_update);
- ntype.build_multi_function = blender::nodes::fn_node_boolean_math_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_boolean_math_layout;
+ fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_boolean_math_declare;
+ ntype.labelfunc = file_ns::node_boolean_math_label;
+ node_type_update(&ntype, file_ns::node_boolean_math_update);
+ ntype.build_multi_function = file_ns::fn_node_boolean_math_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_boolean_math_layout;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc
index c880f0b1423..13a7ff86624 100644
--- a/source/blender/nodes/function/nodes/node_fn_compare.cc
+++ b/source/blender/nodes/function/nodes/node_fn_compare.cc
@@ -16,8 +16,6 @@
#include <cmath>
-//#include "node_geometry_util.hh"
-
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -28,8 +26,12 @@
#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();
@@ -53,13 +55,13 @@ static void fn_node_compare_declare(NodeDeclarationBuilder &b)
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 = (NodeFunctionCompare *)((bNode *)(ptr->data))->storage;
+ 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) {
+ if (data.data_type == SOCK_VECTOR) {
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
}
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
@@ -95,14 +97,70 @@ static void node_compare_update(bNodeTree *ntree, bNode *node)
static void node_compare_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeFunctionCompare *data = (NodeFunctionCompare *)MEM_callocN(sizeof(NodeFunctionCompare),
- __func__);
+ NodeFunctionCompare *data = MEM_cnew<NodeFunctionCompare>(__func__);
data->operation = NODE_COMPARE_GREATER_THAN;
data->data_type = SOCK_FLOAT;
data->mode = NODE_COMPARE_MODE_ELEMENT;
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 eNodeSocketDatatype type = static_cast<eNodeSocketDatatype>(params.other_socket().type);
+ if (!ELEM(type, SOCK_BOOLEAN, SOCK_FLOAT, SOCK_RGBA, SOCK_VECTOR, SOCK_INT, SOCK_STRING)) {
+ return;
+ }
+
+ const eNodeSocketDatatype mode_type = (type == SOCK_BOOLEAN) ? SOCK_INT : type;
+ const bool string_type = (type == SOCK_STRING);
+
+ const std::string socket_name = params.in_out() == SOCK_IN ? "A" : "Result";
+
+ for (const EnumPropertyItem *item = rna_enum_node_compare_operation_items;
+ item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ if (!string_type &&
+ ELEM(item->value, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER)) {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{socket_name,
+ SOCK_RGBA,
+ static_cast<NodeCompareOperation>(item->value)});
+ }
+ else if ((!string_type) ||
+ (string_type && ELEM(item->value, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL))) {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{socket_name,
+ mode_type,
+ static_cast<NodeCompareOperation>(item->value)});
+ }
+ }
+ }
+ /* Add Angle socket. */
+ if (!string_type && params.in_out() == SOCK_IN) {
+ params.add_item(
+ IFACE_("Angle"),
+ SocketSearchOp{
+ "Angle", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DIRECTION});
+ }
+}
+
static void node_compare_label(const bNodeTree *UNUSED(ntree),
const bNode *node,
char *label,
@@ -208,7 +266,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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; }};
+ [](float3 a, float3 b, float comp) { return math::dot(a, b) < comp; }};
return &fn;
}
case NODE_COMPARE_MODE_DIRECTION: {
@@ -226,7 +284,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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(); }};
+ [](float3 a, float3 b) { return math::length(a) < math::length(b); }};
return &fn;
}
}
@@ -242,7 +300,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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; }};
+ [](float3 a, float3 b, float comp) { return math::dot(a, b) <= comp; }};
return &fn;
}
case NODE_COMPARE_MODE_DIRECTION: {
@@ -260,7 +318,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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(); }};
+ [](float3 a, float3 b) { return math::length(a) <= math::length(b); }};
return &fn;
}
}
@@ -276,7 +334,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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; }};
+ [](float3 a, float3 b, float comp) { return math::dot(a, b) > comp; }};
return &fn;
}
case NODE_COMPARE_MODE_DIRECTION: {
@@ -294,7 +352,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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(); }};
+ [](float3 a, float3 b) { return math::length(a) > math::length(b); }};
return &fn;
}
}
@@ -310,7 +368,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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; }};
+ [](float3 a, float3 b, float comp) { return math::dot(a, b) >= comp; }};
return &fn;
}
case NODE_COMPARE_MODE_DIRECTION: {
@@ -328,7 +386,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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(); }};
+ [](float3 a, float3 b) { return math::length(a) >= math::length(b); }};
return &fn;
}
}
@@ -345,7 +403,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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 abs(math::dot(a, b) - comp) <= epsilon;
}};
return &fn;
}
@@ -367,7 +425,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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 abs(math::length(a) - math::length(b)) <= epsilon;
}};
return &fn;
}
@@ -385,7 +443,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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 abs(math::dot(a, b) - comp) >= epsilon;
}};
return &fn;
}
@@ -407,7 +465,7 @@ static const fn::MultiFunction *get_multi_function(bNode &node)
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 abs(math::length(a) - math::length(b)) > epsilon;
}};
return &fn;
}
@@ -480,7 +538,7 @@ void register_node_type_fn_compare()
namespace file_ns = blender::nodes::node_fn_compare_cc;
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_COMPARE, "Compare", NODE_CLASS_CONVERTER, 0);
+ fn_node_type_base(&ntype, FN_NODE_COMPARE, "Compare", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::fn_node_compare_declare;
ntype.labelfunc = file_ns::node_compare_label;
node_type_update(&ntype, file_ns::node_compare_update);
@@ -489,5 +547,6 @@ void register_node_type_fn_compare()
&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_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
index 21f6734e4aa..488787980dc 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
@@ -25,14 +25,14 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_float_to_int_cc {
static void fn_node_float_to_int_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_input<decl::Float>(N_("Float"));
b.add_output<decl::Int>(N_("Integer"));
-};
+}
static void fn_node_float_to_int_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
@@ -81,16 +81,18 @@ static void fn_node_float_to_int_build_multi_function(NodeMultiFunctionBuilder &
builder.set_matching_fn(fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_float_to_int_cc
void register_node_type_fn_float_to_int()
{
+ namespace file_ns = blender::nodes::node_fn_float_to_int_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_float_to_int_declare;
- ntype.labelfunc = blender::nodes::node_float_to_int_label;
- ntype.build_multi_function = blender::nodes::fn_node_float_to_int_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_float_to_int_layout;
+ fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_float_to_int_declare;
+ ntype.labelfunc = file_ns::node_float_to_int_label;
+ ntype.build_multi_function = file_ns::fn_node_float_to_int_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_float_to_int_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_bool.cc b/source/blender/nodes/function/nodes/node_fn_input_bool.cc
index 1358bf8a223..583570effd9 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_bool.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_bool.cc
@@ -21,12 +21,12 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_bool_cc {
static void fn_node_input_bool_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Bool>(N_("Boolean"));
-};
+}
static void fn_node_input_bool_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
@@ -43,22 +43,24 @@ static void fn_node_input_bool_build_multi_function(NodeMultiFunctionBuilder &bu
static void fn_node_input_bool_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeInputBool *data = (NodeInputBool *)MEM_callocN(sizeof(NodeInputBool), __func__);
+ NodeInputBool *data = MEM_cnew<NodeInputBool>(__func__);
node->storage = data;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_bool_cc
void register_node_type_fn_input_bool()
{
+ namespace file_ns = blender::nodes::node_fn_input_bool_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_BOOL, "Boolean", 0, 0);
- ntype.declare = blender::nodes::fn_node_input_bool_declare;
- node_type_init(&ntype, blender::nodes::fn_node_input_bool_init);
+ fn_node_type_base(&ntype, FN_NODE_INPUT_BOOL, "Boolean", 0);
+ ntype.declare = file_ns::fn_node_input_bool_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_bool_init);
node_type_storage(
&ntype, "NodeInputBool", node_free_standard_storage, node_copy_standard_storage);
- ntype.build_multi_function = blender::nodes::fn_node_input_bool_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_input_bool_layout;
+ ntype.build_multi_function = file_ns::fn_node_input_bool_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_bool_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_color.cc b/source/blender/nodes/function/nodes/node_fn_input_color.cc
index 43bb654b776..1fad5b2f5f4 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_color.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_color.cc
@@ -19,12 +19,12 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_color_cc {
static void fn_node_input_color_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Color>(N_("Color"));
-};
+}
static void fn_node_input_color_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
@@ -43,23 +43,25 @@ static void fn_node_input_color_build_multi_function(
static void fn_node_input_color_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeInputColor *data = (NodeInputColor *)MEM_callocN(sizeof(NodeInputColor), __func__);
+ NodeInputColor *data = MEM_cnew<NodeInputColor>(__func__);
copy_v4_fl4(data->color, 0.5f, 0.5f, 0.5f, 1.0f);
node->storage = data;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_color_cc
void register_node_type_fn_input_color()
{
+ namespace file_ns = blender::nodes::node_fn_input_color_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_COLOR, "Color", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::fn_node_input_color_declare;
- node_type_init(&ntype, blender::nodes::fn_node_input_color_init);
+ fn_node_type_base(&ntype, FN_NODE_INPUT_COLOR, "Color", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::fn_node_input_color_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_color_init);
node_type_storage(
&ntype, "NodeInputColor", node_free_standard_storage, node_copy_standard_storage);
- ntype.build_multi_function = blender::nodes::fn_node_input_color_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_input_color_layout;
+ ntype.build_multi_function = file_ns::fn_node_input_color_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_color_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_int.cc b/source/blender/nodes/function/nodes/node_fn_input_int.cc
index ddbb86e2661..dc30ecb253c 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_int.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_int.cc
@@ -21,12 +21,12 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_int_cc {
static void fn_node_input_int_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Int>(N_("Integer"));
-};
+}
static void fn_node_input_int_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
@@ -43,22 +43,24 @@ static void fn_node_input_int_build_multi_function(NodeMultiFunctionBuilder &bui
static void fn_node_input_int_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeInputInt *data = (NodeInputInt *)MEM_callocN(sizeof(NodeInputInt), __func__);
+ NodeInputInt *data = MEM_cnew<NodeInputInt>(__func__);
node->storage = data;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_int_cc
void register_node_type_fn_input_int()
{
+ namespace file_ns = blender::nodes::node_fn_input_int_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_INT, "Integer", 0, 0);
- ntype.declare = blender::nodes::fn_node_input_int_declare;
- node_type_init(&ntype, blender::nodes::fn_node_input_int_init);
+ fn_node_type_base(&ntype, FN_NODE_INPUT_INT, "Integer", 0);
+ ntype.declare = file_ns::fn_node_input_int_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_int_init);
node_type_storage(
&ntype, "NodeInputInt", node_free_standard_storage, node_copy_standard_storage);
- ntype.build_multi_function = blender::nodes::fn_node_input_int_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_input_int_layout;
+ ntype.build_multi_function = file_ns::fn_node_input_int_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_int_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
index c61af419e50..681bc16a301 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
@@ -16,13 +16,13 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_special_characters_cc {
static void fn_node_input_special_characters_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::String>(N_("Line Break"));
b.add_output<decl::String>(N_("Tab"));
-};
+}
class MF_SpecialCharacters : public fn::MultiFunction {
public:
@@ -59,16 +59,17 @@ static void fn_node_input_special_characters_build_multi_function(
builder.set_matching_fn(special_characters_fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_special_characters_cc
void register_node_type_fn_input_special_characters()
{
+ namespace file_ns = blender::nodes::node_fn_input_special_characters_cc;
+
static bNodeType ntype;
fn_node_type_base(
- &ntype, FN_NODE_INPUT_SPECIAL_CHARACTERS, "Special Characters", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::fn_node_input_special_characters_declare;
- ntype.build_multi_function =
- blender::nodes::fn_node_input_special_characters_build_multi_function;
+ &ntype, FN_NODE_INPUT_SPECIAL_CHARACTERS, "Special Characters", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::fn_node_input_special_characters_declare;
+ ntype.build_multi_function = file_ns::fn_node_input_special_characters_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc
index dd2d1292601..4abb352d802 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc
@@ -19,13 +19,13 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_string_cc {
static void fn_node_input_string_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
b.add_output<decl::String>(N_("String"));
-};
+}
static void fn_node_input_string_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
@@ -71,20 +71,20 @@ static void fn_node_string_copy(bNodeTree *UNUSED(dest_ntree),
dest_node->storage = destination_storage;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_string_cc
void register_node_type_fn_input_string()
{
+ namespace file_ns = blender::nodes::node_fn_input_string_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_STRING, "String", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::fn_node_input_string_declare;
- node_type_init(&ntype, blender::nodes::fn_node_input_string_init);
- node_type_storage(&ntype,
- "NodeInputString",
- blender::nodes::fn_node_input_string_free,
- blender::nodes::fn_node_string_copy);
- ntype.build_multi_function = blender::nodes::fn_node_input_string_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_input_string_layout;
+ fn_node_type_base(&ntype, FN_NODE_INPUT_STRING, "String", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::fn_node_input_string_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_string_init);
+ node_type_storage(
+ &ntype, "NodeInputString", file_ns::fn_node_input_string_free, file_ns::fn_node_string_copy);
+ ntype.build_multi_function = file_ns::fn_node_input_string_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_string_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_vector.cc b/source/blender/nodes/function/nodes/node_fn_input_vector.cc
index 1e5fd186b5a..ba9600b461c 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_vector.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_vector.cc
@@ -21,12 +21,12 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_vector_cc {
static void fn_node_input_vector_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Vector>(N_("Vector"));
-};
+}
static void fn_node_input_vector_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
@@ -44,23 +44,24 @@ static void fn_node_input_vector_build_multi_function(NodeMultiFunctionBuilder &
static void fn_node_input_vector_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeInputVector *data = (NodeInputVector *)MEM_callocN(sizeof(NodeInputVector),
- "input vector node");
+ NodeInputVector *data = MEM_cnew<NodeInputVector>(__func__);
node->storage = data;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_vector_cc
void register_node_type_fn_input_vector()
{
+ namespace file_ns = blender::nodes::node_fn_input_vector_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_VECTOR, "Vector", 0, 0);
- ntype.declare = blender::nodes::fn_node_input_vector_declare;
- node_type_init(&ntype, blender::nodes::fn_node_input_vector_init);
+ fn_node_type_base(&ntype, FN_NODE_INPUT_VECTOR, "Vector", 0);
+ ntype.declare = file_ns::fn_node_input_vector_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_vector_init);
node_type_storage(
&ntype, "NodeInputVector", node_free_standard_storage, node_copy_standard_storage);
- ntype.build_multi_function = blender::nodes::fn_node_input_vector_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_input_vector_layout;
+ ntype.build_multi_function = file_ns::fn_node_input_vector_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_vector_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc
index e2efae68001..ceea6246cb0 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_value.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc
@@ -19,10 +19,12 @@
#include "node_function_util.hh"
+#include "NOD_socket_search_link.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_random_value_cc {
NODE_STORAGE_FUNCS(NodeRandomValue)
@@ -43,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();
@@ -60,7 +63,7 @@ static void fn_node_random_value_layout(uiLayout *layout, bContext *UNUSED(C), P
static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeRandomValue *data = (NodeRandomValue *)MEM_callocN(sizeof(NodeRandomValue), __func__);
+ NodeRandomValue *data = MEM_cnew<NodeRandomValue>(__func__);
data->data_type = CD_PROP_FLOAT;
node->storage = data;
}
@@ -97,6 +100,54 @@ 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:
+ case SOCK_RGBA:
+ return CD_PROP_FLOAT3;
+ 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()
@@ -286,17 +337,21 @@ static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_random_value_cc
void register_node_type_fn_random_value()
{
+ namespace file_ns = blender::nodes::node_fn_random_value_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_RANDOM_VALUE, "Random Value", NODE_CLASS_CONVERTER, 0);
- node_type_init(&ntype, blender::nodes::fn_node_random_value_init);
- node_type_update(&ntype, blender::nodes::fn_node_random_value_update);
- ntype.draw_buttons = blender::nodes::fn_node_random_value_layout;
- ntype.declare = blender::nodes::fn_node_random_value_declare;
- ntype.build_multi_function = blender::nodes::fn_node_random_value_build_multi_function;
+
+ fn_node_type_base(&ntype, FN_NODE_RANDOM_VALUE, "Random Value", NODE_CLASS_CONVERTER);
+ node_type_init(&ntype, file_ns::fn_node_random_value_init);
+ node_type_update(&ntype, file_ns::fn_node_random_value_update);
+ ntype.draw_buttons = file_ns::fn_node_random_value_layout;
+ ntype.declare = file_ns::fn_node_random_value_declare;
+ ntype.build_multi_function = file_ns::fn_node_random_value_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::fn_node_random_value_gather_link_search;
node_type_storage(
&ntype, "NodeRandomValue", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/function/nodes/node_fn_replace_string.cc b/source/blender/nodes/function/nodes/node_fn_replace_string.cc
index 881a3c68e7d..afe516a5214 100644
--- a/source/blender/nodes/function/nodes/node_fn_replace_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_replace_string.cc
@@ -18,7 +18,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_replace_string_cc {
static void fn_node_replace_string_declare(NodeDeclarationBuilder &b)
{
@@ -27,7 +27,7 @@ static void fn_node_replace_string_declare(NodeDeclarationBuilder &b)
b.add_input<decl::String>(N_("Replace"))
.description(N_("The string to replace each match with"));
b.add_output<decl::String>(N_("String"));
-};
+}
static std::string replace_all(std::string str, const std::string &from, const std::string &to)
{
@@ -53,14 +53,16 @@ static void fn_node_replace_string_build_multi_function(NodeMultiFunctionBuilder
builder.set_matching_fn(&substring_fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_replace_string_cc
void register_node_type_fn_replace_string()
{
+ namespace file_ns = blender::nodes::node_fn_replace_string_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_REPLACE_STRING, "Replace String", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_replace_string_declare;
- ntype.build_multi_function = blender::nodes::fn_node_replace_string_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_REPLACE_STRING, "Replace String", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_replace_string_declare;
+ ntype.build_multi_function = file_ns::fn_node_replace_string_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
index 7dbc11fb161..3140aeac975 100644
--- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
+++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
@@ -24,7 +24,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_rotate_euler_cc {
static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b)
{
@@ -34,7 +34,7 @@ static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Vector>(N_("Axis")).default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE);
b.add_output<decl::Vector>(N_("Rotation"));
-};
+}
static void fn_node_rotate_euler_update(bNodeTree *ntree, bNode *node)
{
@@ -125,15 +125,18 @@ static void fn_node_rotate_euler_build_multi_function(NodeMultiFunctionBuilder &
builder.set_matching_fn(fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_rotate_euler_cc
void register_node_type_fn_rotate_euler()
{
+ namespace file_ns = blender::nodes::node_fn_rotate_euler_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_ROTATE_EULER, "Rotate Euler", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_rotate_euler_declare;
- ntype.draw_buttons = blender::nodes::fn_node_rotate_euler_layout;
- node_type_update(&ntype, blender::nodes::fn_node_rotate_euler_update);
- ntype.build_multi_function = blender::nodes::fn_node_rotate_euler_build_multi_function;
+
+ fn_node_type_base(&ntype, FN_NODE_ROTATE_EULER, "Rotate Euler", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_rotate_euler_declare;
+ ntype.draw_buttons = file_ns::fn_node_rotate_euler_layout;
+ node_type_update(&ntype, file_ns::fn_node_rotate_euler_update);
+ ntype.build_multi_function = file_ns::fn_node_rotate_euler_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_slice_string.cc b/source/blender/nodes/function/nodes/node_fn_slice_string.cc
index 5cb753e8f34..4055495ec1f 100644
--- a/source/blender/nodes/function/nodes/node_fn_slice_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_slice_string.cc
@@ -18,7 +18,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_slice_string_cc {
static void fn_node_slice_string_declare(NodeDeclarationBuilder &b)
{
@@ -26,7 +26,7 @@ static void fn_node_slice_string_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Int>(N_("Position"));
b.add_input<decl::Int>(N_("Length")).min(0).default_value(10);
b.add_output<decl::String>(N_("String"));
-};
+}
static void fn_node_slice_string_build_multi_function(NodeMultiFunctionBuilder &builder)
{
@@ -40,14 +40,16 @@ static void fn_node_slice_string_build_multi_function(NodeMultiFunctionBuilder &
builder.set_matching_fn(&slice_fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_slice_string_cc
void register_node_type_fn_slice_string()
{
+ namespace file_ns = blender::nodes::node_fn_slice_string_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_SLICE_STRING, "Slice String", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_slice_string_declare;
- ntype.build_multi_function = blender::nodes::fn_node_slice_string_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_SLICE_STRING, "Slice String", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_slice_string_declare;
+ ntype.build_multi_function = file_ns::fn_node_slice_string_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_string_length.cc b/source/blender/nodes/function/nodes/node_fn_string_length.cc
index 63429d35993..bed434c8f2c 100644
--- a/source/blender/nodes/function/nodes/node_fn_string_length.cc
+++ b/source/blender/nodes/function/nodes/node_fn_string_length.cc
@@ -20,13 +20,13 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_string_length_cc {
static void fn_node_string_length_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::String>(N_("String"));
b.add_output<decl::Int>(N_("Length"));
-};
+}
static void fn_node_string_length_build_multi_function(NodeMultiFunctionBuilder &builder)
{
@@ -35,14 +35,16 @@ static void fn_node_string_length_build_multi_function(NodeMultiFunctionBuilder
builder.set_matching_fn(&str_len_fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_string_length_cc
void register_node_type_fn_string_length()
{
+ namespace file_ns = blender::nodes::node_fn_string_length_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_STRING_LENGTH, "String Length", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_string_length_declare;
- ntype.build_multi_function = blender::nodes::fn_node_string_length_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_STRING_LENGTH, "String Length", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_string_length_declare;
+ ntype.build_multi_function = file_ns::fn_node_string_length_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
index 96a56760664..ee0613de9bd 100644
--- a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
@@ -17,14 +17,14 @@
#include "node_function_util.hh"
#include <iomanip>
-namespace blender::nodes {
+namespace blender::nodes::node_fn_value_to_string_cc {
static void fn_node_value_to_string_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Float>(N_("Value"));
b.add_input<decl::Int>(N_("Decimals")).min(0);
b.add_output<decl::String>(N_("String"));
-};
+}
static void fn_node_value_to_string_build_multi_function(NodeMultiFunctionBuilder &builder)
{
@@ -37,14 +37,16 @@ static void fn_node_value_to_string_build_multi_function(NodeMultiFunctionBuilde
builder.set_matching_fn(&to_str_fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_value_to_string_cc
void register_node_type_fn_value_to_string()
{
+ namespace file_ns = blender::nodes::node_fn_value_to_string_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_VALUE_TO_STRING, "Value to String", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_value_to_string_declare;
- ntype.build_multi_function = blender::nodes::fn_node_value_to_string_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_VALUE_TO_STRING, "Value to String", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_value_to_string_declare;
+ ntype.build_multi_function = file_ns::fn_node_value_to_string_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index f9a64381981..b4add633b0c 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -18,7 +18,7 @@
set(INC
.
- ../
+ ..
../intern
../../editors/include
../../blenkernel
@@ -80,6 +80,7 @@ set(SRC
nodes/legacy/node_geo_legacy_subdivision_surface.cc
nodes/legacy/node_geo_legacy_volume_to_mesh.cc
+ nodes/node_geo_accumulate_field.cc
nodes/node_geo_attribute_capture.cc
nodes/node_geo_attribute_domain_size.cc
nodes/node_geo_attribute_remove.cc
@@ -94,6 +95,7 @@ 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_primitive_arc.cc
nodes/node_geo_curve_primitive_bezier_segment.cc
nodes/node_geo_curve_primitive_circle.cc
nodes/node_geo_curve_primitive_line.cc
@@ -105,8 +107,8 @@ set(SRC
nodes/node_geo_curve_reverse.cc
nodes/node_geo_curve_sample.cc
nodes/node_geo_curve_set_handles.cc
- nodes/node_geo_curve_spline_type.cc
nodes/node_geo_curve_spline_parameter.cc
+ nodes/node_geo_curve_spline_type.cc
nodes/node_geo_curve_subdivide.cc
nodes/node_geo_curve_to_mesh.cc
nodes/node_geo_curve_to_points.cc
@@ -115,14 +117,18 @@ set(SRC
nodes/node_geo_distribute_points_on_faces.cc
nodes/node_geo_dual_mesh.cc
nodes/node_geo_edge_split.cc
+ nodes/node_geo_extrude_mesh.cc
+ nodes/node_geo_field_at_index.cc
+ nodes/node_geo_flip_faces.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
nodes/node_geo_input_id.cc
nodes/node_geo_input_index.cc
- nodes/node_geo_input_material_index.cc
nodes/node_geo_input_material.cc
+ nodes/node_geo_input_material_index.cc
+ nodes/node_geo_input_mesh_edge_angle.cc
nodes/node_geo_input_mesh_edge_neighbors.cc
nodes/node_geo_input_mesh_edge_vertices.cc
nodes/node_geo_input_mesh_face_area.cc
@@ -144,6 +150,7 @@ set(SRC
nodes/node_geo_join_geometry.cc
nodes/node_geo_material_replace.cc
nodes/node_geo_material_selection.cc
+ nodes/node_geo_merge_by_distance.cc
nodes/node_geo_mesh_primitive_circle.cc
nodes/node_geo_mesh_primitive_cone.cc
nodes/node_geo_mesh_primitive_cube.cc
@@ -162,6 +169,7 @@ set(SRC
nodes/node_geo_raycast.cc
nodes/node_geo_realize_instances.cc
nodes/node_geo_rotate_instances.cc
+ nodes/node_geo_scale_elements.cc
nodes/node_geo_scale_instances.cc
nodes/node_geo_separate_components.cc
nodes/node_geo_separate_geometry.cc
@@ -169,8 +177,8 @@ set(SRC
nodes/node_geo_set_curve_radius.cc
nodes/node_geo_set_curve_tilt.cc
nodes/node_geo_set_id.cc
- nodes/node_geo_set_material_index.cc
nodes/node_geo_set_material.cc
+ nodes/node_geo_set_material_index.cc
nodes/node_geo_set_point_radius.cc
nodes/node_geo_set_position.cc
nodes/node_geo_set_shade_smooth.cc
@@ -203,7 +211,7 @@ set(LIB
if(WITH_BULLET)
list(APPEND INC_SYS
${BULLET_INCLUDE_DIRS}
- "../../../../intern/rigidbody/"
+ ../../../../intern/rigidbody
)
if(NOT WITH_SYSTEM_BULLET)
list(APPEND LIB
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index 3f4089807bc..a6dec71ed06 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -32,6 +32,8 @@
#include "RNA_access.h"
+#include "UI_resources.h"
+
#include "node_common.h"
bNodeTreeType *ntreeType_Geometry;
@@ -84,15 +86,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),
@@ -120,7 +123,7 @@ void register_node_tree_type_geo()
tt->type = NTREE_GEOMETRY;
strcpy(tt->idname, "GeometryNodeTree");
strcpy(tt->ui_name, N_("Geometry Node Editor"));
- tt->ui_icon = 0; /* Defined in `drawnode.c`. */
+ tt->ui_icon = ICON_NODETREE;
strcpy(tt->ui_description, N_("Geometry nodes"));
tt->rna_ext.srna = &RNA_GeometryNodeTree;
tt->update = geometry_node_tree_update;
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index ebe678c6de8..ceb9a7e1467 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -24,6 +24,8 @@
#include "BKE_mesh_runtime.h"
#include "BKE_pointcloud.h"
+#include "NOD_socket_search_link.hh"
+
namespace blender::nodes {
using bke::GeometryInstanceGroup;
@@ -49,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),
@@ -62,9 +89,10 @@ bool geo_node_poll_default(bNodeType *UNUSED(ntype),
return true;
}
-void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = geo_node_poll_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index cf731427841..dddc3527124 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -18,7 +18,7 @@
#include <string.h>
-#include "BLI_float3.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
@@ -36,8 +36,7 @@
#include "node_util.h"
-void geo_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void geo_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
bool geo_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
@@ -53,11 +52,11 @@ namespace blender::nodes {
void update_attribute_input_socket_availabilities(bNodeTree &ntree,
bNode &node,
const StringRef name,
- const GeometryNodeAttributeInputMode mode,
- const bool name_is_available = true);
+ GeometryNodeAttributeInputMode mode,
+ bool name_is_available = true);
Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
- const AttributeDomain domain);
+ AttributeDomain domain);
void transform_mesh(Mesh &mesh,
const float3 translation,
@@ -68,12 +67,9 @@ void transform_geometry_set(GeometrySet &geometry,
const float4x4 &transform,
const Depsgraph &depsgraph);
-Mesh *create_line_mesh(const float3 start, const float3 delta, const int count);
+Mesh *create_line_mesh(const float3 start, const float3 delta, int count);
-Mesh *create_grid_mesh(const int verts_x,
- const int verts_y,
- const float size_x,
- const float size_y);
+Mesh *create_grid_mesh(int verts_x, int verts_y, float size_x, float size_y);
struct ConeAttributeOutputs {
StrongAnonymousAttributeID top_id;
@@ -81,13 +77,13 @@ struct ConeAttributeOutputs {
StrongAnonymousAttributeID side_id;
};
-Mesh *create_cylinder_or_cone_mesh(const float radius_top,
- const float radius_bottom,
- const float depth,
- const int circle_segments,
- const int side_segments,
- const int fill_segments,
- const GeometryNodeMeshCircleFillType fill_type,
+Mesh *create_cylinder_or_cone_mesh(float radius_top,
+ float radius_bottom,
+ float depth,
+ int circle_segments,
+ int side_segments,
+ int fill_segments,
+ GeometryNodeMeshCircleFillType fill_type,
ConeAttributeOutputs &attribute_outputs);
Mesh *create_cuboid_mesh(float3 size, int verts_x, int verts_y, int verts_z);
@@ -98,17 +94,17 @@ Mesh *create_cuboid_mesh(float3 size, int verts_x, int verts_y, int verts_z);
void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
GeometryComponent &result_component,
Span<bool> masks,
- const bool invert);
+ bool invert);
/**
* Returns the parts of the geometry that are on the selection for the given domain. If the domain
* is not applicable for the component, e.g. face domain for point cloud, nothing happens to that
* component. If no component can work with the domain, then `error_message` is set to true.
*/
void separate_geometry(GeometrySet &geometry_set,
- const AttributeDomain domain,
- const GeometryNodeDeleteGeometryMode mode,
+ AttributeDomain domain,
+ GeometryNodeDeleteGeometryMode mode,
const Field<bool> &selection_field,
- const bool invert,
+ bool invert,
bool &r_is_error);
struct CurveToPointsResults {
@@ -133,4 +129,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_legacy_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
index 4366c6f9234..1d064586238 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
@@ -53,8 +53,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *)
- MEM_callocN(sizeof(NodeGeometryAlignRotationToVector), __func__);
+ NodeGeometryAlignRotationToVector *node_storage = MEM_cnew<NodeGeometryAlignRotationToVector>(
+ __func__);
node_storage->axis = GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_X;
node_storage->input_type_factor = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
@@ -90,14 +90,14 @@ static void align_rotations_auto_pivot(const VArray<float3> &vectors,
float3 old_axis;
mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
- const float3 new_axis = vector.normalized();
- float3 rotation_axis = float3::cross_high_precision(old_axis, new_axis);
+ const float3 new_axis = math::normalize(vector);
+ float3 rotation_axis = math::cross_high_precision(old_axis, new_axis);
if (is_zero_v3(rotation_axis)) {
/* The vectors are linearly dependent, so we fall back to another axis. */
- rotation_axis = float3::cross_high_precision(old_axis, float3(1, 0, 0));
+ rotation_axis = math::cross_high_precision(old_axis, float3(1, 0, 0));
if (is_zero_v3(rotation_axis)) {
/* This is now guaranteed to not be zero. */
- rotation_axis = float3::cross_high_precision(old_axis, float3(0, 1, 0));
+ rotation_axis = math::cross_high_precision(old_axis, float3(0, 1, 0));
}
}
@@ -228,8 +228,7 @@ void register_node_type_geo_align_rotation_to_vector()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ALIGN_ROTATION_TO_VECTOR,
"Align Rotation to Vector",
- NODE_CLASS_GEOMETRY,
- 0);
+ NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
index 7435152a966..cac2a90a76c 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
@@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp),
- __func__);
+ NodeAttributeClamp *data = MEM_cnew<NodeAttributeClamp>(__func__);
data->data_type = CD_PROP_FLOAT;
data->operation = NODE_CLAMP_MINMAX;
node->storage = data;
@@ -271,7 +270,7 @@ void register_node_type_geo_attribute_clamp()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
ntype.declare = file_ns::node_declare;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
index 4efdf786e4e..ec57422a531 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
@@ -23,7 +23,7 @@
#include "node_geometry_util.hh"
-namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc {
+namespace blender::nodes::node_geo_legacy_attribute_color_ramp_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
@@ -40,8 +40,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN(
- sizeof(NodeAttributeColorRamp), __func__);
+ NodeAttributeColorRamp *node_storage = MEM_cnew<NodeAttributeColorRamp>(__func__);
BKE_colorband_init(&node_storage->color_ramp, true);
node->storage = node_storage;
}
@@ -117,19 +116,16 @@ static void node_geo_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
}
-} // namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc
+} // namespace blender::nodes::node_geo_legacy_attribute_color_ramp_cc
void register_node_type_geo_attribute_color_ramp()
{
- namespace file_ns = blender::nodes::node_geo_legacy_attributes_color_ramp_cc;
+ namespace file_ns = blender::nodes::node_geo_legacy_attribute_color_ramp_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype,
- GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP,
- "Attribute Color Ramp",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ geo_node_type_base(
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP, "Attribute Color Ramp", NODE_CLASS_ATTRIBUTE);
node_type_storage(
&ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage);
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
index 7ba64c8db2b..403b9446f75 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
@@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeCombineXYZ *data = (NodeAttributeCombineXYZ *)MEM_callocN(
- sizeof(NodeAttributeCombineXYZ), __func__);
+ NodeAttributeCombineXYZ *data = MEM_cnew<NodeAttributeCombineXYZ>(__func__);
data->input_type_x = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
data->input_type_y = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
@@ -139,8 +138,7 @@ void register_node_type_geo_attribute_combine_xyz()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ,
"Attribute Combine XYZ",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
index 8aa1adb0cf3..6cec73d76a2 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare),
- __func__);
+ NodeAttributeCompare *data = MEM_cnew<NodeAttributeCompare>(__func__);
data->operation = NODE_COMPARE_GREATER_THAN;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
@@ -348,7 +347,7 @@ void register_node_type_geo_attribute_compare()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
index 28c133871f7..2b13f57e990 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
@@ -39,8 +39,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeConvert *data = (NodeAttributeConvert *)MEM_callocN(sizeof(NodeAttributeConvert),
- __func__);
+ NodeAttributeConvert *data = MEM_cnew<NodeAttributeConvert>(__func__);
data->data_type = CD_AUTO_FROM_NAME;
data->domain = ATTR_DOMAIN_AUTO;
@@ -182,7 +181,7 @@ void register_node_type_geo_attribute_convert()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
index 0a7b5dd8463..8e1e763f1ad 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
@@ -75,8 +75,7 @@ static void node_copy_storage(bNodeTree *UNUSED(dest_ntree),
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)MEM_callocN(sizeof(NodeAttributeCurveMap),
- __func__);
+ NodeAttributeCurveMap *data = MEM_cnew<NodeAttributeCurveMap>(__func__);
data->data_type = CD_PROP_FLOAT;
data->curve_vec = BKE_curvemapping_add(4, -1.0f, -1.0f, 1.0f, 1.0f);
@@ -210,7 +209,7 @@ void register_node_type_geo_attribute_curve_map()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE);
node_type_update(&ntype, file_ns::node_update);
node_type_init(&ntype, file_ns::node_init);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc
index a05bcf1bed8..a32e3b7412f 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc
@@ -155,7 +155,7 @@ void register_node_type_geo_attribute_fill()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
index 8ebcf34ad0b..398af087499 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
@@ -51,8 +51,7 @@ static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C),
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange),
- __func__);
+ NodeAttributeMapRange *data = MEM_cnew<NodeAttributeMapRange>(__func__);
data->data_type = CD_PROP_FLOAT;
data->interpolation_type = NODE_MAP_RANGE_LINEAR;
@@ -425,7 +424,7 @@ void register_node_type_geo_attribute_map_range()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE);
ntype.geometry_node_execute = file_ns::node_geo_exec;
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
index e0a829b4100..3257d2d7358 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
@@ -121,7 +121,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), __func__);
+ NodeAttributeMath *data = MEM_cnew<NodeAttributeMath>(__func__);
data->operation = NODE_MATH_ADD;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
@@ -309,7 +309,7 @@ void register_node_type_geo_attribute_math()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
index 4a110e9690a..c0c30898584 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
@@ -61,8 +61,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeMix *data = (NodeAttributeMix *)MEM_callocN(sizeof(NodeAttributeMix),
- "attribute mix node");
+ NodeAttributeMix *data = MEM_cnew<NodeAttributeMix>("attribute mix node");
data->blend_type = MA_RAMP_BLEND;
data->input_type_factor = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
@@ -248,8 +247,7 @@ void register_node_type_geo_attribute_mix()
namespace file_ns = blender::nodes::node_geo_legacy_attribute_mix_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE, 0);
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
ntype.declare = file_ns::node_declare;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
index 080bf38a740..20f500b1bd8 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
@@ -44,8 +44,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN(
- sizeof(NodeGeometryAttributeProximity), __func__);
+ NodeGeometryAttributeProximity *node_storage = MEM_cnew<NodeGeometryAttributeProximity>(
+ __func__);
node_storage->target_geometry_element = GEO_NODE_PROXIMITY_TARGET_FACES;
node->storage = node_storage;
@@ -81,7 +81,7 @@ static void calculate_mesh_proximity(const VArray<float3> &positions,
for (int i : range) {
/* Use the distance to the last found point as upper bound to speedup the bvh lookup. */
- nearest.dist_sq = float3::distance_squared(nearest.co, positions[i]);
+ nearest.dist_sq = math::distance_squared(float3(nearest.co), positions[i]);
BLI_bvhtree_find_nearest(
bvh_data.tree, positions[i], &nearest, bvh_data.nearest_callback, &bvh_data);
@@ -237,7 +237,7 @@ void register_node_type_geo_legacy_attribute_proximity()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryAttributeProximity",
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
index ab2bc7b379c..92a946b225b 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
@@ -81,8 +81,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN(
- sizeof(NodeAttributeRandomize), __func__);
+ NodeAttributeRandomize *data = MEM_cnew<NodeAttributeRandomize>(__func__);
data->data_type = CD_PROP_FLOAT;
data->domain = ATTR_DOMAIN_POINT;
data->operation = GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE;
@@ -335,7 +334,7 @@ void register_node_type_geo_legacy_attribute_randomize()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
index bc18cb32e73..ae034d152be 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
@@ -130,8 +130,7 @@ void register_node_type_geo_sample_texture()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE,
"Attribute Sample Texture",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ NODE_CLASS_ATTRIBUTE);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
index c5aac118baf..960ec540556 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
@@ -41,8 +41,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeSeparateXYZ *data = (NodeAttributeSeparateXYZ *)MEM_callocN(
- sizeof(NodeAttributeSeparateXYZ), __func__);
+ NodeAttributeSeparateXYZ *data = MEM_cnew<NodeAttributeSeparateXYZ>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
}
@@ -160,8 +159,7 @@ void register_node_type_geo_attribute_separate_xyz()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ,
"Attribute Separate XYZ",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ NODE_CLASS_ATTRIBUTE);
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
index 686edc80f62..a85a7c56cb9 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryAttributeTransfer *data = (NodeGeometryAttributeTransfer *)MEM_callocN(
- sizeof(NodeGeometryAttributeTransfer), __func__);
+ NodeGeometryAttributeTransfer *data = MEM_cnew<NodeGeometryAttributeTransfer>(__func__);
data->domain = ATTR_DOMAIN_AUTO;
node->storage = data;
}
@@ -230,7 +229,7 @@ static void get_closest_mesh_corners(const Mesh &mesh,
const MLoop &loop = mesh.mloop[loop_index];
const int vertex_index = loop.v;
const MVert &mvert = mesh.mvert[vertex_index];
- const float distance_sq = float3::distance_squared(position, mvert.co);
+ const float distance_sq = math::distance_squared(position, float3(mvert.co));
if (distance_sq < min_distance_sq) {
min_distance_sq = distance_sq;
closest_loop_index = loop_index;
@@ -517,7 +516,7 @@ void register_node_type_geo_legacy_attribute_transfer()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryAttributeTransfer",
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
index 68051e81f57..5b3c3c05a6a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
@@ -103,8 +103,7 @@ static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation op
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeVectorMath *data = (NodeAttributeVectorMath *)MEM_callocN(
- sizeof(NodeAttributeVectorMath), __func__);
+ NodeAttributeVectorMath *data = MEM_cnew<NodeAttributeVectorMath>(__func__);
data->operation = NODE_VECTOR_MATH_ADD;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
@@ -560,8 +559,7 @@ void register_node_type_geo_attribute_vector_math()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_MATH,
"Attribute Vector Math",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ NODE_CLASS_ATTRIBUTE);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
index 1ef50e69775..3738c4ad14d 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
@@ -112,8 +112,7 @@ static float3 vector_rotate_around_axis(const float3 vector,
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)MEM_callocN(
- sizeof(NodeAttributeVectorRotate), __func__);
+ NodeAttributeVectorRotate *node_storage = MEM_cnew<NodeAttributeVectorRotate>(__func__);
node_storage->mode = GEO_NODE_VECTOR_ROTATE_TYPE_AXIS;
node_storage->input_type_vector = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
@@ -337,8 +336,7 @@ void register_node_type_geo_attribute_vector_rotate()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE,
"Attribute Vector Rotate",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ NODE_CLASS_ATTRIBUTE);
node_type_update(&ntype, file_ns::node_update);
node_type_init(&ntype, file_ns::node_init);
node_type_size(&ntype, 165, 100, 600);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
index e61dee4bee1..51564d8d200 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
@@ -213,7 +213,7 @@ void register_node_type_geo_legacy_curve_endpoints()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
index 7c550495b41..844baa53962 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
@@ -65,8 +65,7 @@ void register_node_type_geo_legacy_curve_reverse()
namespace file_ns = blender::nodes::node_geo_legacy_curve_reverse_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
index c702e9ff686..780756bcbca 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
@@ -40,8 +40,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSelectHandles), __func__);
+ NodeGeometryCurveSelectHandles *data = MEM_cnew<NodeGeometryCurveSelectHandles>(__func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
@@ -127,11 +126,8 @@ void register_node_type_geo_legacy_select_by_handle_type()
static bNodeType ntype;
- geo_node_type_base(&ntype,
- GEO_NODE_LEGACY_CURVE_SELECT_HANDLES,
- "Select by Handle Type",
- NODE_CLASS_GEOMETRY,
- 0);
+ geo_node_type_base(
+ &ntype, GEO_NODE_LEGACY_CURVE_SELECT_HANDLES, "Select by Handle Type", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
index 1e476d01148..a82b917e817 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
@@ -38,8 +38,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSetHandles), __func__);
+ NodeGeometryCurveSetHandles *data = MEM_cnew<NodeGeometryCurveSetHandles>(__func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
@@ -130,7 +129,7 @@ void register_node_type_geo_legacy_curve_set_handles()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_decalre;
ntype.geometry_node_execute = file_ns::node_geo_exec;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
index f3599f4328f..6fd82e6a1bb 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
@@ -39,8 +39,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
- sizeof(NodeGeometryCurveSplineType), __func__);
+ NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
node->storage = data;
@@ -288,7 +287,7 @@ void register_node_type_geo_legacy_curve_spline_type()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
index 9878402dd35..4621a1656aa 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
@@ -44,8 +44,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN(
- sizeof(NodeGeometryCurveSubdivide), __func__);
+ NodeGeometryCurveSubdivide *data = MEM_cnew<NodeGeometryCurveSubdivide>(__func__);
data->cuts_type = GEO_NODE_ATTRIBUTE_INPUT_INTEGER;
node->storage = data;
@@ -379,7 +378,7 @@ void register_node_type_geo_legacy_curve_subdivide()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_layout;
node_type_storage(&ntype,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
index 3bd03f3cee0..1e6b7f92a77 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
@@ -95,8 +95,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
- sizeof(NodeGeometryCurveToPoints), __func__);
+ NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__);
data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
node->storage = data;
@@ -242,13 +241,13 @@ static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines,
spline.sample_with_index_factors<float3>(
spline.evaluated_tangents(), uniform_samples, data.tangents.slice(offset, size));
for (float3 &tangent : data.tangents) {
- tangent.normalize();
+ tangent = math::normalize(tangent);
}
spline.sample_with_index_factors<float3>(
spline.evaluated_normals(), uniform_samples, data.normals.slice(offset, size));
for (float3 &normals : data.normals) {
- normals.normalize();
+ normals = math::normalize(normals);
}
}
});
@@ -353,7 +352,7 @@ void register_node_type_geo_legacy_curve_to_points()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
index abd75e710ae..f7fd12d775a 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
@@ -26,25 +26,10 @@
#include "node_geometry_util.hh"
-using blender::bke::CustomDataAttributes;
-
-/* Code from the mask modifier in MOD_mask.cc. */
-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 {
+using blender::bke::CustomDataAttributes;
+
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
@@ -60,6 +45,78 @@ template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data,
}
}
+static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map)
+{
+ BLI_assert(src_mesh.totvert == vertex_map.size());
+ for (const int i_src : vertex_map.index_range()) {
+ const int i_dst = vertex_map[i_src];
+ if (i_dst == -1) {
+ continue;
+ }
+
+ const MVert &v_src = src_mesh.mvert[i_src];
+ MVert &v_dst = dst_mesh.mvert[i_dst];
+
+ v_dst = v_src;
+ CustomData_copy_data(&src_mesh.vdata, &dst_mesh.vdata, i_src, i_dst, 1);
+ }
+}
+
+static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map,
+ Span<int> edge_map)
+{
+ BLI_assert(src_mesh.totvert == vertex_map.size());
+ BLI_assert(src_mesh.totedge == edge_map.size());
+ for (const int i_src : IndexRange(src_mesh.totedge)) {
+ const int i_dst = edge_map[i_src];
+ if (ELEM(i_dst, -1, -2)) {
+ continue;
+ }
+
+ const MEdge &e_src = src_mesh.medge[i_src];
+ MEdge &e_dst = dst_mesh.medge[i_dst];
+
+ CustomData_copy_data(&src_mesh.edata, &dst_mesh.edata, i_src, i_dst, 1);
+ e_dst = e_src;
+ e_dst.v1 = vertex_map[e_src.v1];
+ e_dst.v2 = vertex_map[e_src.v2];
+ }
+}
+
+static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ Span<int> vertex_map,
+ Span<int> edge_map,
+ Span<int> masked_poly_indices,
+ Span<int> new_loop_starts)
+{
+ for (const int i_dst : masked_poly_indices.index_range()) {
+ const int i_src = masked_poly_indices[i_dst];
+
+ const MPoly &mp_src = src_mesh.mpoly[i_src];
+ MPoly &mp_dst = dst_mesh.mpoly[i_dst];
+ const int i_ml_src = mp_src.loopstart;
+ const int i_ml_dst = new_loop_starts[i_dst];
+
+ CustomData_copy_data(&src_mesh.pdata, &dst_mesh.pdata, i_src, i_dst, 1);
+ CustomData_copy_data(&src_mesh.ldata, &dst_mesh.ldata, i_ml_src, i_ml_dst, mp_src.totloop);
+
+ const MLoop *ml_src = src_mesh.mloop + i_ml_src;
+ MLoop *ml_dst = dst_mesh.mloop + i_ml_dst;
+
+ mp_dst = mp_src;
+ mp_dst.loopstart = i_ml_dst;
+ for (int i : IndexRange(mp_src.totloop)) {
+ ml_dst[i].v = vertex_map[ml_src[i].v];
+ ml_dst[i].e = edge_map[ml_src[i].e];
+ }
+ }
+}
+
static void spline_copy_builtin_attributes(const Spline &spline,
Spline &r_spline,
const IndexMask mask)
@@ -671,7 +728,7 @@ void register_node_type_geo_legacy_delete_geometry()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc
index c046fda4686..e628edb7e17 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc
@@ -84,7 +84,7 @@ void register_node_type_geo_legacy_edge_split()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc
index 88e8374f5d6..8fd6b1e299f 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc
@@ -90,7 +90,7 @@ void register_node_type_geo_legacy_material_assign()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
index 2ff7410f3f6..d026fff003f 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
@@ -73,8 +73,7 @@ void register_node_type_geo_legacy_mesh_to_curve()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc
index 2451a7447ec..29eff373d15 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc
@@ -321,7 +321,7 @@ BLI_NOINLINE static void interpolate_existing_attributes(
continue;
}
- for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
+ for ([[maybe_unused]] const int i_set_instance : set_group.transforms.index_range()) {
const int offset = instance_start_offsets[i_instance];
Span<float3> bary_coords = bary_coords_array[i_instance];
Span<int> looptri_indices = looptri_indices_array[i_instance];
@@ -516,7 +516,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group
const VArray<float> density_factors = component.attribute_get_for_read<float>(
density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
- for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
+ for ([[maybe_unused]] const int i_set_instance : set_group.transforms.index_range()) {
Vector<float3> &positions = positions_all[i_instance];
Vector<float3> &bary_coords = bary_coords_all[i_instance];
Vector<int> &looptri_indices = looptri_indices_all[i_instance];
@@ -662,7 +662,7 @@ void register_node_type_geo_point_distribute()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY);
node_type_update(&ntype, file_ns::node_point_distribute_update);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
index 8915a58feb1..faf0b1a5fe7 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
@@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN(
- sizeof(NodeGeometryPointInstance), __func__);
+ NodeGeometryPointInstance *data = MEM_cnew<NodeGeometryPointInstance>(__func__);
data->instance_type = GEO_NODE_POINT_INSTANCE_TYPE_OBJECT;
data->flag |= GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION;
node->storage = data;
@@ -271,7 +270,7 @@ void register_node_type_geo_point_instance()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryPointInstance", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
index a0a7674797a..ad87ec5541b 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
@@ -59,8 +59,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN(
- sizeof(NodeGeometryRotatePoints), __func__);
+ NodeGeometryRotatePoints *node_storage = MEM_cnew<NodeGeometryRotatePoints>(__func__);
node_storage->type = GEO_NODE_POINT_ROTATE_TYPE_EULER;
node_storage->space = GEO_NODE_POINT_ROTATE_SPACE_OBJECT;
@@ -226,7 +225,7 @@ void register_node_type_geo_point_rotate()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
index d38df124979..69e69a24e29 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
@@ -43,8 +43,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointScale *data = (NodeGeometryPointScale *)MEM_callocN(
- sizeof(NodeGeometryPointScale), __func__);
+ NodeGeometryPointScale *data = MEM_cnew<NodeGeometryPointScale>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node->storage = data;
@@ -128,7 +127,7 @@ void register_node_type_geo_point_scale()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc
index 9260928b311..b9760587706 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc
@@ -171,7 +171,7 @@ void register_node_type_geo_point_separate()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.geometry_node_execute_supports_laziness = true;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
index c70478182ec..385c3d9f22d 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
@@ -74,8 +74,7 @@ static void node_geo_exec(GeoNodeExecParams params)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointTranslate *data = (NodeGeometryPointTranslate *)MEM_callocN(
- sizeof(NodeGeometryPointTranslate), __func__);
+ NodeGeometryPointTranslate *data = MEM_cnew<NodeGeometryPointTranslate>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node->storage = data;
@@ -98,7 +97,7 @@ void register_node_type_geo_point_translate()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
index ec1ab67b530..f54ffc53a6e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
@@ -51,8 +51,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
- sizeof(NodeGeometryPointsToVolume), __func__);
+ NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__);
data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
data->input_type_radius = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
node->storage = data;
@@ -162,7 +161,7 @@ static float compute_voxel_size(const GeoNodeExecParams &params,
}
/* The voxel size adapts to the final size of the volume. */
- const float diagonal = float3::distance(min, max);
+ const float diagonal = math::distance(min, max);
const float extended_diagonal = diagonal + 2.0f * radius;
const float voxel_size = extended_diagonal / voxel_amount;
return voxel_size;
@@ -266,7 +265,7 @@ void register_node_type_geo_legacy_points_to_volume()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY);
node_type_storage(&ntype,
"NodeGeometryPointsToVolume",
node_free_standard_storage,
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
index 599ffd617a5..cfae88e0625 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
@@ -58,8 +58,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
- __func__);
+ NodeGeometryRaycast *data = MEM_cnew<NodeGeometryRaycast>(__func__);
data->input_type_ray_direction = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
data->input_type_ray_length = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
node->storage = data;
@@ -108,7 +107,7 @@ static void raycast_to_mesh(const Mesh &mesh,
for (const int i : ray_origins.index_range()) {
const float ray_length = ray_lengths[i];
const float3 ray_origin = ray_origins[i];
- const float3 ray_direction = ray_directions[i].normalized();
+ const float3 ray_direction = math::normalize(ray_directions[i]);
BVHTreeRayHit hit;
hit.index = -1;
@@ -315,7 +314,7 @@ void register_node_type_geo_legacy_raycast()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc
index b61ba5ff67e..59ac697b658 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc
@@ -87,7 +87,7 @@ void register_node_type_geo_legacy_select_by_material()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
index 819ffb2c20c..7c5553cb5e4 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
@@ -47,8 +47,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN(
- sizeof(NodeGeometrySubdivisionSurface), __func__);
+ NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__);
data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL;
node->storage = data;
@@ -133,7 +132,7 @@ void register_node_type_geo_legacy_subdivision_surface()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
index acff0be7126..42fbc49ed4b 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
@@ -57,8 +57,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
- sizeof(NodeGeometryVolumeToMesh), __func__);
+ NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density");
@@ -164,7 +163,7 @@ void register_node_type_geo_legacy_volume_to_mesh()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
node_type_storage(
&ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
new file mode 100644
index 00000000000..6c2e72cf14f
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
@@ -0,0 +1,430 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_attribute_math.hh"
+
+#include "NOD_socket_search_link.hh"
+
+#include "node_geometry_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_geo_accumulate_field_cc {
+
+NODE_STORAGE_FUNCS(NodeAccumulateField)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ std::string value_in_description = "The values to be accumulated";
+ std::string leading_out_description =
+ "The running total of values in the corresponding group, starting at the first value";
+ std::string trailing_out_description =
+ "The running total of values in the corresponding group, starting at zero";
+ std::string total_out_description = "The total of all of the values in the corresponding group";
+
+ b.add_input<decl::Vector>(N_("Value"), "Value Vector")
+ .default_value({1.0f, 1.0f, 1.0f})
+ .supports_field()
+ .description(N_(value_in_description));
+ b.add_input<decl::Float>(N_("Value"), "Value Float")
+ .default_value(1.0f)
+ .supports_field()
+ .description(N_(value_in_description));
+ b.add_input<decl::Int>(N_("Value"), "Value Int")
+ .default_value(1)
+ .supports_field()
+ .description(N_(value_in_description));
+ b.add_input<decl::Int>(N_("Group Index"))
+ .supports_field()
+ .description(
+ N_("An index used to group values together for multiple separate accumulations"));
+
+ b.add_output<decl::Vector>(N_("Leading"), "Leading Vector")
+ .field_source()
+ .description(N_(leading_out_description));
+ b.add_output<decl::Float>(N_("Leading"), "Leading Float")
+ .field_source()
+ .description(N_(leading_out_description));
+ b.add_output<decl::Int>(N_("Leading"), "Leading Int")
+ .field_source()
+ .description(N_(leading_out_description));
+
+ b.add_output<decl::Vector>(N_("Trailing"), "Trailing Vector")
+ .field_source()
+ .description(N_(trailing_out_description));
+ b.add_output<decl::Float>(N_("Trailing"), "Trailing Float")
+ .field_source()
+ .description(N_(trailing_out_description));
+ b.add_output<decl::Int>(N_("Trailing"), "Trailing Int")
+ .field_source()
+ .description(N_(trailing_out_description));
+
+ b.add_output<decl::Vector>(N_("Total"), "Total Vector")
+ .field_source()
+ .description(N_(total_out_description));
+ b.add_output<decl::Float>(N_("Total"), "Total Float")
+ .field_source()
+ .description(N_(total_out_description));
+ b.add_output<decl::Int>(N_("Total"), "Total Int")
+ .field_source()
+ .description(N_(total_out_description));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeAccumulateField *data = MEM_cnew<NodeAccumulateField>(__func__);
+ data->data_type = CD_PROP_FLOAT;
+ data->domain = ATTR_DOMAIN_POINT;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeAccumulateField &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+
+ bNodeSocket *sock_in_vector = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *sock_in_float = sock_in_vector->next;
+ bNodeSocket *sock_in_int = sock_in_float->next;
+
+ bNodeSocket *sock_out_vector = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *sock_out_float = sock_out_vector->next;
+ bNodeSocket *sock_out_int = sock_out_float->next;
+
+ bNodeSocket *sock_out_first_vector = sock_out_int->next;
+ bNodeSocket *sock_out_first_float = sock_out_first_vector->next;
+ bNodeSocket *sock_out_first_int = sock_out_first_float->next;
+ bNodeSocket *sock_out_total_vector = sock_out_first_int->next;
+ bNodeSocket *sock_out_total_float = sock_out_total_vector->next;
+ bNodeSocket *sock_out_total_int = sock_out_total_float->next;
+
+ nodeSetSocketAvailability(ntree, sock_in_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_in_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_in_int, data_type == CD_PROP_INT32);
+
+ nodeSetSocketAvailability(ntree, sock_out_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_int, data_type == CD_PROP_INT32);
+
+ nodeSetSocketAvailability(ntree, sock_out_first_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_first_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_first_int, data_type == CD_PROP_INT32);
+
+ nodeSetSocketAvailability(ntree, sock_out_total_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_total_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_total_int, data_type == CD_PROP_INT32);
+}
+
+enum class AccumulationMode { Leading = 0, Trailing = 1 };
+
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ return CD_PROP_FLOAT3;
+ default:
+ return {};
+ }
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+ if (params.in_out() == SOCK_OUT) {
+ params.add_item(
+ IFACE_("Leading"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Leading");
+ },
+ 0);
+ params.add_item(
+ IFACE_("Trailing"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Trailing");
+ },
+ -1);
+ params.add_item(
+ IFACE_("Total"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Total");
+ },
+ -2);
+ }
+ else {
+ params.add_item(
+ IFACE_("Value"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ },
+ 0);
+
+ params.add_item(
+ IFACE_("Group Index"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Group Index");
+ },
+ -1);
+ }
+}
+
+template<typename T> class AccumulateFieldInput final : public GeometryFieldInput {
+ private:
+ Field<T> input_;
+ Field<int> group_index_;
+ AttributeDomain source_domain_;
+ AccumulationMode accumulation_mode_;
+
+ public:
+ AccumulateFieldInput(const AttributeDomain source_domain,
+ Field<T> input,
+ Field<int> group_index,
+ AccumulationMode accumulation_mode)
+ : GeometryFieldInput(CPPType::get<T>(), "Accumulation"),
+ input_(input),
+ group_index_(group_index),
+ source_domain_(source_domain),
+ accumulation_mode_(accumulation_mode)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ const GeometryComponentFieldContext field_context{component, source_domain_};
+ const int domain_size = component.attribute_domain_size(field_context.domain());
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(input_);
+ evaluator.add(group_index_);
+ evaluator.evaluate();
+ const VArray<T> &values = evaluator.get_evaluated<T>(0);
+ const VArray<int> &group_indices = evaluator.get_evaluated<int>(1);
+
+ Array<T> accumulations_out(domain_size);
+
+ if (group_indices.is_single()) {
+ T accumulation = T();
+ if (accumulation_mode_ == AccumulationMode::Leading) {
+ for (const int i : values.index_range()) {
+ accumulation = values[i] + accumulation;
+ accumulations_out[i] = accumulation;
+ }
+ }
+ else {
+ for (const int i : values.index_range()) {
+ accumulations_out[i] = accumulation;
+ accumulation = values[i] + accumulation;
+ }
+ }
+ }
+ else {
+ Map<int, T> accumulations;
+ if (accumulation_mode_ == AccumulationMode::Leading) {
+ for (const int i : values.index_range()) {
+ T &accumulation_value = accumulations.lookup_or_add_default(group_indices[i]);
+ accumulation_value += values[i];
+ accumulations_out[i] = accumulation_value;
+ }
+ }
+ else {
+ for (const int i : values.index_range()) {
+ T &accumulation_value = accumulations.lookup_or_add_default(group_indices[i]);
+ accumulations_out[i] = accumulation_value;
+ accumulation_value += values[i];
+ }
+ }
+ }
+
+ return component.attribute_try_adapt_domain<T>(
+ VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash_4(input_, group_index_, source_domain_, accumulation_mode_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const AccumulateFieldInput *other_accumulate = dynamic_cast<const AccumulateFieldInput *>(
+ &other)) {
+ return input_ == other_accumulate->input_ &&
+ group_index_ == other_accumulate->group_index_ &&
+ source_domain_ == other_accumulate->source_domain_ &&
+ accumulation_mode_ == other_accumulate->accumulation_mode_;
+ }
+ return false;
+ }
+};
+
+template<typename T> class TotalFieldInput final : public GeometryFieldInput {
+ private:
+ Field<T> input_;
+ Field<int> group_index_;
+ AttributeDomain source_domain_;
+
+ public:
+ TotalFieldInput(const AttributeDomain source_domain, Field<T> input, Field<int> group_index)
+ : GeometryFieldInput(CPPType::get<T>(), "Total Value"),
+ input_(input),
+ group_index_(group_index),
+ source_domain_(source_domain)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ const GeometryComponentFieldContext field_context{component, source_domain_};
+ const int domain_size = component.attribute_domain_size(field_context.domain());
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(input_);
+ evaluator.add(group_index_);
+ evaluator.evaluate();
+ const VArray<T> &values = evaluator.get_evaluated<T>(0);
+ const VArray<int> &group_indices = evaluator.get_evaluated<int>(1);
+
+ if (group_indices.is_single()) {
+ T accumulation = T();
+ for (const int i : values.index_range()) {
+ accumulation = values[i] + accumulation;
+ }
+ return VArray<T>::ForSingle(accumulation, domain_size);
+ }
+
+ Array<T> accumulations_out(domain_size);
+ Map<int, T> accumulations;
+ for (const int i : values.index_range()) {
+ T &value = accumulations.lookup_or_add_default(group_indices[i]);
+ value = value + values[i];
+ }
+ for (const int i : values.index_range()) {
+ accumulations_out[i] = accumulations.lookup(group_indices[i]);
+ }
+
+ return component.attribute_try_adapt_domain<T>(
+ VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash_3(input_, group_index_, source_domain_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const TotalFieldInput *other_field = dynamic_cast<const TotalFieldInput *>(&other)) {
+ return input_ == other_field->input_ && group_index_ == other_field->group_index_ &&
+ source_domain_ == other_field->source_domain_;
+ }
+ return false;
+ }
+};
+
+template<typename T> std::string identifier_suffix()
+{
+ if constexpr (std::is_same_v<T, int>) {
+ return "Int";
+ }
+ if constexpr (std::is_same_v<T, float>) {
+ return "Float";
+ }
+ if constexpr (std::is_same_v<T, float3>) {
+ return "Vector";
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeAccumulateField &storage = node_storage(params.node());
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const AttributeDomain source_domain = static_cast<AttributeDomain>(storage.domain);
+
+ Field<int> group_index_field = params.extract_input<Field<int>>("Group Index");
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (std::is_same_v<T, int> || std::is_same_v<T, float> ||
+ std::is_same_v<T, float3>) {
+ const std::string suffix = " " + identifier_suffix<T>();
+ Field<T> input_field = params.extract_input<Field<T>>("Value" + suffix);
+ if (params.output_is_required("Leading" + suffix)) {
+ params.set_output(
+ "Leading" + suffix,
+ Field<T>{std::make_shared<AccumulateFieldInput<T>>(
+ source_domain, input_field, group_index_field, AccumulationMode::Leading)});
+ }
+ if (params.output_is_required("Trailing" + suffix)) {
+ params.set_output(
+ "Trailing" + suffix,
+ Field<T>{std::make_shared<AccumulateFieldInput<T>>(
+ source_domain, input_field, group_index_field, AccumulationMode::Trailing)});
+ }
+ if (params.output_is_required("Total" + suffix)) {
+ params.set_output("Total" + suffix,
+ Field<T>{std::make_shared<TotalFieldInput<T>>(
+ source_domain, input_field, group_index_field)});
+ }
+ }
+ });
+}
+} // namespace blender::nodes::node_geo_accumulate_field_cc
+
+void register_node_type_geo_accumulate_field()
+{
+ namespace file_ns = blender::nodes::node_geo_accumulate_field_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_ACCUMULATE_FIELD, "Accumulate Field", NODE_CLASS_CONVERTER);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ node_type_storage(
+ &ntype, "NodeAccumulateField", node_free_standard_storage, node_copy_standard_storage);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
index cf20ddacca7..840dfd2fbd3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -19,6 +19,8 @@
#include "BKE_attribute_math.hh"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_attribute_capture_cc {
@@ -46,14 +48,13 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
}
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryAttributeCapture *data = (NodeGeometryAttributeCapture *)MEM_callocN(
- sizeof(NodeGeometryAttributeCapture), __func__);
+ NodeGeometryAttributeCapture *data = MEM_cnew<NodeGeometryAttributeCapture>(__func__);
data->data_type = CD_PROP_FLOAT;
data->domain = ATTR_DOMAIN_POINT;
@@ -92,6 +93,33 @@ static void node_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,
@@ -206,7 +234,7 @@ void register_node_type_geo_attribute_capture()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CAPTURE_ATTRIBUTE, "Capture Attribute", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_CAPTURE_ATTRIBUTE, "Capture Attribute", NODE_CLASS_ATTRIBUTE);
node_type_storage(&ntype,
"NodeGeometryAttributeCapture",
node_free_standard_storage,
@@ -216,5 +244,6 @@ void register_node_type_geo_attribute_capture()
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
index 082ea87853e..609ef39eb3f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
@@ -24,12 +24,24 @@ 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");
- b.add_output<decl::Int>("Edge Count");
- b.add_output<decl::Int>("Face Count");
- b.add_output<decl::Int>("Face Corner Count");
- b.add_output<decl::Int>("Spline Count");
- b.add_output<decl::Int>("Instance Count");
+ 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)
@@ -131,8 +143,7 @@ void register_node_type_geo_attribute_domain_size()
namespace file_ns = blender::nodes::node_geo_attribute_domain_size_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, "Domain Size", NODE_CLASS_ATTRIBUTE, 0);
+ geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, "Domain Size", NODE_CLASS_ATTRIBUTE);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_layout;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
index 6f26b2c756b..8ed50b2cc75 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
@@ -74,8 +74,7 @@ void register_node_type_geo_attribute_remove()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE, 0);
+ geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
index c754f70d323..7df032b150b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -22,6 +22,8 @@
#include "BLI_math_base_safe.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_attribute_statistic_cc {
@@ -112,6 +114,51 @@ static void node_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 NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(2));
+
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+
+ if (params.in_out() == SOCK_IN) {
+ params.add_item(IFACE_("Attribute"), [node_type, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node.custom1 = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
+ }
+ else {
+ for (const StringRefNull name :
+ {"Mean", "Median", "Sum", "Min", "Max", "Range", "Standard Deviation", "Variance"}) {
+ params.add_item(IFACE_(name.c_str()), [node_type, name, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node.custom1 = *type;
+ 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());
@@ -352,12 +399,13 @@ void register_node_type_geo_attribute_statistic()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE);
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::node_init);
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 0947632cc09..a9158e0ef7a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -127,7 +127,7 @@ void register_node_type_geo_boolean()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_layout;
ntype.updatefunc = file_ns::node_update;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
index da1f9a00c69..465bd72b57a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
@@ -86,7 +86,7 @@ void register_node_type_geo_bounding_box()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
index 6b8c895879d..43816b8d8dc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
@@ -51,8 +51,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCollectionInfo *data = (NodeGeometryCollectionInfo *)MEM_callocN(
- sizeof(NodeGeometryCollectionInfo), __func__);
+ NodeGeometryCollectionInfo *data = MEM_cnew<NodeGeometryCollectionInfo>(__func__);
data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
node->storage = data;
}
@@ -163,7 +162,7 @@ void register_node_type_geo_collection_info()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::node_node_init);
node_type_storage(&ntype,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc
index 64b7a80bdb4..093b4450657 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_common.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc
@@ -26,7 +26,7 @@ void register_node_type_geo_group()
{
static bNodeType ntype;
- node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", NODE_CLASS_GROUP, 0);
+ node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", NODE_CLASS_GROUP);
ntype.type = NODE_GROUP;
ntype.poll = geo_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
@@ -35,7 +35,6 @@ void register_node_type_geo_group()
BLI_assert(ntype.rna_ext.srna != nullptr);
RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
- node_type_socket_templates(&ntype, nullptr, nullptr);
node_type_size(&ntype, 140, 60, 400);
ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index 56c1e95bd70..11bb8a61df5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -324,7 +324,7 @@ void register_node_type_geo_convex_hull()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
index fc407414667..666100ffd7f 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,7 +21,7 @@
#include "node_geometry_util.hh"
-namespace blender::nodes::node_geo_curve_endpoint_select_cc {
+namespace blender::nodes::node_geo_curve_endpoint_selection_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
@@ -130,16 +130,16 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<bool> selection_field{std::make_shared<EndpointFieldInput>(start_size, end_size)};
params.set_output("Selection", std::move(selection_field));
}
-} // namespace blender::nodes::node_geo_curve_endpoint_select_cc
+} // namespace blender::nodes::node_geo_curve_endpoint_selection_cc
void register_node_type_geo_curve_endpoint_selection()
{
- namespace file_ns = blender::nodes::node_geo_curve_endpoint_select_cc;
+ namespace file_ns = blender::nodes::node_geo_curve_endpoint_selection_cc;
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
index 3aabf8e21eb..929d9046f98 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -16,7 +16,7 @@
#include "BLI_array.hh"
#include "BLI_delaunay_2d.h"
-#include "BLI_double2.hh"
+#include "BLI_math_vec_types.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -48,8 +48,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryCurveFill *data = (NodeGeometryCurveFill *)MEM_callocN(sizeof(NodeGeometryCurveFill),
- __func__);
+ NodeGeometryCurveFill *data = MEM_cnew<NodeGeometryCurveFill>(__func__);
data->mode = GEO_NODE_CURVE_FILL_MODE_TRIANGULATED;
node->storage = data;
@@ -170,7 +169,7 @@ void register_node_type_geo_curve_fill()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_storage(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
index 7fbcc47c708..81421609dfd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -32,14 +32,21 @@ 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)
.subtype(PropertySubType::PROP_DISTANCE)
.default_value(0.25f)
.supports_field();
- b.add_input<decl::Bool>(N_("Limit Radius"));
+ b.add_input<decl::Bool>(N_("Limit Radius"))
+ .description(
+ N_("Limit the maximum value of the radius in order to avoid overlapping fillets"));
b.add_output<decl::Geometry>(N_("Curve"));
}
@@ -50,8 +57,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveFillet *data = (NodeGeometryCurveFillet *)MEM_callocN(
- sizeof(NodeGeometryCurveFillet), __func__);
+ NodeGeometryCurveFillet *data = MEM_cnew<NodeGeometryCurveFillet>(__func__);
data->mode = GEO_NODE_CURVE_FILLET_BEZIER;
node->storage = data;
@@ -118,9 +124,9 @@ static Array<float3> calculate_directions(const Span<float3> positions)
Array<float3> directions(size);
for (const int i : IndexRange(size - 1)) {
- directions[i] = (positions[i + 1] - positions[i]).normalized();
+ directions[i] = math::normalize(positions[i + 1] - positions[i]);
}
- directions[size - 1] = (positions[0] - positions[size - 1]).normalized();
+ directions[size - 1] = math::normalize(positions[0] - positions[size - 1]);
return directions;
}
@@ -131,9 +137,9 @@ static Array<float3> calculate_axes(const Span<float3> directions)
const int size = directions.size();
Array<float3> axes(size);
- axes[0] = float3::cross(-directions[size - 1], directions[0]).normalized();
+ axes[0] = math::normalize(math::cross(-directions[size - 1], directions[0]));
for (const int i : IndexRange(1, size - 1)) {
- axes[i] = float3::cross(-directions[i - 1], directions[i]).normalized();
+ axes[i] = math::normalize(math::cross(-directions[i - 1], directions[i]));
}
return axes;
@@ -244,8 +250,8 @@ static void limit_radii(FilletData &fd, const bool cyclic)
if (cyclic) {
/* Calculate lengths between adjacent control points. */
- const float len_prev = float3::distance(positions[0], positions[size - 1]);
- const float len_next = float3::distance(positions[0], positions[1]);
+ const float len_prev = math::distance(positions[0], positions[size - 1]);
+ const float len_next = math::distance(positions[0], positions[1]);
/* Calculate tangent lengths of fillets in control points. */
const float tan_len = radii[0] * tan(angles[0] / 2.0f);
@@ -267,16 +273,16 @@ static void limit_radii(FilletData &fd, const bool cyclic)
}
/* Initialize max_radii to largest possible radii. */
- float prev_dist = float3::distance(positions[1], positions[0]);
+ float prev_dist = math::distance(positions[1], positions[0]);
for (const int i : IndexRange(1, size - 2)) {
- const float temp_dist = float3::distance(positions[i], positions[i + 1]);
+ const float temp_dist = math::distance(positions[i], positions[i + 1]);
max_radii[i] = std::min(prev_dist, temp_dist) / tan(angles[i] / 2.0f);
prev_dist = temp_dist;
}
/* Max radii calculations for each index. */
for (const int i : IndexRange(start, fillet_count - 1)) {
- const float len_next = float3::distance(positions[i], positions[i + 1]);
+ const float len_next = math::distance(positions[i], positions[i + 1]);
const float tan_len = radii[i] * tan(angles[i] / 2.0f);
const float tan_len_next = radii[i + 1] * tan(angles[i + 1] / 2.0f);
@@ -411,7 +417,8 @@ static void update_bezier_positions(const FilletData &fd,
const float3 center = get_center(dst_spline.positions()[i_dst] - positions[i_src], fd, i_src);
/* Calculate the vector of the radius formed by the first vertex. */
float3 radius_vec = dst_spline.positions()[i_dst] - center;
- const float radius = radius_vec.normalize_and_get_length();
+ float radius;
+ radius_vec = math::normalize_and_get_length(radius_vec, radius);
dst_spline.handle_types_right().slice(1, count - 2).fill(BezierSpline::HandleType::Align);
dst_spline.handle_types_left().slice(1, count - 2).fill(BezierSpline::HandleType::Align);
@@ -642,7 +649,7 @@ void register_node_type_geo_curve_fillet()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY);
ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveFillet", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
index 381bb0fc1d0..e4e87e519f7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
@@ -38,8 +38,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSelectHandles), __func__);
+ NodeGeometryCurveSelectHandles *data = MEM_cnew<NodeGeometryCurveSelectHandles>(__func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
@@ -156,7 +155,7 @@ void register_node_type_geo_curve_handle_type_selection()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
index 73ad8a8cf65..21ae88a6852 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
@@ -48,7 +48,7 @@ void register_node_type_geo_curve_length()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
new file mode 100644
index 00000000000..3f6298168a2
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
@@ -0,0 +1,391 @@
+/*
+ * 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_spline.hh"
+#include "BLI_math_base_safe.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+#include "node_geometry_util.hh"
+#include <numeric>
+
+namespace blender::nodes::node_geo_curve_primitive_arc_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveArc)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Resolution"))
+ .default_value(16)
+ .min(2)
+ .max(256)
+ .subtype(PROP_UNSIGNED)
+ .description(N_("The number of points on the arc"));
+ b.add_input<decl::Vector>(N_("Start"))
+ .default_value({-1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the first control point"));
+ b.add_input<decl::Vector>(N_("Middle"))
+ .default_value({0.0f, 2.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the middle control point"));
+ b.add_input<decl::Vector>(N_("End"))
+ .default_value({1.0f, 0.0f, 0.0f})
+ .subtype(PROP_TRANSLATION)
+ .description(N_("Position of the last control point"));
+ b.add_input<decl::Float>(N_("Radius"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Distance of the points from the origin"));
+ b.add_input<decl::Float>(N_("Start Angle"))
+ .default_value(0.0f)
+ .subtype(PROP_ANGLE)
+ .description(N_("Starting angle of the arc"));
+ b.add_input<decl::Float>(N_("Sweep Angle"))
+ .default_value(1.75f * M_PI)
+ .min(-2 * M_PI)
+ .max(2 * M_PI)
+ .subtype(PROP_ANGLE)
+ .description(N_("Length of the arc"));
+ b.add_input<decl::Float>(N_("Offset Angle"))
+ .default_value(0.0f)
+ .subtype(PROP_ANGLE)
+ .description(N_("Offset angle of the arc"));
+ b.add_input<decl::Bool>(N_("Connect Center"))
+ .default_value(false)
+ .description(N_("Connect the arc at the center"));
+ b.add_input<decl::Bool>(N_("Invert Arc"))
+ .default_value(false)
+ .description(N_("Invert and draw opposite arc"));
+
+ b.add_output<decl::Geometry>(N_("Curve"));
+ b.add_output<decl::Vector>(N_("Center"))
+ .description(N_("The center of the circle described by the three points"))
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+ b.add_output<decl::Vector>(N_("Normal"))
+ .description(N_("The normal direction of the plane described by the three points, pointing "
+ "towards the positive Z axis"))
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+ b.add_output<decl::Float>(N_("Radius"))
+ .description(N_("The radius of the circle described by the three points"))
+ .make_available(
+ [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurvePrimitiveArc *data = MEM_cnew<NodeGeometryCurvePrimitiveArc>(__func__);
+
+ data->mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeGeometryCurvePrimitiveArc &storage = node_storage(*node);
+ const GeometryNodeCurvePrimitiveArcMode mode = (GeometryNodeCurvePrimitiveArcMode)storage.mode;
+
+ bNodeSocket *start_socket = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *middle_socket = start_socket->next;
+ bNodeSocket *end_socket = middle_socket->next;
+
+ bNodeSocket *radius_socket = end_socket->next;
+ bNodeSocket *start_angle_socket = radius_socket->next;
+ bNodeSocket *sweep_angle_socket = start_angle_socket->next;
+
+ bNodeSocket *offset_angle_socket = sweep_angle_socket->next;
+
+ bNodeSocket *center_out_socket = ((bNodeSocket *)node->outputs.first)->next;
+ bNodeSocket *normal_out_socket = center_out_socket->next;
+ bNodeSocket *radius_out_socket = normal_out_socket->next;
+
+ const bool radius_mode = (mode == GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS);
+ const bool points_mode = (mode == GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS);
+
+ nodeSetSocketAvailability(ntree, start_socket, points_mode);
+ nodeSetSocketAvailability(ntree, middle_socket, points_mode);
+ nodeSetSocketAvailability(ntree, end_socket, points_mode);
+
+ nodeSetSocketAvailability(ntree, radius_socket, radius_mode);
+ nodeSetSocketAvailability(ntree, start_angle_socket, radius_mode);
+ nodeSetSocketAvailability(ntree, sweep_angle_socket, radius_mode);
+
+ nodeSetSocketAvailability(ntree, offset_angle_socket, points_mode);
+
+ nodeSetSocketAvailability(ntree, center_out_socket, points_mode);
+ nodeSetSocketAvailability(ntree, normal_out_socket, points_mode);
+ nodeSetSocketAvailability(ntree, radius_out_socket, points_mode);
+}
+
+static float3 rotate_vector_around_axis(const float3 vector, const float3 axis, const float angle)
+{
+ float3 result = vector;
+ float mat[3][3];
+ axis_angle_to_mat3(mat, axis, angle);
+ mul_m3_v3(mat, result);
+ return result;
+}
+
+static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3)
+{
+ const float3 a = math::normalize(p2 - p1);
+ const float3 b = math::normalize(p3 - p1);
+ return (ELEM(a, b, b * -1.0f));
+}
+
+static std::unique_ptr<CurveEval> create_arc_curve_from_points(const int resolution,
+ const float3 a,
+ const float3 b,
+ const float3 c,
+ float angle_offset,
+ const bool connect_center,
+ const bool invert_arc,
+ float3 &r_center,
+ float3 &r_normal,
+ float &r_radius)
+{
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+
+ if (connect_center) {
+ spline->resize(resolution + 1);
+ }
+ else {
+ spline->resize(resolution);
+ }
+
+ const int stepcount = resolution - 1;
+ const int centerpoint = resolution;
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
+ const bool is_colinear = colinear_f3_f3_f3(a, b, c);
+
+ float3 center;
+ float3 normal;
+ float radius;
+ const float3 mid_ac = math::midpoint(a, c);
+ normal_tri_v3(normal, a, c, b);
+
+ if (is_colinear || a == c || a == b || b == c || resolution == 2) {
+ /* If colinear, generate a point line between points. */
+ float3 p1, p2;
+
+ /* Find the two points that are furthest away from each other. */
+ const float ab = math::distance_squared(a, b);
+ const float ac = math::distance_squared(a, c);
+ const float bc = math::distance_squared(b, c);
+ if (ab > ac && ab > bc) {
+ p1 = a;
+ p2 = b;
+ }
+ else if (bc > ab && bc > ac) {
+ p1 = b;
+ p2 = c;
+ }
+ else {
+ p1 = a;
+ p2 = c;
+ }
+
+ const float step = 1.0f / stepcount;
+ for (const int i : IndexRange(resolution)) {
+ const float factor = step * i;
+ positions[i] = math::interpolate(p1, p2, factor);
+ }
+ center = mid_ac;
+ radius = 0.0f;
+ }
+ else {
+ /* Midpoints of `A->B` and `B->C`. */
+ const float3 mid_ab = math::midpoint(a, b);
+ const float3 mid_bc = math::midpoint(c, b);
+
+ /* Normalized vectors of `A->B` and `B->C`. */
+ const float3 nba = math::normalize(b - a);
+ const float3 ncb = math::normalize(c - b);
+
+ /* Normal of plane of main 2 segments A->B and `B->C`. */
+ const float3 nabc = math::normalize(math::cross(nba, ncb));
+
+ /* Determine center point from the intersection of 3 planes. */
+ float plane_1[4], plane_2[4], plane_3[4];
+ plane_from_point_normal_v3(plane_1, mid_ab, nabc);
+ plane_from_point_normal_v3(plane_2, mid_ab, nba);
+ plane_from_point_normal_v3(plane_3, mid_bc, ncb);
+
+ /* If the 3 planes do not intersect at one point, just return empty geometry. */
+ if (!isect_plane_plane_plane_v3(plane_1, plane_2, plane_3, center)) {
+ r_center = mid_ac;
+ r_normal = normal;
+ r_radius = 0.0f;
+ return nullptr;
+ }
+
+ /* Radial vectors. */
+ const float3 rad_a = math::normalize(a - center);
+ const float3 rad_b = math::normalize(b - center);
+ const float3 rad_c = math::normalize(c - center);
+
+ /* Calculate angles. */
+ radius = math::distance(center, b);
+ float angle_ab = angle_signed_on_axis_v3v3_v3(rad_a, rad_b, normal) + 2.0f * M_PI;
+ float angle_ac = angle_signed_on_axis_v3v3_v3(rad_a, rad_c, normal) + 2.0f * M_PI;
+ float angle = (angle_ac > angle_ab) ? angle_ac : angle_ab;
+ angle -= 2.0f * M_PI;
+ if (invert_arc) {
+ angle = -(2.0f * M_PI - angle);
+ }
+
+ /* Create arc. */
+ const float step = angle / stepcount;
+ for (const int i : IndexRange(resolution)) {
+ const float factor = step * i + angle_offset;
+ float3 out = rotate_vector_around_axis(rad_a, -normal, factor);
+ positions[i] = out * radius + center;
+ }
+ }
+
+ if (connect_center) {
+ spline->set_cyclic(true);
+ positions[centerpoint] = center;
+ }
+
+ /* Ensure normal is relative to Z-up. */
+ if (math::dot(float3(0, 0, 1), normal) < 0) {
+ normal = -normal;
+ }
+
+ curve->add_spline(std::move(spline));
+ curve->attributes.reallocate(curve->splines().size());
+ r_center = center;
+ r_radius = radius;
+ r_normal = normal;
+ return curve;
+}
+
+static std::unique_ptr<CurveEval> create_arc_curve_from_radius(const int resolution,
+ const float radius,
+ const float start_angle,
+ const float sweep_angle,
+ const bool connect_center,
+ const bool invert_arc)
+{
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+
+ if (connect_center) {
+ spline->resize(resolution + 1);
+ }
+ else {
+ spline->resize(resolution);
+ }
+
+ const int stepcount = resolution - 1;
+ const int centerpoint = resolution;
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
+ const float sweep = (invert_arc) ? -(2.0f * M_PI - sweep_angle) : sweep_angle;
+
+ const float theta_step = sweep / float(stepcount);
+ for (const int i : IndexRange(resolution)) {
+ const float theta = theta_step * i + start_angle;
+ const float x = radius * cos(theta);
+ const float y = radius * sin(theta);
+ positions[i] = float3(x, y, 0.0f);
+ }
+
+ if (connect_center) {
+ spline->set_cyclic(true);
+ positions[centerpoint] = float3(0.0f, 0.0f, 0.0f);
+ }
+
+ curve->add_spline(std::move(spline));
+ curve->attributes.reallocate(curve->splines().size());
+ return curve;
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurvePrimitiveArc &storage = node_storage(params.node());
+
+ const GeometryNodeCurvePrimitiveArcMode mode = (GeometryNodeCurvePrimitiveArcMode)storage.mode;
+
+ switch (mode) {
+ case GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS: {
+ std::unique_ptr<CurveEval> curve;
+ float3 r_center, r_normal;
+ float r_radius;
+ curve = create_arc_curve_from_points(std::max(params.extract_input<int>("Resolution"), 2),
+ params.extract_input<float3>("Start"),
+ params.extract_input<float3>("Middle"),
+ params.extract_input<float3>("End"),
+ params.extract_input<float>("Offset Angle"),
+ params.extract_input<bool>("Connect Center"),
+ params.extract_input<bool>("Invert Arc"),
+ r_center,
+ r_normal,
+ r_radius);
+ params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Center", r_center);
+ params.set_output("Normal", r_normal);
+ params.set_output("Radius", r_radius);
+ break;
+ }
+ case GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS: {
+ std::unique_ptr<CurveEval> curve;
+ curve = create_arc_curve_from_radius(std::max(params.extract_input<int>("Resolution"), 2),
+ params.extract_input<float>("Radius"),
+ params.extract_input<float>("Start Angle"),
+ params.extract_input<float>("Sweep Angle"),
+ params.extract_input<bool>("Connect Center"),
+ params.extract_input<bool>("Invert Arc"));
+
+ params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ break;
+ }
+ }
+}
+
+} // namespace blender::nodes::node_geo_curve_primitive_arc_cc
+
+void register_node_type_geo_curve_primitive_arc()
+{
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_arc_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_ARC, "Arc", NODE_CLASS_GEOMETRY);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ node_type_storage(&ntype,
+ "NodeGeometryCurvePrimitiveArc",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.draw_buttons = file_ns::node_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
index 4299b5cc022..7d84ddf9917 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
@@ -62,8 +62,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveBezierSegment *data = (NodeGeometryCurvePrimitiveBezierSegment *)
- MEM_callocN(sizeof(NodeGeometryCurvePrimitiveBezierSegment), __func__);
+ NodeGeometryCurvePrimitiveBezierSegment *data =
+ MEM_cnew<NodeGeometryCurvePrimitiveBezierSegment>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION;
node->storage = data;
@@ -79,44 +79,29 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve(
{
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
+ spline->set_resolution(resolution);
+
+ spline->resize(2);
+ MutableSpan<float3> positions = spline->positions();
+ spline->handle_types_left().fill(BezierSpline::HandleType::Align);
+ spline->handle_types_right().fill(BezierSpline::HandleType::Align);
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
+ positions.first() = start;
+ positions.last() = end;
if (mode == GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION) {
- spline->add_point(start,
- BezierSpline::HandleType::Align,
- 2.0f * start - start_handle_right,
- BezierSpline::HandleType::Align,
- start_handle_right,
- 1.0f,
- 0.0f);
- spline->add_point(end,
- BezierSpline::HandleType::Align,
- end_handle_left,
- BezierSpline::HandleType::Align,
- 2.0f * end - end_handle_left,
- 1.0f,
- 0.0f);
+ spline->set_handle_position_right(0, start_handle_right);
+ spline->set_handle_position_left(1, end_handle_left);
}
else {
- spline->add_point(start,
- BezierSpline::HandleType::Align,
- start - start_handle_right,
- BezierSpline::HandleType::Align,
- start + start_handle_right,
- 1.0f,
- 0.0f);
- spline->add_point(end,
- BezierSpline::HandleType::Align,
- end + end_handle_left,
- BezierSpline::HandleType::Align,
- end - end_handle_left,
- 1.0f,
- 0.0f);
+ spline->set_handle_position_right(0, start + start_handle_right);
+ spline->set_handle_position_left(1, end + end_handle_left);
}
- spline->set_resolution(resolution);
- spline->attributes.reallocate(spline->size());
curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
+ curve->attributes.reallocate(1);
return curve;
}
@@ -144,7 +129,7 @@ void register_node_type_geo_curve_primitive_bezier_segment()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveBezierSegment",
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index b08fcd86059..7b5d1a1dc80 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
@@ -56,7 +56,9 @@ static void node_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 node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -66,8 +68,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveCircle *data = (NodeGeometryCurvePrimitiveCircle *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveCircle), __func__);
+ NodeGeometryCurvePrimitiveCircle *data = MEM_cnew<NodeGeometryCurvePrimitiveCircle>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS;
node->storage = data;
@@ -100,8 +101,8 @@ static void node_update(bNodeTree *ntree, bNode *node)
static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3)
{
- const float3 a = (p2 - p1).normalized();
- const float3 b = (p3 - p1).normalized();
+ const float3 a = math::normalize(p2 - p1);
+ const float3 b = math::normalize(p3 - p1);
return (ELEM(a, b, b * -1.0f));
}
@@ -121,18 +122,18 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
float3 center;
/* Midpoints of `P1->P2` and `P2->P3`. */
- const float3 q1 = float3::interpolate(p1, p2, 0.5f);
- const float3 q2 = float3::interpolate(p2, p3, 0.5f);
+ const float3 q1 = math::interpolate(p1, p2, 0.5f);
+ const float3 q2 = math::interpolate(p2, p3, 0.5f);
/* Normal Vectors of `P1->P2` and `P2->P3` */
- const float3 v1 = (p2 - p1).normalized();
- const float3 v2 = (p3 - p2).normalized();
+ const float3 v1 = math::normalize(p2 - p1);
+ const float3 v2 = math::normalize(p3 - p2);
/* Normal of plane of main 2 segments P1->P2 and `P2->P3`. */
- const float3 v3 = float3::cross(v1, v2).normalized();
+ const float3 v3 = math::normalize(math::cross(v1, v2));
/* Normal of plane of first perpendicular bisector and `P1->P2`. */
- const float3 v4 = float3::cross(v3, v1).normalized();
+ const float3 v4 = math::normalize(math::cross(v3, v1));
/* Determine Center-point from the intersection of 3 planes. */
float plane_1[4], plane_2[4], plane_3[4];
@@ -147,7 +148,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
}
/* Get the radius from the center-point to p1. */
- const float r = float3::distance(p1, center);
+ const float r = math::distance(p1, center);
const float theta_step = ((2 * M_PI) / (float)resolution);
for (const int i : IndexRange(resolution)) {
@@ -230,8 +231,7 @@ void register_node_type_geo_curve_primitive_circle()
namespace file_ns = blender::nodes::node_geo_curve_primitive_circle_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index 6d71c97b15a..d35fa0a2fdc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveLine *data = (NodeGeometryCurvePrimitiveLine *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveLine), __func__);
+ NodeGeometryCurvePrimitiveLine *data = MEM_cnew<NodeGeometryCurvePrimitiveLine>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS;
node->storage = data;
@@ -101,7 +100,7 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start
spline->resize(2);
MutableSpan<float3> positions = spline->positions();
positions[0] = start;
- positions[1] = direction.normalized() * length + start;
+ positions[1] = math::normalize(direction) * length + start;
spline->radii().fill(1.0f);
spline->tilts().fill(0.0f);
@@ -136,7 +135,7 @@ void register_node_type_geo_curve_primitive_line()
namespace file_ns = blender::nodes::node_geo_curve_primitive_line_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
index 92a9b1b4966..885d92a111b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
@@ -50,15 +50,19 @@ static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1,
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ spline->resize(resolution + 1);
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
const float step = 1.0f / resolution;
- for (int i : IndexRange(resolution + 1)) {
+ for (const int i : IndexRange(resolution + 1)) {
const float factor = step * i;
- const float3 q1 = float3::interpolate(p1, p2, factor);
- const float3 q2 = float3::interpolate(p2, p3, factor);
- const float3 out = float3::interpolate(q1, q2, factor);
- spline->add_point(out, 1.0f, 0.0f);
+ const float3 q1 = math::interpolate(p1, p2, factor);
+ const float3 q2 = math::interpolate(p2, p3, factor);
+ positions[i] = math::interpolate(q1, q2, factor);
}
- spline->attributes.reallocate(spline->size());
+
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
return curve;
@@ -81,11 +85,8 @@ void register_node_type_geo_curve_primitive_quadratic_bezier()
namespace file_ns = blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype,
- GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER,
- "Quadratic Bezier",
- NODE_CLASS_GEOMETRY,
- 0);
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, "Quadratic Bezier", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
index 41f92c7d0c8..8ec42cb1c45 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,9 +17,12 @@
#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::node_geo_curve_primitive_quadrilaterial_cc {
+namespace blender::nodes::node_geo_curve_primitive_quadrilateral_cc {
NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveQuad)
@@ -86,8 +89,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveQuad), __func__);
+ NodeGeometryCurvePrimitiveQuad *data = MEM_cnew<NodeGeometryCurvePrimitiveQuad>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE;
node->storage = data;
}
@@ -110,35 +112,61 @@ static void node_update(bNodeTree *ntree, bNode *node)
bNodeSocket *p3 = p2->next;
bNodeSocket *p4 = p3->next;
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- nodeSetSocketAvailability(ntree, sock, false);
- }
+ Vector<bNodeSocket *> available_sockets;
if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) {
- nodeSetSocketAvailability(ntree, width, true);
- nodeSetSocketAvailability(ntree, height, true);
+ available_sockets.extend({width, height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) {
- nodeSetSocketAvailability(ntree, width, true);
- nodeSetSocketAvailability(ntree, height, true);
- nodeSetSocketAvailability(ntree, offset, true);
+ available_sockets.extend({width, height, offset});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) {
- nodeSetSocketAvailability(ntree, bottom, true);
- nodeSetSocketAvailability(ntree, top, true);
- nodeSetSocketAvailability(ntree, offset, true);
- nodeSetSocketAvailability(ntree, height, true);
+ available_sockets.extend({bottom, top, offset, height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) {
- nodeSetSocketAvailability(ntree, width, true);
- nodeSetSocketAvailability(ntree, bottom_height, true);
- nodeSetSocketAvailability(ntree, top_height, true);
+ available_sockets.extend({width, bottom_height, top_height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) {
- nodeSetSocketAvailability(ntree, p1, true);
- nodeSetSocketAvailability(ntree, p2, true);
- nodeSetSocketAvailability(ntree, p3, true);
- nodeSetSocketAvailability(ntree, p4, true);
+ available_sockets.extend({p1, p2, p3, p4});
+ }
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ nodeSetSocketAvailability(ntree, sock, available_sockets.contains(sock));
+ }
+}
+
+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});
}
}
@@ -253,15 +281,15 @@ static void node_geo_exec(GeoNodeExecParams params)
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
-} // namespace blender::nodes::node_geo_curve_primitive_quadrilaterial_cc
+} // namespace blender::nodes::node_geo_curve_primitive_quadrilateral_cc
void register_node_type_geo_curve_primitive_quadrilateral()
{
- namespace file_ns = blender::nodes::node_geo_curve_primitive_quadrilaterial_cc;
+ namespace file_ns = blender::nodes::node_geo_curve_primitive_quadrilateral_cc;
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
@@ -271,5 +299,6 @@ void register_node_type_geo_curve_primitive_quadrilateral()
"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 d5ae3551904..6aba65b5638 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
@@ -65,6 +65,11 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
const float delta_theta = (M_PI * 2 * rotations) / (float)totalpoints *
(direction ? 1.0f : -1.0f);
+ spline->resize(totalpoints + 1);
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
for (const int i : IndexRange(totalpoints + 1)) {
const float theta = i * delta_theta;
const float radius = start_radius + i * delta_radius;
@@ -72,10 +77,9 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
const float y = radius * sin(theta);
const float z = delta_height * i;
- spline->add_point(float3(x, y, z), 1.0f, 0.0f);
+ positions[i] = {x, y, z};
}
- spline->attributes.reallocate(spline->size());
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
return curve;
@@ -107,7 +111,7 @@ void register_node_type_geo_curve_primitive_spiral()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
index 731be0f0f49..14517a79037 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
@@ -54,19 +54,24 @@ static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius,
{
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ spline->set_cyclic(true);
+
+ spline->resize(points * 2);
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
const float theta_step = (2.0f * M_PI) / float(points);
- for (int i : IndexRange(points)) {
+ for (const int i : IndexRange(points)) {
const float x = outer_radius * cos(theta_step * i);
const float y = outer_radius * sin(theta_step * i);
- spline->add_point(float3(x, y, 0.0f), 1.0f, 0.0f);
+ positions[i * 2] = {x, y, 0.0f};
const float inner_x = inner_radius * cos(theta_step * i + theta_step * 0.5f + twist);
const float inner_y = inner_radius * sin(theta_step * i + theta_step * 0.5f + twist);
- spline->add_point(float3(inner_x, inner_y, 0.0f), 1.0f, 0.0f);
+ positions[i * 2 + 1] = {inner_x, inner_y, 0.0f};
}
- spline->set_cyclic(true);
- spline->attributes.reallocate(spline->size());
+
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
@@ -110,7 +115,7 @@ void register_node_type_geo_curve_primitive_star()
namespace file_ns = blender::nodes::node_geo_curve_primitive_star_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index 7e465714265..8494b4868e8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveResample *data = (NodeGeometryCurveResample *)MEM_callocN(
- sizeof(NodeGeometryCurveResample), __func__);
+ NodeGeometryCurveResample *data = MEM_cnew<NodeGeometryCurveResample>(__func__);
data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
node->storage = data;
@@ -82,8 +81,11 @@ static SplinePtr resample_spline(const Spline &src, const int count)
Spline::copy_base_settings(src, *dst);
if (src.evaluated_edges_size() < 1 || count == 1) {
- dst->add_point(src.positions().first(), src.radii().first(), src.tilts().first());
- dst->attributes.reallocate(1);
+ dst->resize(1);
+ dst->positions().first() = src.positions().first();
+ dst->radii().first() = src.radii().first();
+ dst->tilts().first() = src.tilts().first();
+
src.attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
std::optional<GSpan> src_attribute = src.attributes.get_for_read(attribute_id);
@@ -295,7 +297,7 @@ void register_node_type_geo_curve_resample()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
index d07e89ec7f2..38974fafce7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -67,7 +67,7 @@ void register_node_type_geo_curve_reverse()
namespace file_ns = blender::nodes::node_geo_curve_reverse_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse Curve", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
index 57e08a91211..56fbc50f033 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -32,9 +32,17 @@ 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();
@@ -47,8 +55,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_type_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSample *data = (NodeGeometryCurveSample *)MEM_callocN(
- sizeof(NodeGeometryCurveSample), __func__);
+ NodeGeometryCurveSample *data = MEM_cnew<NodeGeometryCurveSample>(__func__);
data->mode = GEO_NODE_CURVE_SAMPLE_LENGTH;
node->storage = data;
}
@@ -178,7 +185,7 @@ class SampleCurveFunction : public fn::MultiFunction {
for (const int i : mask) {
const Spline::LookupResult &lookup = lookups[i];
const Span<float3> evaluated_tangents = splines[spline_indices[i]]->evaluated_tangents();
- sampled_tangents[i] = sample_with_lookup(lookup, evaluated_tangents).normalized();
+ sampled_tangents[i] = math::normalize(sample_with_lookup(lookup, evaluated_tangents));
}
}
@@ -186,7 +193,7 @@ class SampleCurveFunction : public fn::MultiFunction {
for (const int i : mask) {
const Spline::LookupResult &lookup = lookups[i];
const Span<float3> evaluated_normals = splines[spline_indices[i]]->evaluated_normals();
- sampled_normals[i] = sample_with_lookup(lookup, evaluated_normals).normalized();
+ sampled_normals[i] = math::normalize(sample_with_lookup(lookup, evaluated_normals));
}
}
}
@@ -279,7 +286,7 @@ void register_node_type_geo_curve_sample()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, " Sample Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, "Sample Curve", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::node_type_init);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
index 8c0827570c6..74bdce4cef3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
@@ -40,11 +40,10 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSetHandles), __func__);
+ NodeGeometryCurveSetHandles *data = MEM_cnew<NodeGeometryCurveSetHandles>(__func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
- data->mode = GEO_NODE_CURVE_HANDLE_LEFT;
+ data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
node->storage = data;
}
@@ -136,8 +135,7 @@ void register_node_type_geo_curve_set_handles()
namespace file_ns = blender::nodes::node_geo_curve_set_handles_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
index de352d217ed..257a5b8df00 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -96,7 +96,7 @@ static void calculate_nurbs_lengths(const NURBSpline &spline, MutableSpan<float>
float length = 0.0f;
for (const int i : IndexRange(positions.size() - 1)) {
lengths[i] = length;
- length += float3::distance(positions[i], positions[i + 1]);
+ length += math::distance(positions[i], positions[i + 1]);
}
lengths.last() = length;
}
@@ -319,7 +319,7 @@ void register_node_type_geo_curve_spline_parameter()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index eef8c1b0db5..b91ddd7bc7a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -41,8 +41,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
- sizeof(NodeGeometryCurveSplineType), __func__);
+ NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
node->storage = data;
@@ -70,6 +69,33 @@ static void scale_output_assign(const Span<T> input,
}
}
+template<class T>
+static void nurbs_to_bezier_assign(const Span<T> input,
+ const MutableSpan<T> r_output,
+ const NURBSpline::KnotsMode knotsMode)
+{
+ const int input_size = input.size();
+ const int output_size = r_output.size();
+
+ switch (knotsMode) {
+ case NURBSpline::KnotsMode::Bezier:
+ scale_input_assign<T>(input, 3, 1, r_output);
+ break;
+ case NURBSpline::KnotsMode::Normal:
+ for (const int i : IndexRange(output_size)) {
+ r_output[i] = input[(i + 1) % input_size];
+ }
+ break;
+ case NURBSpline::KnotsMode::EndPoint:
+ for (const int i : IndexRange(1, output_size - 2)) {
+ r_output[i] = input[i + 1];
+ }
+ r_output.first() = input.first();
+ r_output.last() = input.last();
+ break;
+ }
+}
+
template<typename CopyFn>
static void copy_attributes(const Spline &input_spline, Spline &output_spline, CopyFn copy_fn)
{
@@ -94,6 +120,88 @@ static void copy_attributes(const Spline &input_spline, Spline &output_spline, C
ATTR_DOMAIN_POINT);
}
+static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_positions,
+ const NURBSpline::KnotsMode knots_mode)
+{
+ const int nurbs_positions_size = nurbs_positions.size();
+ Vector<float3> handle_positions;
+ if (knots_mode == NURBSpline::KnotsMode::Bezier) {
+ for (const int i : IndexRange(nurbs_positions_size)) {
+ if (i % 3 == 1) {
+ continue;
+ }
+ handle_positions.append(nurbs_positions[i]);
+ }
+ if (nurbs_positions_size % 3 == 1) {
+ handle_positions.pop_last();
+ }
+ else if (nurbs_positions_size % 3 == 2) {
+ const int last_index = nurbs_positions_size - 1;
+ handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
+ }
+ }
+ else {
+ const bool is_periodic = knots_mode == NURBSpline::KnotsMode::Normal;
+ if (is_periodic) {
+ handle_positions.append(nurbs_positions[1] +
+ ((nurbs_positions[0] - nurbs_positions[1]) / 3));
+ }
+ else {
+ handle_positions.append(2 * nurbs_positions[0] - nurbs_positions[1]);
+ handle_positions.append(nurbs_positions[1]);
+ }
+ const int segments_size = nurbs_positions_size - 1;
+ const bool ignore_interior_segment = segments_size == 3 && is_periodic == false;
+ if (ignore_interior_segment == false) {
+ const float mid_offset = (float)(segments_size - 1) / 2.0f;
+ for (const int i : IndexRange(1, segments_size - 2)) {
+ const int divisor = is_periodic ?
+ 3 :
+ std::min(3, (int)(-std::abs(i - mid_offset) + mid_offset + 1.0f));
+ const float3 &p1 = nurbs_positions[i];
+ const float3 &p2 = nurbs_positions[i + 1];
+ const float3 displacement = (p2 - p1) / divisor;
+ const int num_handles_on_segment = divisor < 3 ? 1 : 2;
+ for (int j : IndexRange(1, num_handles_on_segment)) {
+ handle_positions.append(p1 + (displacement * j));
+ }
+ }
+ }
+ const int last_index = nurbs_positions_size - 1;
+ if (is_periodic) {
+ handle_positions.append(
+ nurbs_positions[last_index - 1] +
+ ((nurbs_positions[last_index] - nurbs_positions[last_index - 1]) / 3));
+ }
+ else {
+ handle_positions.append(nurbs_positions[last_index - 1]);
+ handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
+ }
+ }
+ return handle_positions;
+}
+
+static Array<float3> create_nurbs_to_bezier_positions(const Span<float3> nurbs_positions,
+ const Span<float3> handle_positions,
+ const NURBSpline::KnotsMode knots_mode)
+{
+ if (knots_mode == NURBSpline::KnotsMode::Bezier) {
+ /* Every third NURBS position (starting from index 1) should be converted to Bezier position */
+ const int scale = 3;
+ const int offset = 1;
+ Array<float3> bezier_positions((nurbs_positions.size() + offset) / scale);
+ scale_input_assign(nurbs_positions, scale, offset, bezier_positions.as_mutable_span());
+ return bezier_positions;
+ }
+
+ Array<float3> bezier_positions(handle_positions.size() / 2);
+ for (const int i : IndexRange(bezier_positions.size())) {
+ bezier_positions[i] = math::interpolate(
+ handle_positions[i * 2], handle_positions[i * 2 + 1], 0.5f);
+ }
+ return bezier_positions;
+}
+
static SplinePtr convert_to_poly_spline(const Spline &input)
{
std::unique_ptr<PolySpline> output = std::make_unique<PolySpline>();
@@ -176,22 +284,43 @@ static SplinePtr poly_to_bezier(const Spline &input)
static SplinePtr nurbs_to_bezier(const Spline &input)
{
const NURBSpline &nurbs_spline = static_cast<const NURBSpline &>(input);
+ Span<float3> nurbs_positions;
+ Vector<float3> nurbs_positions_vector;
+ NURBSpline::KnotsMode knots_mode;
+ if (nurbs_spline.is_cyclic()) {
+ nurbs_positions_vector = nurbs_spline.positions();
+ nurbs_positions_vector.append(nurbs_spline.positions()[0]);
+ nurbs_positions_vector.append(nurbs_spline.positions()[1]);
+ nurbs_positions = nurbs_positions_vector;
+ knots_mode = NURBSpline::KnotsMode::Normal;
+ }
+ else {
+ nurbs_positions = nurbs_spline.positions();
+ knots_mode = nurbs_spline.knots_mode;
+ }
+ const Vector<float3> handle_positions = create_nurbs_to_bezier_handles(nurbs_positions,
+ knots_mode);
+ BLI_assert(handle_positions.size() % 2 == 0);
+ const Array<float3> bezier_positions = create_nurbs_to_bezier_positions(
+ nurbs_positions, handle_positions.as_span(), knots_mode);
+ BLI_assert(handle_positions.size() == bezier_positions.size() * 2);
+
std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
- output->resize(input.size() / 3);
- scale_input_assign<float3>(input.positions(), 3, 1, output->positions());
- scale_input_assign<float3>(input.positions(), 3, 0, output->handle_positions_left());
- scale_input_assign<float3>(input.positions(), 3, 2, output->handle_positions_right());
- scale_input_assign<float>(input.radii(), 3, 2, output->radii());
- scale_input_assign<float>(input.tilts(), 3, 2, output->tilts());
+ output->resize(bezier_positions.size());
+ output->positions().copy_from(bezier_positions);
+ nurbs_to_bezier_assign(nurbs_spline.radii(), output->radii(), knots_mode);
+ nurbs_to_bezier_assign(nurbs_spline.tilts(), output->tilts(), knots_mode);
+ scale_input_assign(handle_positions.as_span(), 2, 0, output->handle_positions_left());
+ scale_input_assign(handle_positions.as_span(), 2, 1, output->handle_positions_right());
output->handle_types_left().fill(BezierSpline::HandleType::Align);
output->handle_types_right().fill(BezierSpline::HandleType::Align);
output->set_resolution(nurbs_spline.resolution());
- Spline::copy_base_settings(input, *output);
+ Spline::copy_base_settings(nurbs_spline, *output);
output->attributes.reallocate(output->size());
- copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) {
+ copy_attributes(nurbs_spline, *output, [knots_mode](GSpan src, GMutableSpan dst) {
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
- scale_input_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>());
+ nurbs_to_bezier_assign(src.typed<T>(), dst.typed<T>(), knots_mode);
});
});
return output;
@@ -205,20 +334,13 @@ static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params
case Spline::Type::Poly:
return poly_to_bezier(input);
case Spline::Type::NURBS:
- if (input.size() < 6) {
+ if (input.size() < 4) {
params.error_message_add(
NodeWarningType::Info,
- TIP_("NURBS must have minimum of 6 points for Bezier Conversion"));
+ TIP_("NURBS must have minimum of 4 points for Bezier Conversion"));
return input.copy();
}
- else {
- if (input.size() % 3 != 0) {
- params.error_message_add(NodeWarningType::Info,
- TIP_("NURBS must have multiples of 3 points for full Bezier "
- "conversion, curve truncated"));
- }
- return nurbs_to_bezier(input);
- }
+ return nurbs_to_bezier(input);
}
BLI_assert_unreachable();
return {};
@@ -298,8 +420,7 @@ void register_node_type_geo_curve_spline_type()
namespace file_ns = blender::nodes::node_geo_curve_spline_type_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index 6de188fc1c4..c2b9ddfb114 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -30,7 +30,12 @@ namespace blender::nodes::node_geo_curve_subdivide_cc {
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();
+ b.add_input<decl::Int>(N_("Cuts"))
+ .default_value(1)
+ .min(0)
+ .max(1000)
+ .supports_field()
+ .description(N_("The number of control points to create on the segment following each point"));
b.add_output<decl::Geometry>(N_("Curve"));
}
@@ -359,7 +364,7 @@ void register_node_type_geo_curve_subdivide()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide Curve", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index ff3e85cb6b7..ef4fc51d1b3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -80,7 +80,7 @@ void register_node_type_geo_curve_to_mesh()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index 2f9dfa8158b..19efd4b7508 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
@@ -47,8 +47,18 @@ NODE_STORAGE_FUNCS(NodeGeometryCurveToPoints)
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();
@@ -62,8 +72,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
- sizeof(NodeGeometryCurveToPoints), __func__);
+ NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__);
data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
node->storage = data;
@@ -276,7 +285,7 @@ static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines,
spline.sample_with_index_factors<float3>(
spline.evaluated_tangents(), uniform_samples, data.tangents.slice(offset, size));
for (float3 &tangent : data.tangents) {
- tangent.normalize();
+ tangent = math::normalize(tangent);
}
}
@@ -284,7 +293,7 @@ static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines,
spline.sample_with_index_factors<float3>(
spline.evaluated_normals(), uniform_samples, data.normals.slice(offset, size));
for (float3 &normals : data.normals) {
- normals.normalize();
+ normals = math::normalize(normals);
}
}
}
@@ -393,7 +402,7 @@ void register_node_type_geo_curve_to_points()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
@@ -401,6 +410,5 @@ void register_node_type_geo_curve_to_points()
&ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
-
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index 449d0d14092..359863d39e0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -20,6 +20,8 @@
#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 {
@@ -31,21 +33,29 @@ NODE_STORAGE_FUNCS(NodeGeometryCurveTrim)
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"));
}
@@ -57,8 +67,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim),
- __func__);
+ NodeGeometryCurveTrim *data = MEM_cnew<NodeGeometryCurveTrim>(__func__);
data->mode = GEO_NODE_CURVE_SAMPLE_FACTOR;
node->storage = data;
@@ -80,6 +89,38 @@ static void node_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;
@@ -566,7 +607,7 @@ void register_node_type_geo_curve_trim()
namespace file_ns = blender::nodes::node_geo_curve_trim_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
ntype.declare = file_ns::node_declare;
@@ -574,5 +615,6 @@ void register_node_type_geo_curve_trim()
&ntype, "NodeGeometryCurveTrim", node_free_standard_storage, node_copy_standard_storage);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
+ ntype.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 1de809b30e4..8b762abd29b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -29,7 +29,7 @@
#include "node_geometry_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_geo_delete_geometry_cc {
using blender::bke::CustomDataAttributes;
@@ -529,6 +529,30 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set,
geometry_set.replace_pointcloud(pointcloud);
}
+static void separate_instance_selection(GeometrySet &geometry_set,
+ const Field<bool> &selection_field,
+ const bool invert)
+{
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
+
+ const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+ const VArray_Span<bool> &selection = evaluator.get_evaluated<bool>(0);
+
+ Vector<int64_t> indices;
+ const IndexMask mask = index_mask_indices(selection, invert, indices);
+
+ if (mask.is_empty()) {
+ geometry_set.remove<InstancesComponent>();
+ return;
+ }
+
+ instances.remove_instances(mask);
+}
+
static void compute_selected_vertices_from_vertex_selection(const Span<bool> vertex_selection,
const bool invert,
MutableSpan<int> r_vertex_map,
@@ -979,8 +1003,8 @@ static void do_mesh_separation(GeometrySet &geometry_set,
/* Needed in all cases. */
Vector<int> selected_poly_indices;
Vector<int> new_loop_starts;
- int num_selected_polys;
- int num_selected_loops;
+ int num_selected_polys = 0;
+ int num_selected_loops = 0;
const Mesh &mesh_in = *in_component.get_for_read();
Mesh *mesh_out;
@@ -1246,6 +1270,10 @@ static void separate_mesh_selection(GeometrySet &geometry_set,
do_mesh_separation(geometry_set, src_component, selection, invert, selection_domain, mode);
}
+} // namespace blender::nodes::node_geo_delete_geometry_cc
+
+namespace blender::nodes {
+
void separate_geometry(GeometrySet &geometry_set,
const AttributeDomain domain,
const GeometryNodeDeleteGeometryMode mode,
@@ -1253,22 +1281,30 @@ void separate_geometry(GeometrySet &geometry_set,
const bool invert,
bool &r_is_error)
{
+ namespace file_ns = blender::nodes::node_geo_delete_geometry_cc;
+
bool some_valid_domain = false;
if (geometry_set.has_pointcloud()) {
if (domain == ATTR_DOMAIN_POINT) {
- separate_point_cloud_selection(geometry_set, selection_field, invert);
+ file_ns::separate_point_cloud_selection(geometry_set, selection_field, invert);
some_valid_domain = true;
}
}
if (geometry_set.has_mesh()) {
- if (domain != ATTR_DOMAIN_CURVE) {
- separate_mesh_selection(geometry_set, selection_field, domain, mode, invert);
+ if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER)) {
+ file_ns::separate_mesh_selection(geometry_set, selection_field, domain, mode, invert);
some_valid_domain = true;
}
}
if (geometry_set.has_curve()) {
if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) {
- separate_curve_selection(geometry_set, selection_field, domain, invert);
+ file_ns::separate_curve_selection(geometry_set, selection_field, domain, invert);
+ some_valid_domain = true;
+ }
+ }
+ if (geometry_set.has_instances()) {
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ file_ns::separate_instance_selection(geometry_set, selection_field, invert);
some_valid_domain = true;
}
}
@@ -1307,8 +1343,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN(
- sizeof(NodeGeometryDeleteGeometry), __func__);
+ NodeGeometryDeleteGeometry *data = MEM_cnew<NodeGeometryDeleteGeometry>(__func__);
data->domain = ATTR_DOMAIN_POINT;
data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL;
@@ -1325,16 +1360,16 @@ static void node_geo_exec(GeoNodeExecParams params)
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
const GeometryNodeDeleteGeometryMode mode = (GeometryNodeDeleteGeometryMode)storage.mode;
- bool all_is_error = false;
- geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- bool this_is_error = false;
- /* Invert here because we want to keep the things not in the selection. */
- separate_geometry(geometry_set, domain, mode, selection_field, true, this_is_error);
- all_is_error &= this_is_error;
- });
- if (all_is_error) {
- /* Only show this if none of the instances/components actually changed. */
- params.error_message_add(NodeWarningType::Info, TIP_("No geometry with given domain"));
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ bool is_error;
+ separate_geometry(geometry_set, domain, mode, selection_field, true, is_error);
+ }
+ else {
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ bool is_error;
+ /* Invert here because we want to keep the things not in the selection. */
+ separate_geometry(geometry_set, domain, mode, selection_field, true, is_error);
+ });
}
params.set_output("Geometry", std::move(geometry_set));
@@ -1348,7 +1383,7 @@ void register_node_type_geo_delete_geometry()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY);
node_type_storage(&ntype,
"NodeGeometryDeleteGeometry",
diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc
index 3537b62c76e..d17657bfa3a 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
@@ -44,7 +44,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).subtype(PROP_DISTANCE);
b.add_input<decl::Float>(N_("Density Max")).default_value(10.0f).min(0.0f);
- b.add_input<decl::Float>(N_("Density")).default_value(10.0f).supports_field();
+ b.add_input<decl::Float>(N_("Density")).default_value(10.0f).min(0.0f).supports_field();
b.add_input<decl::Float>(N_("Density Factor"))
.default_value(1.0f)
.min(0.0f)
@@ -573,8 +573,7 @@ void register_node_type_geo_distribute_points_on_faces()
geo_node_type_base(&ntype,
GEO_NODE_DISTRIBUTE_POINTS_ON_FACES,
"Distribute Points on Faces",
- NODE_CLASS_GEOMETRY,
- 0);
+ NODE_CLASS_GEOMETRY);
node_type_update(&ntype, file_ns::node_point_distribute_points_on_faces_update);
node_type_size(&ntype, 170, 100, 320);
ntype.declare = file_ns::node_declare;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
index a3bbeca7af3..f6be6c1e7fb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -415,7 +415,7 @@ static void sort_vertex_polys(const Mesh &mesh,
}
}
else {
- /* Any polygon can be the first. Just need to check the orientation.*/
+ /* 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) {
@@ -537,6 +537,77 @@ static void add_edge(const Mesh &mesh,
loop_edges.append(new_edge_i);
}
+/* Returns true if the vertex is connected only to the two polygons and is not on the boundary. */
+static bool vertex_needs_dissolving(const int vertex,
+ const int first_poly_index,
+ const int second_poly_index,
+ const Span<VertexType> vertex_types,
+ const Span<Vector<int>> vertex_poly_indices)
+{
+ /* Order is guaranteed to be the same because 2poly verts that are not on the boundary are
+ * ignored in `sort_vertex_polys`. */
+ return (vertex_types[vertex] != VertexType::Boundary &&
+ vertex_poly_indices[vertex].size() == 2 &&
+ vertex_poly_indices[vertex][0] == first_poly_index &&
+ vertex_poly_indices[vertex][1] == second_poly_index);
+}
+
+/**
+ * Finds 'normal' vertices which are connected to only two polygons and marks them to not be
+ * used in the data-structures derived from the mesh. For each pair of polygons which has such a
+ * vertex, an edge is created for the dual mesh between the centers of those two polygons. All
+ * edges in the input mesh which contain such a vertex are marked as 'done' to prevent duplicate
+ * edges being created. (See T94144)
+ */
+static void dissolve_redundant_verts(const Mesh &mesh,
+ const Span<Vector<int>> vertex_poly_indices,
+ MutableSpan<VertexType> vertex_types,
+ MutableSpan<int> old_to_new_edges_map,
+ Vector<MEdge> &new_edges,
+ Vector<int> &new_to_old_edges_map)
+{
+ for (const int vert_i : IndexRange(mesh.totvert)) {
+ if (vertex_poly_indices[vert_i].size() != 2 || vertex_types[vert_i] != VertexType::Normal) {
+ continue;
+ }
+ const int first_poly_index = vertex_poly_indices[vert_i][0];
+ const int second_poly_index = vertex_poly_indices[vert_i][1];
+ const int new_edge_index = new_edges.size();
+ bool edge_created = false;
+ const MPoly &poly = mesh.mpoly[first_poly_index];
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ const MEdge &edge = mesh.medge[loop.e];
+ const int v1 = edge.v1;
+ const int v2 = edge.v2;
+ bool mark_edge = false;
+ if (vertex_needs_dissolving(
+ v1, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
+ /* This vertex is now 'removed' and should be ignored elsewhere. */
+ vertex_types[v1] = VertexType::Loose;
+ mark_edge = true;
+ }
+ if (vertex_needs_dissolving(
+ v2, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
+ /* This vertex is now 'removed' and should be ignored elsewhere. */
+ vertex_types[v2] = VertexType::Loose;
+ mark_edge = true;
+ }
+ if (mark_edge) {
+ if (!edge_created) {
+ MEdge new_edge = MEdge(edge);
+ /* The vertex indices in the dual mesh are the polygon indices of the input mesh. */
+ new_edge.v1 = first_poly_index;
+ new_edge.v2 = second_poly_index;
+ new_to_old_edges_map.append(loop.e);
+ new_edges.append(new_edge);
+ edge_created = true;
+ }
+ old_to_new_edges_map[loop.e] = new_edge_index;
+ }
+ }
+ }
+}
+
/**
* Calculate the barycentric dual of a mesh. The dual is only "dual" in terms of connectivity,
* i.e. applying the function twice will give the same vertices, edges, and faces, but not the
@@ -564,6 +635,9 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
Array<VertexType> vertex_types(mesh_in.totvert);
Array<EdgeType> edge_types(mesh_in.totedge);
calc_boundaries(mesh_in, vertex_types, edge_types);
+ /* Stores the indices of the polygons connected to the vertex. Because the polygons are looped
+ * over in order of their indices, the polygon's indices will be sorted in ascending order.
+ (This can change once they are sorted using `sort_vertex_polys`). */
Array<Vector<int>> vertex_poly_indices(mesh_in.totvert);
Array<Array<int>> vertex_shared_edges(mesh_in.totvert);
Array<Array<int>> vertex_corners(mesh_in.totvert);
@@ -629,9 +703,19 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
* 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. */
+ * don't need a hash-map for that. */
Array<int> old_to_new_edges_map(mesh_in.totedge);
old_to_new_edges_map.fill(-1);
+
+ /* This is necessary to prevent duplicate edges from being created, but will likely not do
+ * anything for most meshes. */
+ dissolve_redundant_verts(mesh_in,
+ vertex_poly_indices,
+ vertex_types,
+ old_to_new_edges_map,
+ new_edges,
+ new_to_old_edges_map);
+
for (const int i : IndexRange(mesh_in.totvert)) {
if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
(!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
@@ -840,7 +924,7 @@ void register_node_type_geo_dual_mesh()
namespace file_ns = blender::nodes::node_geo_dual_mesh_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_DUAL_MESH, "Dual Mesh", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_DUAL_MESH, "Dual Mesh", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
index d23a18ba37b..9376789cf2c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -90,7 +90,7 @@ void register_node_type_geo_edge_split()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
new file mode 100644
index 00000000000..1d1c5bd2285
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -0,0 +1,1365 @@
+/*
+ * 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_disjoint_set.hh"
+#include "BLI_task.hh"
+#include "BLI_vector_set.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_extrude_mesh_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryExtrudeMesh)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>("Mesh").supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value();
+ b.add_input<decl::Vector>(N_("Offset")).subtype(PROP_TRANSLATION).implicit_field().hide_value();
+ b.add_input<decl::Float>(N_("Offset Scale")).default_value(1.0f).min(0.0f).supports_field();
+ b.add_input<decl::Bool>(N_("Individual")).default_value(true);
+ b.add_output<decl::Geometry>("Mesh");
+ b.add_output<decl::Bool>(N_("Top")).field_source();
+ b.add_output<decl::Bool>(N_("Side")).field_source();
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryExtrudeMesh *data = MEM_cnew<NodeGeometryExtrudeMesh>(__func__);
+ data->mode = GEO_NODE_EXTRUDE_MESH_FACES;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeGeometryExtrudeMesh &storage = node_storage(*node);
+ const GeometryNodeExtrudeMeshMode mode = static_cast<GeometryNodeExtrudeMeshMode>(storage.mode);
+
+ bNodeSocket *individual_socket = (bNodeSocket *)node->inputs.last;
+
+ nodeSetSocketAvailability(ntree, individual_socket, mode == GEO_NODE_EXTRUDE_MESH_FACES);
+}
+
+struct AttributeOutputs {
+ StrongAnonymousAttributeID top_id;
+ StrongAnonymousAttributeID side_id;
+};
+
+static void save_selection_as_attribute(MeshComponent &component,
+ const AnonymousAttributeID *id,
+ const AttributeDomain domain,
+ const IndexMask selection)
+{
+ BLI_assert(!component.attribute_exists(id));
+
+ OutputAttribute_Typed<bool> attribute = component.attribute_try_get_for_output_only<bool>(
+ id, domain);
+ /* Rely on the new attribute being zeroed by default. */
+ BLI_assert(!attribute.as_span().as_span().contains(true));
+
+ if (selection.is_range()) {
+ attribute.as_span().slice(selection.as_range()).fill(true);
+ }
+ else {
+ attribute.as_span().fill_indices(selection, true);
+ }
+
+ attribute.save();
+}
+
+static MutableSpan<MVert> mesh_verts(Mesh &mesh)
+{
+ return {mesh.mvert, mesh.totvert};
+}
+static MutableSpan<MEdge> mesh_edges(Mesh &mesh)
+{
+ return {mesh.medge, mesh.totedge};
+}
+static Span<MPoly> mesh_polys(const Mesh &mesh)
+{
+ return {mesh.mpoly, mesh.totpoly};
+}
+static MutableSpan<MPoly> mesh_polys(Mesh &mesh)
+{
+ return {mesh.mpoly, mesh.totpoly};
+}
+static Span<MLoop> mesh_loops(const Mesh &mesh)
+{
+ return {mesh.mloop, mesh.totloop};
+}
+static MutableSpan<MLoop> mesh_loops(Mesh &mesh)
+{
+ return {mesh.mloop, mesh.totloop};
+}
+
+/**
+ * \note: Some areas in this file rely on the new sections of attributes from #CustomData_realloc
+ * to be zeroed.
+ */
+static void expand_mesh(Mesh &mesh,
+ const int vert_expand,
+ const int edge_expand,
+ const int poly_expand,
+ const int loop_expand)
+{
+ if (vert_expand != 0) {
+ CustomData_duplicate_referenced_layers(&mesh.vdata, mesh.totvert);
+ mesh.totvert += vert_expand;
+ CustomData_realloc(&mesh.vdata, mesh.totvert);
+ }
+ else {
+ /* Even when the number of vertices is not changed, the mesh can still be deformed. */
+ CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert);
+ }
+ if (edge_expand != 0) {
+ CustomData_duplicate_referenced_layers(&mesh.edata, mesh.totedge);
+ mesh.totedge += edge_expand;
+ CustomData_realloc(&mesh.edata, mesh.totedge);
+ }
+ if (poly_expand != 0) {
+ CustomData_duplicate_referenced_layers(&mesh.pdata, mesh.totpoly);
+ mesh.totpoly += poly_expand;
+ CustomData_realloc(&mesh.pdata, mesh.totpoly);
+ }
+ if (loop_expand != 0) {
+ CustomData_duplicate_referenced_layers(&mesh.ldata, mesh.totloop);
+ mesh.totloop += loop_expand;
+ CustomData_realloc(&mesh.ldata, mesh.totloop);
+ }
+ BKE_mesh_update_customdata_pointers(&mesh, false);
+}
+
+static MEdge new_edge(const int v1, const int v2)
+{
+ MEdge edge;
+ edge.v1 = v1;
+ edge.v2 = v2;
+ edge.flag = (ME_EDGEDRAW | ME_EDGERENDER);
+ return edge;
+}
+
+static MEdge new_loose_edge(const int v1, const int v2)
+{
+ MEdge edge;
+ edge.v1 = v1;
+ edge.v2 = v2;
+ edge.flag = ME_LOOSEEDGE;
+ return edge;
+}
+
+static MPoly new_poly(const int loopstart, const int totloop)
+{
+ MPoly poly;
+ poly.loopstart = loopstart;
+ poly.totloop = totloop;
+ poly.flag = 0;
+ return poly;
+}
+
+template<typename T> void copy_with_indices(MutableSpan<T> dst, Span<T> src, Span<int> indices)
+{
+ BLI_assert(dst.size() == indices.size());
+ for (const int i : dst.index_range()) {
+ dst[i] = src[indices[i]];
+ }
+}
+
+template<typename T> void copy_with_mask(MutableSpan<T> dst, Span<T> src, IndexMask mask)
+{
+ BLI_assert(dst.size() == mask.size());
+ threading::parallel_for(mask.index_range(), 512, [&](const IndexRange range) {
+ for (const int i : range) {
+ dst[i] = src[mask[i]];
+ }
+ });
+}
+
+/**
+ * \param get_mix_indices_fn: Returns a Span of indices of the source points to mix for every
+ * result point.
+ */
+template<typename T, typename GetMixIndicesFn>
+void copy_with_mixing(MutableSpan<T> dst, Span<T> src, GetMixIndicesFn get_mix_indices_fn)
+{
+ threading::parallel_for(dst.index_range(), 512, [&](const IndexRange range) {
+ attribute_math::DefaultPropatationMixer<T> mixer{dst.slice(range)};
+ for (const int i_dst : IndexRange(range.size())) {
+ for (const int i_src : get_mix_indices_fn(range[i_dst])) {
+ mixer.mix_in(i_dst, src[i_src]);
+ }
+ }
+ mixer.finalize();
+ });
+}
+
+static Array<Vector<int>> create_vert_to_edge_map(const int vert_size,
+ Span<MEdge> edges,
+ const int vert_offset = 0)
+{
+ Array<Vector<int>> vert_to_edge_map(vert_size);
+ for (const int i : edges.index_range()) {
+ vert_to_edge_map[edges[i].v1 - vert_offset].append(i);
+ vert_to_edge_map[edges[i].v2 - vert_offset].append(i);
+ }
+ return vert_to_edge_map;
+}
+
+static void extrude_mesh_vertices(MeshComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float3> &offset_field,
+ const AttributeOutputs &attribute_outputs)
+{
+ Mesh &mesh = *component.get_for_write();
+ const int orig_vert_size = mesh.totvert;
+ const int orig_edge_size = mesh.totedge;
+
+ GeometryComponentFieldContext context{component, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{context, mesh.totvert};
+ evaluator.add(offset_field);
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> offsets = evaluator.get_evaluated<float3>(0);
+
+ /* This allows parallelizing attribute mixing for new edges. */
+ Array<Vector<int>> vert_to_edge_map = create_vert_to_edge_map(orig_vert_size, mesh_edges(mesh));
+
+ expand_mesh(mesh, selection.size(), selection.size(), 0, 0);
+
+ const IndexRange new_vert_range{orig_vert_size, selection.size()};
+ const IndexRange new_edge_range{orig_edge_size, selection.size()};
+
+ MutableSpan<MVert> new_verts = mesh_verts(mesh).slice(new_vert_range);
+ MutableSpan<MEdge> new_edges = mesh_edges(mesh).slice(new_edge_range);
+
+ for (const int i_selection : selection.index_range()) {
+ new_edges[i_selection] = new_loose_edge(selection[i_selection], new_vert_range[i_selection]);
+ }
+
+ component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (!ELEM(meta_data.domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE)) {
+ return true;
+ }
+ OutputAttribute attribute = component.attribute_try_get_for_output(
+ id, meta_data.domain, meta_data.data_type);
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ MutableSpan<T> data = attribute.as_span().typed<T>();
+ switch (attribute.domain()) {
+ case ATTR_DOMAIN_POINT: {
+ /* New vertices copy the attribute values from their source vertex. */
+ copy_with_mask(data.slice(new_vert_range), data.as_span(), selection);
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ /* New edge values are mixed from of all the edges connected to the source vertex. */
+ copy_with_mixing(data.slice(new_edge_range), data.as_span(), [&](const int i) {
+ return vert_to_edge_map[selection[i]].as_span();
+ });
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+ });
+
+ attribute.save();
+ return true;
+ });
+
+ devirtualize_varray(offsets, [&](const auto offsets) {
+ threading::parallel_for(selection.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ const float3 offset = offsets[selection[i]];
+ add_v3_v3(new_verts[i].co, offset);
+ }
+ });
+ });
+
+ if (attribute_outputs.top_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range);
+ }
+ if (attribute_outputs.side_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.side_id.get(), ATTR_DOMAIN_EDGE, new_edge_range);
+ }
+
+ BKE_mesh_runtime_clear_cache(&mesh);
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+static Array<Vector<int, 2>> mesh_calculate_polys_of_edge(const Mesh &mesh)
+{
+ Span<MPoly> polys = mesh_polys(mesh);
+ Span<MLoop> loops = mesh_loops(mesh);
+ Array<Vector<int, 2>> polys_of_edge(mesh.totedge);
+
+ for (const int i_poly : polys.index_range()) {
+ const MPoly &poly = polys[i_poly];
+ for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
+ polys_of_edge[loop.e].append(i_poly);
+ }
+ }
+
+ return polys_of_edge;
+}
+
+static void fill_quad_consistent_direction(Span<MLoop> other_poly_loops,
+ MutableSpan<MLoop> new_loops,
+ const int vert_connected_to_poly_1,
+ const int vert_connected_to_poly_2,
+ const int vert_across_from_poly_1,
+ const int vert_across_from_poly_2,
+ const int edge_connected_to_poly,
+ const int connecting_edge_1,
+ const int edge_across_from_poly,
+ const int connecting_edge_2)
+{
+ /* Find the loop on the polygon connected to the new quad that uses the duplicate edge. */
+ bool start_with_connecting_edge = true;
+ for (const MLoop &loop : other_poly_loops) {
+ if (loop.e == edge_connected_to_poly) {
+ start_with_connecting_edge = loop.v == vert_connected_to_poly_1;
+ break;
+ }
+ }
+ if (start_with_connecting_edge) {
+ new_loops[0].v = vert_connected_to_poly_1;
+ new_loops[0].e = connecting_edge_1;
+ new_loops[1].v = vert_across_from_poly_1;
+ new_loops[1].e = edge_across_from_poly;
+ new_loops[2].v = vert_across_from_poly_2;
+ new_loops[2].e = connecting_edge_2;
+ new_loops[3].v = vert_connected_to_poly_2;
+ new_loops[3].e = edge_connected_to_poly;
+ }
+ else {
+ new_loops[0].v = vert_connected_to_poly_1;
+ new_loops[0].e = edge_connected_to_poly;
+ new_loops[1].v = vert_connected_to_poly_2;
+ new_loops[1].e = connecting_edge_2;
+ new_loops[2].v = vert_across_from_poly_2;
+ new_loops[2].e = edge_across_from_poly;
+ new_loops[3].v = vert_across_from_poly_1;
+ new_loops[3].e = connecting_edge_1;
+ }
+}
+
+template<typename T>
+static VectorSet<int> vert_indices_from_edges(const Mesh &mesh, const Span<T> edge_indices)
+{
+ static_assert(is_same_any_v<T, int, int64_t>);
+
+ VectorSet<int> vert_indices;
+ vert_indices.reserve(edge_indices.size());
+ for (const T i_edge : edge_indices) {
+ const MEdge &edge = mesh.medge[i_edge];
+ vert_indices.add(edge.v1);
+ vert_indices.add(edge.v2);
+ }
+ return vert_indices;
+}
+
+static void extrude_mesh_edges(MeshComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float3> &offset_field,
+ const AttributeOutputs &attribute_outputs)
+{
+ Mesh &mesh = *component.get_for_write();
+ const int orig_vert_size = mesh.totvert;
+ Span<MEdge> orig_edges = mesh_edges(mesh);
+ Span<MPoly> orig_polys = mesh_polys(mesh);
+ const int orig_loop_size = mesh.totloop;
+
+ GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
+ FieldEvaluator edge_evaluator{edge_context, mesh.totedge};
+ edge_evaluator.set_selection(selection_field);
+ edge_evaluator.add(offset_field);
+ edge_evaluator.evaluate();
+ const IndexMask edge_selection = edge_evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &edge_offsets = edge_evaluator.get_evaluated<float3>(0);
+ if (edge_selection.is_empty()) {
+ return;
+ }
+
+ const Array<Vector<int, 2>> edge_to_poly_map = mesh_calculate_polys_of_edge(mesh);
+
+ /* Find the offsets on the vertex domain for translation. This must be done before the mesh's
+ * custom data layers are reallocated, in case the virtual array references on of them. */
+ Array<float3> vert_offsets;
+ if (!edge_offsets.is_single()) {
+ vert_offsets.reinitialize(orig_vert_size);
+ attribute_math::DefaultPropatationMixer<float3> mixer(vert_offsets);
+ for (const int i_edge : edge_selection) {
+ const MEdge &edge = orig_edges[i_edge];
+ const float3 offset = edge_offsets[i_edge];
+ mixer.mix_in(edge.v1, offset);
+ mixer.mix_in(edge.v2, offset);
+ }
+ mixer.finalize();
+ }
+
+ const VectorSet<int> new_vert_indices = vert_indices_from_edges(mesh, edge_selection.indices());
+
+ const IndexRange new_vert_range{orig_vert_size, new_vert_indices.size()};
+ /* The extruded edges connect the original and duplicate edges. */
+ const IndexRange connect_edge_range{orig_edges.size(), new_vert_range.size()};
+ /* The duplicate edges are extruded copies of the selected edges. */
+ const IndexRange duplicate_edge_range = connect_edge_range.after(edge_selection.size());
+ /* There is a new polygon for every selected edge. */
+ const IndexRange new_poly_range{orig_polys.size(), edge_selection.size()};
+ /* Every new polygon is a quad with four corners. */
+ const IndexRange new_loop_range{orig_loop_size, new_poly_range.size() * 4};
+
+ expand_mesh(mesh,
+ new_vert_range.size(),
+ connect_edge_range.size() + duplicate_edge_range.size(),
+ new_poly_range.size(),
+ new_loop_range.size());
+
+ MutableSpan<MVert> new_verts = mesh_verts(mesh).slice(new_vert_range);
+ MutableSpan<MEdge> connect_edges = mesh_edges(mesh).slice(connect_edge_range);
+ MutableSpan<MEdge> duplicate_edges = mesh_edges(mesh).slice(duplicate_edge_range);
+ MutableSpan<MPoly> polys = mesh_polys(mesh);
+ MutableSpan<MPoly> new_polys = polys.slice(new_poly_range);
+ MutableSpan<MLoop> loops = mesh_loops(mesh);
+ MutableSpan<MLoop> new_loops = loops.slice(new_loop_range);
+
+ for (const int i : connect_edges.index_range()) {
+ connect_edges[i] = new_edge(new_vert_indices[i], new_vert_range[i]);
+ }
+
+ for (const int i : duplicate_edges.index_range()) {
+ const MEdge &orig_edge = mesh.medge[edge_selection[i]];
+ const int i_new_vert_1 = new_vert_indices.index_of(orig_edge.v1);
+ const int i_new_vert_2 = new_vert_indices.index_of(orig_edge.v2);
+ duplicate_edges[i] = new_edge(new_vert_range[i_new_vert_1], new_vert_range[i_new_vert_2]);
+ }
+
+ for (const int i : new_polys.index_range()) {
+ new_polys[i] = new_poly(new_loop_range[i * 4], 4);
+ }
+
+ for (const int i : edge_selection.index_range()) {
+ const int orig_edge_index = edge_selection[i];
+
+ const MEdge &duplicate_edge = duplicate_edges[i];
+ const int new_vert_1 = duplicate_edge.v1;
+ const int new_vert_2 = duplicate_edge.v2;
+ const int extrude_index_1 = new_vert_1 - orig_vert_size;
+ const int extrude_index_2 = new_vert_2 - orig_vert_size;
+
+ Span<int> connected_polys = edge_to_poly_map[orig_edge_index];
+
+ /* When there was a single polygon connected to the new polygon, we can use the old one to keep
+ * the face direction consistent. When there is more than one connected edge, the new face
+ * direction is totally arbitrary and the only goal for the behavior is to be deterministic. */
+ Span<MLoop> connected_poly_loops = {};
+ if (connected_polys.size() == 1) {
+ const MPoly &connected_poly = polys[connected_polys.first()];
+ connected_poly_loops = loops.slice(connected_poly.loopstart, connected_poly.totloop);
+ }
+ fill_quad_consistent_direction(connected_poly_loops,
+ new_loops.slice(4 * i, 4),
+ new_vert_indices[extrude_index_1],
+ new_vert_indices[extrude_index_2],
+ new_vert_1,
+ new_vert_2,
+ orig_edge_index,
+ connect_edge_range[extrude_index_1],
+ duplicate_edge_range[i],
+ connect_edge_range[extrude_index_2]);
+ }
+
+ /* Create a map of indices in the extruded vertices array to all of the indices of edges
+ * in the duplicate edges array that connect to that vertex. This can be used to simplify the
+ * mixing of attribute data for the connecting edges. */
+ const Array<Vector<int>> new_vert_to_duplicate_edge_map = create_vert_to_edge_map(
+ new_vert_range.size(), duplicate_edges, orig_vert_size);
+
+ component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ OutputAttribute attribute = component.attribute_try_get_for_output(
+ id, meta_data.domain, meta_data.data_type);
+ if (!attribute) {
+ return true; /* Impossible to write the "normal" attribute. */
+ }
+
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ MutableSpan<T> data = attribute.as_span().typed<T>();
+ switch (attribute.domain()) {
+ case ATTR_DOMAIN_POINT: {
+ /* New vertices copy the attribute values from their source vertex. */
+ copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices);
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ /* Edges parallel to original edges copy the edge attributes from the original edges. */
+ MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range);
+ copy_with_mask(duplicate_data, data.as_span(), edge_selection);
+
+ /* Edges connected to original vertices mix values of selected connected edges. */
+ MutableSpan<T> connect_data = data.slice(connect_edge_range);
+ copy_with_mixing(connect_data, duplicate_data.as_span(), [&](const int i_new_vert) {
+ return new_vert_to_duplicate_edge_map[i_new_vert].as_span();
+ });
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ /* Attribute values for new faces are a mix of the values of faces connected to the its
+ * original edge. */
+ copy_with_mixing(data.slice(new_poly_range), data.as_span(), [&](const int i) {
+ return edge_to_poly_map[edge_selection[i]].as_span();
+ });
+
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ /* New corners get the average value of all adjacent corners on original faces connected
+ * to the original edge of their face. */
+ MutableSpan<T> new_data = data.slice(new_loop_range);
+ threading::parallel_for(edge_selection.index_range(), 256, [&](const IndexRange range) {
+ for (const int i_edge_selection : range) {
+ const int orig_edge_index = edge_selection[i_edge_selection];
+
+ Span<int> connected_polys = edge_to_poly_map[orig_edge_index];
+ if (connected_polys.is_empty()) {
+ /* If there are no connected polygons, there is no corner data to
+ * interpolate. */
+ new_data.slice(4 * i_edge_selection, 4).fill(T());
+ continue;
+ }
+
+ /* Both corners on each vertical edge of the side polygon get the same value,
+ * so there are only two unique values to mix. */
+ Array<T> side_poly_corner_data(2);
+ attribute_math::DefaultPropatationMixer<T> mixer{side_poly_corner_data};
+
+ const MEdge &duplicate_edge = duplicate_edges[i_edge_selection];
+ const int new_vert_1 = duplicate_edge.v1;
+ const int new_vert_2 = duplicate_edge.v2;
+ const int orig_vert_1 = new_vert_indices[new_vert_1 - orig_vert_size];
+ const int orig_vert_2 = new_vert_indices[new_vert_2 - orig_vert_size];
+
+ /* Average the corner data from the corners that share a vertex from the
+ * polygons that share an edge with the extruded edge. */
+ for (const int i_connected_poly : connected_polys.index_range()) {
+ const MPoly &connected_poly = polys[connected_polys[i_connected_poly]];
+ for (const int i_loop :
+ IndexRange(connected_poly.loopstart, connected_poly.totloop)) {
+ const MLoop &loop = loops[i_loop];
+ if (loop.v == orig_vert_1) {
+ mixer.mix_in(0, data[i_loop]);
+ }
+ if (loop.v == orig_vert_2) {
+ mixer.mix_in(1, data[i_loop]);
+ }
+ }
+ }
+
+ mixer.finalize();
+
+ /* Instead of replicating the order in #fill_quad_consistent_direction here, it's
+ * simpler (though probably slower) to just match the corner data based on the vertex
+ * indices. */
+ for (const int i : IndexRange(4 * i_edge_selection, 4)) {
+ if (ELEM(new_loops[i].v, new_vert_1, orig_vert_1)) {
+ new_data[i] = side_poly_corner_data.first();
+ }
+ else if (ELEM(new_loops[i].v, new_vert_2, orig_vert_2)) {
+ new_data[i] = side_poly_corner_data.last();
+ }
+ }
+ }
+ });
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+ });
+
+ attribute.save();
+ return true;
+ });
+
+ if (edge_offsets.is_single()) {
+ const float3 offset = edge_offsets.get_internal_single();
+ threading::parallel_for(new_verts.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ add_v3_v3(new_verts[i].co, offset);
+ }
+ });
+ }
+ else {
+ threading::parallel_for(new_verts.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ add_v3_v3(new_verts[i].co, vert_offsets[new_vert_indices[i]]);
+ }
+ });
+ }
+
+ if (attribute_outputs.top_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range);
+ }
+ if (attribute_outputs.side_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, new_poly_range);
+ }
+
+ BKE_mesh_runtime_clear_cache(&mesh);
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+/**
+ * Edges connected to one selected face are on the boundary of a region and will be duplicated into
+ * a "side face". Edges inside a region will be duplicated to leave any original faces unchanged.
+ */
+static void extrude_mesh_face_regions(MeshComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float3> &offset_field,
+ const AttributeOutputs &attribute_outputs)
+{
+ Mesh &mesh = *component.get_for_write();
+ const int orig_vert_size = mesh.totvert;
+ Span<MEdge> orig_edges = mesh_edges(mesh);
+ Span<MPoly> orig_polys = mesh_polys(mesh);
+ Span<MLoop> orig_loops = mesh_loops(mesh);
+
+ GeometryComponentFieldContext poly_context{component, ATTR_DOMAIN_FACE};
+ FieldEvaluator poly_evaluator{poly_context, mesh.totpoly};
+ poly_evaluator.set_selection(selection_field);
+ poly_evaluator.add(offset_field);
+ poly_evaluator.evaluate();
+ const IndexMask poly_selection = poly_evaluator.get_evaluated_selection_as_mask();
+ const VArray<float3> &poly_offsets = poly_evaluator.get_evaluated<float3>(0);
+ if (poly_selection.is_empty()) {
+ return;
+ }
+
+ Array<bool> poly_selection_array(orig_polys.size(), false);
+ for (const int i_poly : poly_selection) {
+ poly_selection_array[i_poly] = true;
+ }
+
+ /* Mix the offsets from the face domain to the vertex domain. Evaluate on the face domain above
+ * in order to be consistent with the selection, and to use the face normals rather than vertex
+ * normals as an offset, for example. */
+ Array<float3> vert_offsets;
+ if (!poly_offsets.is_single()) {
+ vert_offsets.reinitialize(orig_vert_size);
+ attribute_math::DefaultPropatationMixer<float3> mixer(vert_offsets);
+ for (const int i_poly : poly_selection) {
+ const MPoly &poly = orig_polys[i_poly];
+ const float3 offset = poly_offsets[i_poly];
+ for (const MLoop &loop : orig_loops.slice(poly.loopstart, poly.totloop)) {
+ mixer.mix_in(loop.v, offset);
+ }
+ }
+ mixer.finalize();
+ }
+
+ /* All of the faces (selected and deselected) connected to each edge. */
+ const Array<Vector<int, 2>> edge_to_poly_map = mesh_calculate_polys_of_edge(mesh);
+
+ /* All vertices that are connected to the selected polygons.
+ * Start the size at one vert per poly to reduce unnecessary reallocation. */
+ VectorSet<int> all_selected_verts;
+ all_selected_verts.reserve(orig_polys.size());
+ for (const int i_poly : poly_selection) {
+ const MPoly &poly = orig_polys[i_poly];
+ for (const MLoop &loop : orig_loops.slice(poly.loopstart, poly.totloop)) {
+ all_selected_verts.add(loop.v);
+ }
+ }
+
+ /* Edges inside of an extruded region that are also attached to deselected edges. They must be
+ * duplicated in order to leave the old edge attached to the unchanged deselected faces. */
+ VectorSet<int> new_inner_edge_indices;
+ /* Edges inside of an extruded region. Their vertices should be translated
+ * with the offset, but the edges themselves should not be duplicated. */
+ Vector<int> inner_edge_indices;
+ /* The extruded face corresponding to each boundary edge (and each boundary face). */
+ Vector<int> edge_extruded_face_indices;
+ /* Edges on the outside of selected regions, either because there are no
+ * other connected faces, or because all of the other faces aren't selected. */
+ VectorSet<int> boundary_edge_indices;
+ for (const int i_edge : orig_edges.index_range()) {
+ Span<int> polys = edge_to_poly_map[i_edge];
+
+ int i_selected_poly = -1;
+ int deselected_poly_count = 0;
+ int selected_poly_count = 0;
+ for (const int i_other_poly : polys) {
+ if (poly_selection_array[i_other_poly]) {
+ selected_poly_count++;
+ i_selected_poly = i_other_poly;
+ }
+ else {
+ deselected_poly_count++;
+ }
+ }
+
+ if (selected_poly_count == 1) {
+ /* If there is only one selected polygon connected to the edge,
+ * the edge should be extruded to form a "side face". */
+ boundary_edge_indices.add_new(i_edge);
+ edge_extruded_face_indices.append(i_selected_poly);
+ }
+ else if (selected_poly_count > 1) {
+ /* The edge is inside an extruded region of faces. */
+ if (deselected_poly_count > 0) {
+ /* Add edges that are also connected to deselected edges to a separate list. */
+ new_inner_edge_indices.add_new(i_edge);
+ }
+ else {
+ /* Otherwise, just keep track of edges inside the region so that
+ * we can reattach them to duplicated vertices if necessary. */
+ inner_edge_indices.append(i_edge);
+ }
+ }
+ }
+
+ VectorSet<int> new_vert_indices = vert_indices_from_edges(mesh, boundary_edge_indices.as_span());
+ /* Before adding the rest of the new vertices from the new inner edges, store the number
+ * of new vertices from the boundary edges, since this is the number of connecting edges. */
+ const int extruded_vert_size = new_vert_indices.size();
+
+ /* The vertices attached to duplicate inner edges also have to be duplicated. */
+ for (const int i_edge : new_inner_edge_indices) {
+ const MEdge &edge = mesh.medge[i_edge];
+ new_vert_indices.add(edge.v1);
+ new_vert_indices.add(edge.v2);
+ }
+
+ /* New vertices forming the duplicated boundary edges and the ends of the new inner edges. */
+ const IndexRange new_vert_range{orig_vert_size, new_vert_indices.size()};
+ /* One edge connects each selected vertex to a new vertex on the extruded polygons. */
+ const IndexRange connect_edge_range{orig_edges.size(), extruded_vert_size};
+ /* Each selected edge is duplicated to form a single edge on the extrusion. */
+ const IndexRange boundary_edge_range = connect_edge_range.after(boundary_edge_indices.size());
+ /* Duplicated edges inside regions that were connected to deselected faces. */
+ const IndexRange new_inner_edge_range = boundary_edge_range.after(new_inner_edge_indices.size());
+ /* Each edge selected for extrusion is extruded into a single face. */
+ const IndexRange side_poly_range{orig_polys.size(), boundary_edge_indices.size()};
+ /* The loops that form the new side faces. */
+ const IndexRange side_loop_range{orig_loops.size(), side_poly_range.size() * 4};
+
+ expand_mesh(mesh,
+ new_vert_range.size(),
+ connect_edge_range.size() + boundary_edge_range.size() + new_inner_edge_range.size(),
+ side_poly_range.size(),
+ side_loop_range.size());
+
+ MutableSpan<MEdge> edges = mesh_edges(mesh);
+ MutableSpan<MEdge> connect_edges = edges.slice(connect_edge_range);
+ MutableSpan<MEdge> boundary_edges = edges.slice(boundary_edge_range);
+ MutableSpan<MEdge> new_inner_edges = edges.slice(new_inner_edge_range);
+ MutableSpan<MPoly> polys = mesh_polys(mesh);
+ MutableSpan<MPoly> new_polys = polys.slice(side_poly_range);
+ MutableSpan<MLoop> loops = mesh_loops(mesh);
+ MutableSpan<MLoop> new_loops = loops.slice(side_loop_range);
+
+ /* Initialize the edges that form the sides of the extrusion. */
+ for (const int i : connect_edges.index_range()) {
+ connect_edges[i] = new_edge(new_vert_indices[i], new_vert_range[i]);
+ }
+
+ /* Initialize the edges that form the top of the extrusion. */
+ for (const int i : boundary_edges.index_range()) {
+ const MEdge &orig_edge = edges[boundary_edge_indices[i]];
+ const int i_new_vert_1 = new_vert_indices.index_of(orig_edge.v1);
+ const int i_new_vert_2 = new_vert_indices.index_of(orig_edge.v2);
+ boundary_edges[i] = new_edge(new_vert_range[i_new_vert_1], new_vert_range[i_new_vert_2]);
+ }
+
+ /* Initialize the new edges inside of extrude regions. */
+ for (const int i : new_inner_edge_indices.index_range()) {
+ const MEdge &orig_edge = edges[new_inner_edge_indices[i]];
+ const int i_new_vert_1 = new_vert_indices.index_of(orig_edge.v1);
+ const int i_new_vert_2 = new_vert_indices.index_of(orig_edge.v2);
+ new_inner_edges[i] = new_edge(new_vert_range[i_new_vert_1], new_vert_range[i_new_vert_2]);
+ }
+
+ /* Initialize the new side polygons. */
+ for (const int i : new_polys.index_range()) {
+ new_polys[i] = new_poly(side_loop_range[i * 4], 4);
+ }
+
+ /* Connect original edges inside face regions to any new vertices, if necessary. */
+ for (const int i : inner_edge_indices) {
+ MEdge &edge = edges[i];
+ const int i_new_vert_1 = new_vert_indices.index_of_try(edge.v1);
+ const int i_new_vert_2 = new_vert_indices.index_of_try(edge.v2);
+ if (i_new_vert_1 != -1) {
+ edge.v1 = new_vert_range[i_new_vert_1];
+ }
+ if (i_new_vert_2 != -1) {
+ edge.v2 = new_vert_range[i_new_vert_2];
+ }
+ }
+
+ /* Connect the selected faces to the extruded or duplicated edges and the new vertices. */
+ for (const int i_poly : poly_selection) {
+ const MPoly &poly = polys[i_poly];
+ for (MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
+ const int i_new_vert = new_vert_indices.index_of_try(loop.v);
+ if (i_new_vert != -1) {
+ loop.v = new_vert_range[i_new_vert];
+ }
+ const int i_boundary_edge = boundary_edge_indices.index_of_try(loop.e);
+ if (i_boundary_edge != -1) {
+ loop.e = boundary_edge_range[i_boundary_edge];
+ /* Skip the next check, an edge cannot be both a boundary edge and an inner edge. */
+ continue;
+ }
+ const int i_new_inner_edge = new_inner_edge_indices.index_of_try(loop.e);
+ if (i_new_inner_edge != -1) {
+ loop.e = new_inner_edge_range[i_new_inner_edge];
+ }
+ }
+ }
+
+ /* Create the faces on the sides of extruded regions. */
+ for (const int i : boundary_edge_indices.index_range()) {
+ const MEdge &boundary_edge = boundary_edges[i];
+ const int new_vert_1 = boundary_edge.v1;
+ const int new_vert_2 = boundary_edge.v2;
+ const int extrude_index_1 = new_vert_1 - orig_vert_size;
+ const int extrude_index_2 = new_vert_2 - orig_vert_size;
+
+ const MPoly &extrude_poly = polys[edge_extruded_face_indices[i]];
+
+ fill_quad_consistent_direction(loops.slice(extrude_poly.loopstart, extrude_poly.totloop),
+ new_loops.slice(4 * i, 4),
+ new_vert_1,
+ new_vert_2,
+ new_vert_indices[extrude_index_1],
+ new_vert_indices[extrude_index_2],
+ boundary_edge_range[i],
+ connect_edge_range[extrude_index_1],
+ boundary_edge_indices[i],
+ connect_edge_range[extrude_index_2]);
+ }
+
+ /* Create a map of indices in the extruded vertices array to all of the indices of edges
+ * in the duplicate edges array that connect to that vertex. This can be used to simplify the
+ * mixing of attribute data for the connecting edges. */
+ const Array<Vector<int>> new_vert_to_duplicate_edge_map = create_vert_to_edge_map(
+ new_vert_range.size(), boundary_edges, orig_vert_size);
+
+ component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ OutputAttribute attribute = component.attribute_try_get_for_output(
+ id, meta_data.domain, meta_data.data_type);
+ if (!attribute) {
+ return true; /* Impossible to write the "normal" attribute. */
+ }
+
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ MutableSpan<T> data = attribute.as_span().typed<T>();
+ switch (attribute.domain()) {
+ case ATTR_DOMAIN_POINT: {
+ /* New vertices copy the attributes from their original vertices. */
+ copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices);
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ /* Edges parallel to original edges copy the edge attributes from the original edges. */
+ MutableSpan<T> boundary_data = data.slice(boundary_edge_range);
+ copy_with_indices(boundary_data, data.as_span(), boundary_edge_indices);
+
+ /* Edges inside of face regions also just duplicate their source data. */
+ MutableSpan<T> new_inner_data = data.slice(new_inner_edge_range);
+ copy_with_indices(new_inner_data, data.as_span(), new_inner_edge_indices);
+
+ /* Edges connected to original vertices mix values of selected connected edges. */
+ MutableSpan<T> connect_data = data.slice(connect_edge_range);
+ copy_with_mixing(connect_data, boundary_data.as_span(), [&](const int i) {
+ return new_vert_to_duplicate_edge_map[i].as_span();
+ });
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ /* New faces on the side of extrusions get the values from the corresponding selected
+ * face. */
+ copy_with_indices(
+ data.slice(side_poly_range), data.as_span(), edge_extruded_face_indices);
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ /* New corners get the values from the corresponding corner on the extruded face. */
+ MutableSpan<T> new_data = data.slice(side_loop_range);
+ threading::parallel_for(
+ boundary_edge_indices.index_range(), 256, [&](const IndexRange range) {
+ for (const int i_boundary_edge : range) {
+ const MPoly &poly = polys[edge_extruded_face_indices[i_boundary_edge]];
+
+ const MEdge &boundary_edge = boundary_edges[i_boundary_edge];
+ const int new_vert_1 = boundary_edge.v1;
+ const int new_vert_2 = boundary_edge.v2;
+ const int orig_vert_1 = new_vert_indices[new_vert_1 - orig_vert_size];
+ const int orig_vert_2 = new_vert_indices[new_vert_2 - orig_vert_size];
+
+ /* Retrieve the data for the first two sides of the quad from the extruded
+ * polygon, which we generally expect to have just a small amount of sides. This
+ * loop could be eliminated by adding a cache of connected loops (which would
+ * also simplify some of the other code to find the correct loops on the extruded
+ * face). */
+ T data_1;
+ T data_2;
+ for (const int i_loop : IndexRange(poly.loopstart, poly.totloop)) {
+ if (loops[i_loop].v == new_vert_1) {
+ data_1 = data[i_loop];
+ }
+ if (loops[i_loop].v == new_vert_2) {
+ data_2 = data[i_loop];
+ }
+ }
+
+ /* Instead of replicating the order in #fill_quad_consistent_direction here, it's
+ * simpler (though probably slower) to just match the corner data based on the
+ * vertex indices. */
+ for (const int i : IndexRange(4 * i_boundary_edge, 4)) {
+ if (ELEM(new_loops[i].v, new_vert_1, orig_vert_1)) {
+ new_data[i] = data_1;
+ }
+ else if (ELEM(new_loops[i].v, new_vert_2, orig_vert_2)) {
+ new_data[i] = data_2;
+ }
+ }
+ }
+ });
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+ });
+
+ attribute.save();
+ return true;
+ });
+
+ /* Translate vertices based on the offset. If the vertex is used by a selected edge, it will
+ * have been duplicated and only the new vertex should use the offset. Otherwise the vertex might
+ * still need an offset, but it was reused on the inside of a region of extruded faces. */
+ if (poly_offsets.is_single()) {
+ const float3 offset = poly_offsets.get_internal_single();
+ threading::parallel_for(
+ IndexRange(all_selected_verts.size()), 1024, [&](const IndexRange range) {
+ for (const int i_orig : all_selected_verts.as_span().slice(range)) {
+ const int i_new = new_vert_indices.index_of_try(i_orig);
+ MVert &vert = mesh_verts(mesh)[(i_new == -1) ? i_orig : new_vert_range[i_new]];
+ add_v3_v3(vert.co, offset);
+ }
+ });
+ }
+ else {
+ threading::parallel_for(
+ IndexRange(all_selected_verts.size()), 1024, [&](const IndexRange range) {
+ for (const int i_orig : all_selected_verts.as_span().slice(range)) {
+ const int i_new = new_vert_indices.index_of_try(i_orig);
+ const float3 offset = vert_offsets[i_orig];
+ MVert &vert = mesh_verts(mesh)[(i_new == -1) ? i_orig : new_vert_range[i_new]];
+ add_v3_v3(vert.co, offset);
+ }
+ });
+ }
+
+ if (attribute_outputs.top_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
+ }
+ if (attribute_outputs.side_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
+ }
+
+ BKE_mesh_runtime_clear_cache(&mesh);
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+/* Get the range into an array of extruded corners, edges, or vertices for a particular polygon. */
+static IndexRange selected_corner_range(Span<int> offsets, const int index)
+{
+ const int offset = offsets[index];
+ const int next_offset = offsets[index + 1];
+ return IndexRange(offset, next_offset - offset);
+}
+
+static void extrude_individual_mesh_faces(MeshComponent &component,
+ const Field<bool> &selection_field,
+ const Field<float3> &offset_field,
+ const AttributeOutputs &attribute_outputs)
+{
+ Mesh &mesh = *component.get_for_write();
+ const int orig_vert_size = mesh.totvert;
+ const int orig_edge_size = mesh.totedge;
+ Span<MPoly> orig_polys = mesh_polys(mesh);
+ Span<MLoop> orig_loops = mesh_loops(mesh);
+
+ /* Use a mesh for the result of the evaluation because the mesh is reallocated before
+ * the vertices are moved, and the evaluated result might reference an attribute. */
+ Array<float3> poly_offset(orig_polys.size());
+ GeometryComponentFieldContext poly_context{component, ATTR_DOMAIN_FACE};
+ FieldEvaluator poly_evaluator{poly_context, mesh.totpoly};
+ poly_evaluator.set_selection(selection_field);
+ poly_evaluator.add_with_destination(offset_field, poly_offset.as_mutable_span());
+ poly_evaluator.evaluate();
+ const IndexMask poly_selection = poly_evaluator.get_evaluated_selection_as_mask();
+
+ /* Build an array of offsets into the new data for each polygon. This is used to facilitate
+ * parallelism later on by avoiding the need to keep track of an offset when iterating through
+ * all polygons. */
+ int extrude_corner_size = 0;
+ Array<int> index_offsets(poly_selection.size() + 1);
+ for (const int i_selection : poly_selection.index_range()) {
+ const MPoly &poly = orig_polys[poly_selection[i_selection]];
+ index_offsets[i_selection] = extrude_corner_size;
+ extrude_corner_size += poly.totloop;
+ }
+ index_offsets.last() = extrude_corner_size;
+
+ const IndexRange new_vert_range{orig_vert_size, extrude_corner_size};
+ /* One edge connects each selected vertex to a new vertex on the extruded polygons. */
+ const IndexRange connect_edge_range{orig_edge_size, extrude_corner_size};
+ /* Each selected edge is duplicated to form a single edge on the extrusion. */
+ const IndexRange duplicate_edge_range = connect_edge_range.after(extrude_corner_size);
+ /* Each edge selected for extrusion is extruded into a single face. */
+ const IndexRange side_poly_range{orig_polys.size(), duplicate_edge_range.size()};
+ const IndexRange side_loop_range{orig_loops.size(), side_poly_range.size() * 4};
+
+ expand_mesh(mesh,
+ new_vert_range.size(),
+ connect_edge_range.size() + duplicate_edge_range.size(),
+ side_poly_range.size(),
+ side_loop_range.size());
+
+ MutableSpan<MVert> new_verts = mesh_verts(mesh).slice(new_vert_range);
+ MutableSpan<MEdge> edges{mesh.medge, mesh.totedge};
+ MutableSpan<MEdge> connect_edges = edges.slice(connect_edge_range);
+ MutableSpan<MEdge> duplicate_edges = edges.slice(duplicate_edge_range);
+ MutableSpan<MPoly> polys{mesh.mpoly, mesh.totpoly};
+ MutableSpan<MPoly> new_polys = polys.slice(side_poly_range);
+ MutableSpan<MLoop> loops{mesh.mloop, mesh.totloop};
+
+ /* For every selected polygon, build the faces that form the sides of the extrusion. Filling some
+ * of this data like the new edges or polygons could be easily split into separate loops, which
+ * may or may not be faster, and would involve more duplication. */
+ threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection);
+
+ const MPoly &poly = polys[poly_selection[i_selection]];
+ Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+
+ for (const int i : IndexRange(poly.totloop)) {
+ const int i_next = (i == poly.totloop - 1) ? 0 : i + 1;
+ const MLoop &orig_loop = poly_loops[i];
+ const MLoop &orig_loop_next = poly_loops[i_next];
+
+ const int i_extrude = poly_corner_range[i];
+ const int i_extrude_next = poly_corner_range[i_next];
+
+ const int i_duplicate_edge = duplicate_edge_range[i_extrude];
+ const int new_vert = new_vert_range[i_extrude];
+ const int new_vert_next = new_vert_range[i_extrude_next];
+
+ const int orig_edge = orig_loop.e;
+
+ const int orig_vert = orig_loop.v;
+ const int orig_vert_next = orig_loop_next.v;
+
+ duplicate_edges[i_extrude] = new_edge(new_vert, new_vert_next);
+
+ new_polys[i_extrude] = new_poly(side_loop_range[i_extrude * 4], 4);
+
+ MutableSpan<MLoop> side_loops = loops.slice(side_loop_range[i_extrude * 4], 4);
+ side_loops[0].v = new_vert_next;
+ side_loops[0].e = i_duplicate_edge;
+ side_loops[1].v = new_vert;
+ side_loops[1].e = connect_edge_range[i_extrude];
+ side_loops[2].v = orig_vert;
+ side_loops[2].e = orig_edge;
+ side_loops[3].v = orig_vert_next;
+ side_loops[3].e = connect_edge_range[i_extrude_next];
+
+ connect_edges[i_extrude] = new_edge(orig_vert, new_vert);
+ }
+ }
+ });
+
+ component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ OutputAttribute attribute = component.attribute_try_get_for_output(
+ id, meta_data.domain, meta_data.data_type);
+ if (!attribute) {
+ return true; /* Impossible to write the "normal" attribute. */
+ }
+
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ MutableSpan<T> data = attribute.as_span().typed<T>();
+ switch (attribute.domain()) {
+ case ATTR_DOMAIN_POINT: {
+ /* New vertices copy the attributes from their original vertices. */
+ MutableSpan<T> new_data = data.slice(new_vert_range);
+
+ threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const MPoly &poly = polys[poly_selection[i_selection]];
+ Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+
+ const int corner_offset = index_offsets[i_selection];
+ for (const int i : poly_loops.index_range()) {
+ const int orig_index = poly_loops[i].v;
+ new_data[corner_offset + i] = data[orig_index];
+ }
+ }
+ });
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range);
+ MutableSpan<T> connect_data = data.slice(connect_edge_range);
+
+ threading::parallel_for(poly_selection.index_range(), 512, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const MPoly &poly = polys[poly_selection[i_selection]];
+ Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets,
+ i_selection);
+
+ /* The data for the duplicate edge is simply a copy of the original edge's data. */
+ for (const int i : poly_loops.index_range()) {
+ const int orig_index = poly_loops[i].e;
+ duplicate_data[poly_corner_range[i]] = data[orig_index];
+ }
+
+ /* For the extruded edges, mix the data from the two neighboring original edges of
+ * the extruded polygon. */
+ for (const int i : poly_loops.index_range()) {
+ const int i_loop_prev = (i == 0) ? poly.totloop - 1 : i - 1;
+ const int orig_index = poly_loops[i].e;
+ const int orig_index_prev = poly_loops[i_loop_prev].e;
+ if constexpr (std::is_same_v<T, bool>) {
+ /* Propagate selections with "or" instead of "at least half". */
+ connect_data[poly_corner_range[i]] = data[orig_index] || data[orig_index_prev];
+ }
+ else {
+ connect_data[poly_corner_range[i]] = attribute_math::mix2(
+ 0.5f, data[orig_index], data[orig_index_prev]);
+ }
+ }
+ }
+ });
+ break;
+ }
+ case ATTR_DOMAIN_FACE: {
+ /* Each side face gets the values from the corresponding new face. */
+ MutableSpan<T> new_data = data.slice(side_poly_range);
+ threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const int poly_index = poly_selection[i_selection];
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets,
+ i_selection);
+ new_data.slice(poly_corner_range).fill(data[poly_index]);
+ }
+ });
+ break;
+ }
+ case ATTR_DOMAIN_CORNER: {
+ /* Each corner on a side face gets its value from the matching corner on an extruded
+ * face. */
+ MutableSpan<T> new_data = data.slice(side_loop_range);
+ threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const MPoly &poly = polys[poly_selection[i_selection]];
+ Span<T> poly_loop_data = data.slice(poly.loopstart, poly.totloop);
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets,
+ i_selection);
+
+ for (const int i : IndexRange(poly.totloop)) {
+ const int i_next = (i == poly.totloop - 1) ? 0 : i + 1;
+ const int i_extrude = poly_corner_range[i];
+
+ MutableSpan<T> side_loop_data = new_data.slice(i_extrude * 4, 4);
+
+ /* The two corners on each side of the side polygon get the data from the matching
+ * corners of the extruded polygon. This order depends on the loop filling the loop
+ * indices. */
+ side_loop_data[0] = poly_loop_data[i_next];
+ side_loop_data[1] = poly_loop_data[i];
+ side_loop_data[2] = poly_loop_data[i];
+ side_loop_data[3] = poly_loop_data[i_next];
+ }
+ }
+ });
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+ });
+
+ attribute.save();
+ return true;
+ });
+
+ /* Offset the new vertices. */
+ threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection);
+ for (MVert &vert : new_verts.slice(poly_corner_range)) {
+ add_v3_v3(vert.co, poly_offset[poly_selection[i_selection]]);
+ }
+ }
+ });
+
+ /* Finally update each extruded polygon's loops to point to the new edges and vertices.
+ * This must be done last, because they were used to find original indices for attribute
+ * interpolation before. Alternatively an original index array could be built for each domain. */
+ threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) {
+ for (const int i_selection : range) {
+ const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection);
+
+ const MPoly &poly = polys[poly_selection[i_selection]];
+ MutableSpan<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+
+ for (const int i : IndexRange(poly.totloop)) {
+ MLoop &loop = poly_loops[i];
+ loop.v = new_vert_range[poly_corner_range[i]];
+ loop.e = duplicate_edge_range[poly_corner_range[i]];
+ }
+ }
+ });
+
+ if (attribute_outputs.top_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
+ }
+ if (attribute_outputs.side_id) {
+ save_selection_as_attribute(
+ component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range);
+ }
+
+ BKE_mesh_runtime_clear_cache(&mesh);
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+ Field<bool> selection = params.extract_input<Field<bool>>("Selection");
+ Field<float3> offset_field = params.extract_input<Field<float3>>("Offset");
+ Field<float> scale_field = params.extract_input<Field<float>>("Offset Scale");
+ const NodeGeometryExtrudeMesh &storage = node_storage(params.node());
+ GeometryNodeExtrudeMeshMode mode = static_cast<GeometryNodeExtrudeMeshMode>(storage.mode);
+
+ /* Create a combined field from the offset and the scale so the field evaluator
+ * can take care of the multiplication and to simplify each extrude function. */
+ static fn::CustomMF_SI_SI_SO<float3, float, float3> multiply_fn{
+ "Scale", [](const float3 &offset, const float scale) { return offset * scale; }};
+ std::shared_ptr<FieldOperation> multiply_op = std::make_shared<FieldOperation>(
+ FieldOperation(multiply_fn, {std::move(offset_field), std::move(scale_field)}));
+ const Field<float3> final_offset{std::move(multiply_op)};
+
+ AttributeOutputs attribute_outputs;
+ if (params.output_is_required("Top")) {
+ attribute_outputs.top_id = StrongAnonymousAttributeID("Top");
+ }
+ if (params.output_is_required("Side")) {
+ attribute_outputs.side_id = StrongAnonymousAttributeID("Side");
+ }
+
+ const bool extrude_individual = mode == GEO_NODE_EXTRUDE_MESH_FACES &&
+ params.extract_input<bool>("Individual");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_mesh()) {
+ MeshComponent &component = geometry_set.get_component_for_write<MeshComponent>();
+ switch (mode) {
+ case GEO_NODE_EXTRUDE_MESH_VERTICES:
+ extrude_mesh_vertices(component, selection, final_offset, attribute_outputs);
+ break;
+ case GEO_NODE_EXTRUDE_MESH_EDGES:
+ extrude_mesh_edges(component, selection, final_offset, attribute_outputs);
+ break;
+ case GEO_NODE_EXTRUDE_MESH_FACES: {
+ if (extrude_individual) {
+ extrude_individual_mesh_faces(component, selection, final_offset, attribute_outputs);
+ }
+ else {
+ extrude_mesh_face_regions(component, selection, final_offset, attribute_outputs);
+ }
+ break;
+ }
+ }
+
+ BLI_assert(BKE_mesh_is_valid(component.get_for_write()));
+ }
+ });
+
+ params.set_output("Mesh", std::move(geometry_set));
+ if (attribute_outputs.top_id) {
+ params.set_output("Top",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_outputs.top_id), params.attribute_producer_name()));
+ }
+ if (attribute_outputs.side_id) {
+ params.set_output("Side",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_outputs.side_id), params.attribute_producer_name()));
+ }
+}
+
+} // namespace blender::nodes::node_geo_extrude_mesh_cc
+
+void register_node_type_geo_extrude_mesh()
+{
+ namespace file_ns = blender::nodes::node_geo_extrude_mesh_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_EXTRUDE_MESH, "Extrude Mesh", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_update(&ntype, file_ns::node_update);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ node_type_storage(
+ &ntype, "NodeGeometryExtrudeMesh", node_free_standard_storage, node_copy_standard_storage);
+ ntype.draw_buttons = file_ns::node_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
new file mode 100644
index 00000000000..9512323834c
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
@@ -0,0 +1,193 @@
+/*
+ * 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"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BKE_attribute_math.hh"
+
+#include "BLI_task.hh"
+
+namespace blender::nodes::node_geo_field_at_index_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Index")).min(0).supports_field();
+
+ b.add_input<decl::Float>(N_("Value"), "Value_Float").supports_field();
+ b.add_input<decl::Int>(N_("Value"), "Value_Int").supports_field();
+ b.add_input<decl::Vector>(N_("Value"), "Value_Vector").supports_field();
+ b.add_input<decl::Color>(N_("Value"), "Value_Color").supports_field();
+ b.add_input<decl::Bool>(N_("Value"), "Value_Bool").supports_field();
+
+ b.add_output<decl::Float>(N_("Value"), "Value_Float").field_source();
+ b.add_output<decl::Int>(N_("Value"), "Value_Int").field_source();
+ b.add_output<decl::Vector>(N_("Value"), "Value_Vector").field_source();
+ b.add_output<decl::Color>(N_("Value"), "Value_Color").field_source();
+ b.add_output<decl::Bool>(N_("Value"), "Value_Bool").field_source();
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ node->custom1 = ATTR_DOMAIN_POINT;
+ node->custom2 = CD_PROP_FLOAT;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const CustomDataType data_type = static_cast<CustomDataType>(node->custom2);
+
+ bNodeSocket *sock_index = static_cast<bNodeSocket *>(node->inputs.first);
+ bNodeSocket *sock_in_float = sock_index->next;
+ bNodeSocket *sock_in_int = sock_in_float->next;
+ bNodeSocket *sock_in_vector = sock_in_int->next;
+ bNodeSocket *sock_in_color = sock_in_vector->next;
+ bNodeSocket *sock_in_bool = sock_in_color->next;
+
+ bNodeSocket *sock_out_float = static_cast<bNodeSocket *>(node->outputs.first);
+ bNodeSocket *sock_out_int = sock_out_float->next;
+ bNodeSocket *sock_out_vector = sock_out_int->next;
+ bNodeSocket *sock_out_color = sock_out_vector->next;
+ bNodeSocket *sock_out_bool = sock_out_color->next;
+
+ nodeSetSocketAvailability(ntree, sock_in_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_in_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, sock_in_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_in_color, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, sock_in_bool, data_type == CD_PROP_BOOL);
+
+ nodeSetSocketAvailability(ntree, sock_out_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_int, data_type == CD_PROP_INT32);
+ nodeSetSocketAvailability(ntree, sock_out_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_color, data_type == CD_PROP_COLOR);
+ nodeSetSocketAvailability(ntree, sock_out_bool, data_type == CD_PROP_BOOL);
+}
+
+class FieldAtIndex final : public GeometryFieldInput {
+ private:
+ Field<int> index_field_;
+ GField value_field_;
+ AttributeDomain value_field_domain_;
+
+ public:
+ FieldAtIndex(Field<int> index_field, GField value_field, AttributeDomain value_field_domain)
+ : GeometryFieldInput(value_field.cpp_type(), "Field at Index"),
+ index_field_(std::move(index_field)),
+ value_field_(std::move(value_field)),
+ value_field_domain_(value_field_domain)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
+ {
+ const GeometryComponentFieldContext value_field_context{component, value_field_domain_};
+ FieldEvaluator value_evaluator{value_field_context,
+ component.attribute_domain_size(value_field_domain_)};
+ value_evaluator.add(value_field_);
+ value_evaluator.evaluate();
+ const GVArray &values = value_evaluator.get_evaluated(0);
+
+ const GeometryComponentFieldContext index_field_context{component, domain};
+ FieldEvaluator index_evaluator{index_field_context, &mask};
+ index_evaluator.add(index_field_);
+ index_evaluator.evaluate();
+ const VArray<int> &indices = index_evaluator.get_evaluated<int>(0);
+
+ GVArray output_array;
+ attribute_math::convert_to_static_type(*type_, [&](auto dummy) {
+ using T = decltype(dummy);
+ Array<T> dst_array(mask.min_array_size());
+ VArray<T> src_values = values.typed<T>();
+ threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : mask.slice(range)) {
+ const int index = indices[i];
+ if (index >= 0 && index < src_values.size()) {
+ dst_array[i] = src_values[index];
+ }
+ else {
+ dst_array[i] = {};
+ }
+ }
+ });
+ output_array = VArray<T>::ForContainer(std::move(dst_array));
+ });
+
+ return output_array;
+ }
+};
+
+static StringRefNull identifier_suffix(CustomDataType data_type)
+{
+ switch (data_type) {
+ case CD_PROP_BOOL:
+ return "Bool";
+ case CD_PROP_FLOAT:
+ return "Float";
+ case CD_PROP_INT32:
+ return "Int";
+ case CD_PROP_COLOR:
+ return "Color";
+ case CD_PROP_FLOAT3:
+ return "Vector";
+ default:
+ BLI_assert_unreachable();
+ return "";
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const bNode &node = params.node();
+ const AttributeDomain domain = static_cast<AttributeDomain>(node.custom1);
+ const CustomDataType data_type = static_cast<CustomDataType>(node.custom2);
+
+ Field<int> index_field = params.extract_input<Field<int>>("Index");
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ static const std::string identifier = "Value_" + identifier_suffix(data_type);
+ Field<T> value_field = params.extract_input<Field<T>>(identifier);
+ Field<T> output_field{
+ std::make_shared<FieldAtIndex>(std::move(index_field), std::move(value_field), domain)};
+ params.set_output(identifier, std::move(output_field));
+ });
+}
+
+} // namespace blender::nodes::node_geo_field_at_index_cc
+
+void register_node_type_geo_field_at_index()
+{
+ namespace file_ns = blender::nodes::node_geo_field_at_index_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_FIELD_AT_INDEX, "Field at Index", NODE_CLASS_CONVERTER);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.initfunc = file_ns::node_init;
+ ntype.updatefunc = file_ns::node_update;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
new file mode 100644
index 00000000000..41970d75dfe
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
@@ -0,0 +1,114 @@
+/*
+ * 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_mesh.h"
+#include "BKE_mesh_runtime.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_math.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_flip_faces_cc {
+
+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_("Mesh"));
+}
+
+static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selection_field)
+{
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ if (domain_size == 0) {
+ return;
+ }
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+
+ Mesh *mesh = component.get_for_write();
+
+ mesh->mloop = (MLoop *)CustomData_duplicate_referenced_layer(
+ &mesh->ldata, CD_MLOOP, mesh->totloop);
+ Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
+
+ for (const int i : selection.index_range()) {
+ const MPoly &poly = polys[selection[i]];
+ int start = poly.loopstart;
+ for (const int j : IndexRange(poly.totloop / 2)) {
+ const int index1 = start + j + 1;
+ const int index2 = start + poly.totloop - j - 1;
+ std::swap(loops[index1].v, loops[index2].v);
+ std::swap(loops[index1 - 1].e, loops[index2].e);
+ }
+ }
+
+ component.attribute_foreach(
+ [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ if (meta_data.domain == ATTR_DOMAIN_CORNER) {
+ OutputAttribute attribute = component.attribute_try_get_for_output(
+ attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type, nullptr);
+ attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ MutableSpan<T> dst_span = attribute.as_span<T>();
+ for (const int j : selection.index_range()) {
+ const MPoly &poly = polys[selection[j]];
+ dst_span.slice(poly.loopstart + 1, poly.totloop - 1).reverse();
+ }
+ });
+ attribute.save();
+ }
+ return true;
+ });
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+
+ const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (!geometry_set.has_mesh()) {
+ return;
+ }
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ mesh_flip_faces(mesh_component, selection_field);
+ });
+
+ params.set_output("Mesh", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_flip_faces_cc
+
+void register_node_type_geo_flip_faces()
+{
+ namespace file_ns = blender::nodes::node_geo_flip_faces_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_FLIP_FACES, "Flip Faces", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
index 7faf104737f..f65af5b6737 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
@@ -47,7 +47,7 @@ void register_node_type_geo_geometry_to_instance()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_GEOMETRY_TO_INSTANCE, "Geometry to Instance", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_GEOMETRY_TO_INSTANCE, "Geometry to Instance", NODE_CLASS_GEOMETRY);
node_type_size(&ntype, 160, 100, 300);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
index 0003f15854d..624a8b6b0f6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
@@ -21,7 +21,7 @@
#include "BKE_image.h"
-#include "BLI_float4.hh"
+#include "BLI_math_vec_types.hh"
#include "BLI_threads.h"
#include "BLI_timeit.hh"
@@ -55,8 +55,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryImageTexture *tex = (NodeGeometryImageTexture *)MEM_callocN(
- sizeof(NodeGeometryImageTexture), __func__);
+ NodeGeometryImageTexture *tex = MEM_cnew<NodeGeometryImageTexture>(__func__);
node->storage = tex;
}
@@ -416,7 +415,7 @@ void register_node_type_geo_image_texture()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE, 0);
+ geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE);
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_layout;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
index dae8fda2099..b1144b58c37 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
@@ -14,20 +14,100 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BKE_spline.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_input_curve_handles_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
+ b.add_input<decl::Bool>(N_("Relative"))
+ .default_value(false)
+ .supports_field()
+ .description(N_("Output the handle positions relative to the corresponding control point "
+ "instead of in the local space of the geometry"));
b.add_output<decl::Vector>(N_("Left")).field_source();
b.add_output<decl::Vector>(N_("Right")).field_source();
}
+class HandlePositionFieldInput final : public GeometryFieldInput {
+ Field<bool> relative_;
+ bool left_;
+
+ public:
+ HandlePositionFieldInput(Field<bool> relative, bool left)
+ : GeometryFieldInput(CPPType::get<float3>(), "Handle"), relative_(relative), left_(left)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask mask) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
+ return {};
+ }
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator evaluator(field_context, &mask);
+ evaluator.add(relative_);
+ evaluator.evaluate();
+ const VArray<bool> &relative = evaluator.get_evaluated<bool>(0);
+
+ VArray<float3> positions = component.attribute_get_for_read<float3>(
+ "position", ATTR_DOMAIN_POINT, {0, 0, 0});
+
+ StringRef side = left_ ? "handle_left" : "handle_right";
+ VArray<float3> handles = component.attribute_get_for_read<float3>(
+ side, ATTR_DOMAIN_POINT, {0, 0, 0});
+
+ if (relative.is_single()) {
+ if (relative.get_internal_single()) {
+ Array<float3> output(positions.size());
+ for (const int i : positions.index_range()) {
+ output[i] = handles[i] - positions[i];
+ }
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
+ }
+ return component.attribute_try_adapt_domain<float3>(handles, ATTR_DOMAIN_POINT, domain);
+ }
+
+ Array<float3> output(positions.size());
+ for (const int i : positions.index_range()) {
+ if (relative[i]) {
+ output[i] = handles[i] - positions[i];
+ }
+ else {
+ output[i] = handles[i];
+ }
+ }
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash_2(relative_, left_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const HandlePositionFieldInput *other_handle =
+ dynamic_cast<const HandlePositionFieldInput *>(&other)) {
+ return relative_ == other_handle->relative_ && left_ == other_handle->left_;
+ }
+ return false;
+ }
+};
+
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");
+ Field<bool> relative = params.extract_input<Field<bool>>("Relative");
+ Field<float3> left_field{std::make_shared<HandlePositionFieldInput>(relative, true)};
+ Field<float3> right_field{std::make_shared<HandlePositionFieldInput>(relative, false)};
+
params.set_output("Left", std::move(left_field));
params.set_output("Right", std::move(right_field));
}
@@ -40,7 +120,7 @@ void register_node_type_geo_input_curve_handles()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
index 5ba85b6f34e..61b4b6bb9e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_curve_tilt()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
index d2e103a093a..afe7546f7e5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
@@ -20,7 +20,9 @@ namespace blender::nodes::node_geo_input_id_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Int>(N_("ID")).field_source();
+ b.add_output<decl::Int>(N_("ID")).field_source().description(
+ N_("The values from the \"id\" attribute on points, or the index if that attribute does not "
+ "exist"));
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -37,7 +39,7 @@ void register_node_type_geo_input_id()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
index 74cddfc6a4a..98c2c9d58f0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_index()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
index 1b6e3c8fc68..a1c905fccaa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
@@ -45,7 +45,7 @@ void register_node_type_geo_input_material()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT);
ntype.draw_buttons = file_ns::node_layout;
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
index 4df218eb669..fca29feb73c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_material_index()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
new file mode 100644
index 00000000000..4b6ed7b77b7
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
@@ -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.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_edge_angle_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Unsigned Angle"))
+ .field_source()
+ .description(
+ "The shortest angle in radians between two faces where they meet at an edge. Flat edges "
+ "and Non-manifold edges have an angle of zero. Computing this value is faster than the "
+ "signed angle");
+ b.add_output<decl::Float>(N_("Signed Angle"))
+ .field_source()
+ .description(
+ "The signed angle in radians between two faces where they meet at an edge. Flat edges "
+ "and Non-manifold edges have an angle of zero. Concave angles are positive and convex "
+ "angles are negative. Computing this value is slower than the unsigned angle");
+}
+
+struct EdgeMapEntry {
+ int face_count;
+ int face_index_1;
+ int face_index_2;
+};
+
+static Array<EdgeMapEntry> create_edge_map(const Span<MPoly> polys,
+ const Span<MLoop> loops,
+ const int total_edges)
+{
+ Array<EdgeMapEntry> edge_map(total_edges, {0, 0, 0});
+
+ for (const int i_poly : polys.index_range()) {
+ const MPoly &mpoly = polys[i_poly];
+ for (const MLoop &loop : loops.slice(mpoly.loopstart, mpoly.totloop)) {
+ EdgeMapEntry &entry = edge_map[loop.e];
+ if (entry.face_count == 0) {
+ entry.face_index_1 = i_poly;
+ }
+ else if (entry.face_count == 1) {
+ entry.face_index_2 = i_poly;
+ }
+ entry.face_count++;
+ }
+ }
+ return edge_map;
+}
+
+class AngleFieldInput final : public GeometryFieldInput {
+ public:
+ AngleFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Unsigned Angle Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ Span<MLoop> loops{mesh->mloop, mesh->totloop};
+ Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh->totedge);
+
+ auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float {
+ if (edge_map[i].face_count != 2) {
+ return 0.0f;
+ }
+ const MPoly &mpoly_1 = polys[edge_map[i].face_index_1];
+ const MPoly &mpoly_2 = polys[edge_map[i].face_index_2];
+ float3 normal_1, normal_2;
+ BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, normal_1);
+ BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, normal_2);
+ return angle_normalized_v3v3(normal_1, normal_2);
+ };
+
+ VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
+ return component.attribute_try_adapt_domain<float>(
+ std::move(angles), ATTR_DOMAIN_EDGE, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 32426725235;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const AngleFieldInput *>(&other) != nullptr;
+ }
+};
+
+class SignedAngleFieldInput final : public GeometryFieldInput {
+ public:
+ SignedAngleFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Signed Angle Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ Span<MLoop> loops{mesh->mloop, mesh->totloop};
+ Array<EdgeMapEntry> edge_map = create_edge_map(polys, loops, mesh->totedge);
+
+ auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float {
+ if (edge_map[i].face_count != 2) {
+ return 0.0f;
+ }
+ const MPoly &mpoly_1 = polys[edge_map[i].face_index_1];
+ const MPoly &mpoly_2 = polys[edge_map[i].face_index_2];
+
+ /* Find the normals of the 2 polys. */
+ float3 poly_1_normal, poly_2_normal;
+ BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, poly_1_normal);
+ BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, poly_2_normal);
+
+ /* Find the centerpoint of the axis edge */
+ const float3 edge_centerpoint = (float3(mesh->mvert[mesh->medge[i].v1].co) +
+ float3(mesh->mvert[mesh->medge[i].v2].co)) *
+ 0.5f;
+
+ /* Get the centerpoint of poly 2 and subtract the edge centerpoint to get a tangent
+ * normal for poly 2. */
+ float3 poly_center_2;
+ BKE_mesh_calc_poly_center(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, poly_center_2);
+ const float3 poly_2_tangent = math::normalize(poly_center_2 - edge_centerpoint);
+ const float concavity = math::dot(poly_1_normal, poly_2_tangent);
+
+ /* Get the unsigned angle between the two polys */
+ const float angle = angle_normalized_v3v3(poly_1_normal, poly_2_normal);
+
+ if (angle == 0.0f || angle == 2.0f * M_PI || concavity < 0) {
+ return angle;
+ }
+ return -angle;
+ };
+
+ VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
+ return component.attribute_try_adapt_domain<float>(
+ std::move(angles), ATTR_DOMAIN_EDGE, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 68465416863;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const SignedAngleFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ if (params.output_is_required("Unsigned Angle")) {
+ Field<float> angle_field{std::make_shared<AngleFieldInput>()};
+ params.set_output("Unsigned Angle", std::move(angle_field));
+ }
+ if (params.output_is_required("Signed Angle")) {
+ Field<float> angle_field{std::make_shared<SignedAngleFieldInput>()};
+ params.set_output("Signed Angle", std::move(angle_field));
+ }
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_edge_angle_cc
+
+void register_node_type_geo_input_mesh_edge_angle()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_edge_angle_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_EDGE_ANGLE, "Edge Angle", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
index ede87252312..43c867e0977 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
@@ -27,7 +27,7 @@ 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"));
+ .description(N_("The number of faces that use each edge as one of their sides"));
}
class EdgeNeighborCountFieldInput final : public GeometryFieldInput {
@@ -86,7 +86,7 @@ void register_node_type_geo_input_mesh_edge_neighbors()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, "Edge Neighbors", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, "Edge Neighbors", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
index 473bef63e92..f54c92fea7b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
@@ -50,12 +50,11 @@ static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &componen
return {};
}
if (domain == ATTR_DOMAIN_EDGE) {
-
if (vertex == VERTEX_ONE) {
- return VArray<int>::ForFunc(mesh->totpoly,
+ return VArray<int>::ForFunc(mesh->totedge,
[mesh](const int i) -> int { return mesh->medge[i].v1; });
}
- return VArray<int>::ForFunc(mesh->totpoly,
+ return VArray<int>::ForFunc(mesh->totedge,
[mesh](const int i) -> int { return mesh->medge[i].v2; });
}
return {};
@@ -180,8 +179,7 @@ void register_node_type_geo_input_mesh_edge_vertices()
namespace file_ns = blender::nodes::node_geo_input_mesh_edge_vertices_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_INPUT_MESH_EDGE_VERTICES, "Edge Vertices", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_EDGE_VERTICES, "Edge Vertices", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
index 538b9e9682d..ef8adff48f1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
@@ -89,7 +89,7 @@ void register_node_type_geo_input_mesh_face_area()
namespace file_ns = blender::nodes::node_geo_input_mesh_face_area_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_FACE_AREA, "Face Area", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_FACE_AREA, "Face Area", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
index 80bb25dc7ca..8d196e5f8dd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
@@ -150,7 +150,7 @@ void register_node_type_geo_input_mesh_face_neighbors()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, "Face Neighbors", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, "Face Neighbors", NODE_CLASS_INPUT);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
index 3c713ef6ca9..f1777c9ebf5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
@@ -27,10 +27,13 @@ namespace blender::nodes::node_geo_input_mesh_island_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_output<decl::Int>(N_("Index"))
+ b.add_output<decl::Int>(N_("Island Index"))
.field_source()
- .description(N_("Island indices are based on the order of the lowest-numbered vertex "
- "contained in each island"));
+ .description(N_("The index of the each vertex's island. Indices are based on the "
+ "lowest vertex index contained in each island"));
+ b.add_output<decl::Int>(N_("Island Count"))
+ .field_source()
+ .description(N_("The total number of mesh islands"));
}
class IslandFieldInput final : public GeometryFieldInput {
@@ -81,10 +84,63 @@ class IslandFieldInput final : public GeometryFieldInput {
}
};
+class IslandCountFieldInput final : public GeometryFieldInput {
+ public:
+ IslandCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island 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_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);
+ }
+
+ Set<int> island_list;
+ for (const int i_vert : IndexRange(mesh->totvert)) {
+ const int64_t root = islands.find_root(i_vert);
+ island_list.add(root);
+ }
+
+ return VArray<int>::ForSingle(island_list.size(),
+ mesh_component.attribute_domain_size(domain));
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random hash. */
+ return 45634572457;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const IslandCountFieldInput *>(&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));
+ if (params.output_is_required("Island Index")) {
+ Field<int> field{std::make_shared<IslandFieldInput>()};
+ params.set_output("Island Index", std::move(field));
+ }
+ if (params.output_is_required("Island Count")) {
+ Field<int> field{std::make_shared<IslandCountFieldInput>()};
+ params.set_output("Island Count", std::move(field));
+ }
}
} // namespace blender::nodes::node_geo_input_mesh_island_cc
@@ -94,7 +150,7 @@ void register_node_type_geo_input_mesh_island()
namespace file_ns = blender::nodes::node_geo_input_mesh_island_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_ISLAND, "Mesh Island", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_ISLAND, "Mesh Island", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
index 05140c92205..c2da065cbfc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
@@ -27,7 +27,8 @@ 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"));
+ .description(N_("The number of vertices connected to this vertex with an edge, "
+ "equal to the number of connected edges"));
b.add_output<decl::Int>(N_("Face Count"))
.field_source()
.description(N_("Number of faces that contain the vertex"));
@@ -148,7 +149,7 @@ void register_node_type_geo_input_mesh_vertex_neighbors()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, "Vertex Neighbors", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, "Vertex Neighbors", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
index 1cc508d9d9d..120ae0e9bd1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -31,246 +31,9 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Normal")).field_source();
}
-static VArray<float3> mesh_face_normals(const Mesh &mesh,
- const Span<MVert> verts,
- const Span<MPoly> polys,
- const Span<MLoop> loops,
- const IndexMask mask)
-{
- /* Use existing normals to avoid unnecessarily recalculating them, if possible. */
- if (!(mesh.runtime.cd_dirty_poly & CD_MASK_NORMAL) &&
- CustomData_has_layer(&mesh.pdata, CD_NORMAL)) {
- const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL);
-
- return VArray<float3>::ForSpan({(const float3 *)data, polys.size()});
- }
-
- auto normal_fn = [verts, polys, loops](const int i) -> float3 {
- float3 normal;
- const MPoly &poly = polys[i];
- BKE_mesh_calc_poly_normal(&poly, &loops[poly.loopstart], verts.data(), normal);
- return normal;
- };
-
- return VArray<float3>::ForFunc(mask.min_array_size(), normal_fn);
-}
-
-static VArray<float3> mesh_vertex_normals(const Mesh &mesh,
- const Span<MVert> verts,
- const Span<MPoly> polys,
- const Span<MLoop> loops,
- const IndexMask mask)
-{
- /* Use existing normals to avoid unnecessarily recalculating them, if possible. */
- if (!(mesh.runtime.cd_dirty_vert & CD_MASK_NORMAL) &&
- CustomData_has_layer(&mesh.vdata, CD_NORMAL)) {
- const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL);
-
- return VArray<float3>::ForSpan({(const float3 *)data, mesh.totvert});
- }
-
- /* If the normals are dirty, they must be recalculated for the output of this node's field
- * source. Ideally vertex normals could be calculated lazily on a const mesh, but that's not
- * possible at the moment, so we take ownership of the results. Sadly we must also create a copy
- * of MVert to use the mesh normals API. This can be improved by adding mutex-protected lazy
- * calculation of normals on meshes.
- *
- * Use mask.min_array_size() to avoid calculating a final chunk of data if possible. */
- Array<MVert> temp_verts(verts);
- Array<float3> normals(verts.size()); /* Use full size for accumulation from faces. */
- BKE_mesh_calc_normals_poly_and_vertex(temp_verts.data(),
- mask.min_array_size(),
- loops.data(),
- loops.size(),
- polys.data(),
- polys.size(),
- nullptr,
- (float(*)[3])normals.data());
-
- return VArray<float3>::ForContainer(std::move(normals));
-}
-
-static VArray<float3> construct_mesh_normals_gvarray(const MeshComponent &mesh_component,
- const Mesh &mesh,
- const IndexMask mask,
- const AttributeDomain domain)
-{
- Span<MVert> verts{mesh.mvert, mesh.totvert};
- Span<MEdge> edges{mesh.medge, mesh.totedge};
- Span<MPoly> polys{mesh.mpoly, mesh.totpoly};
- Span<MLoop> loops{mesh.mloop, mesh.totloop};
-
- switch (domain) {
- case ATTR_DOMAIN_FACE: {
- return mesh_face_normals(mesh, verts, polys, loops, mask);
- }
- case ATTR_DOMAIN_POINT: {
- return mesh_vertex_normals(mesh, verts, polys, loops, mask);
- }
- case ATTR_DOMAIN_EDGE: {
- /* In this case, start with vertex normals and convert to the edge domain, since the
- * conversion from edges to vertices is very simple. Use the full mask since the edges
- * might use the vertex normal from any index. */
- GVArray vert_normals = mesh_vertex_normals(
- mesh, verts, polys, loops, IndexRange(verts.size()));
- Span<float3> vert_normals_span = vert_normals.get_internal_span().typed<float3>();
- Array<float3> edge_normals(mask.min_array_size());
-
- /* Use "manual" domain interpolation instead of the GeometryComponent API to avoid
- * calculating unnecessary values and to allow normalizing the result much more simply. */
- for (const int i : mask) {
- const MEdge &edge = edges[i];
- edge_normals[i] = float3::interpolate(
- vert_normals_span[edge.v1], vert_normals_span[edge.v2], 0.5f)
- .normalized();
- }
-
- return VArray<float3>::ForContainer(std::move(edge_normals));
- }
- case ATTR_DOMAIN_CORNER: {
- /* The normals on corners are just the mesh's face normals, so start with the face normal
- * array and copy the face normal for each of its corners. */
- VArray<float3> face_normals = mesh_face_normals(
- mesh, verts, polys, loops, IndexRange(polys.size()));
-
- /* In this case using the mesh component's generic domain interpolation is fine, the data
- * will still be normalized, since the face normal is just copied to every corner. */
- return mesh_component.attribute_try_adapt_domain<float3>(
- std::move(face_normals), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
- }
- default:
- return {};
- }
-}
-
-static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals)
-{
- Span<int> offsets = spline.control_point_offsets();
- Span<float3> evaluated_normals = spline.evaluated_normals();
- for (const int i : IndexRange(spline.size())) {
- normals[i] = evaluated_normals[offsets[i]];
- }
-}
-
-static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals)
-{
- normals.copy_from(spline.evaluated_normals());
-}
-
-/**
- * Because NURBS control points are not necessarily on the path, the normal at the control points
- * is not well defined, so create a temporary poly spline to find the normals. This requires extra
- * copying currently, but may be more efficient in the future if attributes have some form of CoW.
- */
-static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals)
-{
- PolySpline poly_spline;
- poly_spline.resize(spline.size());
- poly_spline.positions().copy_from(spline.positions());
- normals.copy_from(poly_spline.evaluated_normals());
-}
-
-static Array<float3> curve_normal_point_domain(const CurveEval &curve)
-{
- Span<SplinePtr> splines = curve.splines();
- Array<int> offsets = curve.control_point_offsets();
- const int total_size = offsets.last();
- Array<float3> normals(total_size);
-
- threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- const Spline &spline = *splines[i];
- MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())};
- switch (splines[i]->type()) {
- case Spline::Type::Bezier:
- calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals);
- break;
- case Spline::Type::Poly:
- calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals);
- break;
- case Spline::Type::NURBS:
- calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals);
- break;
- }
- }
- });
- return normals;
-}
-
-static VArray<float3> construct_curve_normal_gvarray(const CurveComponent &component,
- const AttributeDomain domain)
-{
- const CurveEval *curve = component.get_for_read();
- if (curve == nullptr) {
- return nullptr;
- }
-
- if (domain == ATTR_DOMAIN_POINT) {
- const Span<SplinePtr> splines = curve->splines();
-
- /* Use a reference to evaluated normals if possible to avoid an allocation and a copy.
- * This is only possible when there is only one poly spline. */
- if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) {
- const PolySpline &spline = static_cast<PolySpline &>(*splines.first());
- return VArray<float3>::ForSpan(spline.evaluated_normals());
- }
-
- Array<float3> normals = curve_normal_point_domain(*curve);
- return VArray<float3>::ForContainer(std::move(normals));
- }
-
- if (domain == ATTR_DOMAIN_CURVE) {
- Array<float3> point_normals = curve_normal_point_domain(*curve);
- VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals));
- return component.attribute_try_adapt_domain<float3>(
- std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
- }
-
- return nullptr;
-}
-
-class NormalFieldInput final : public GeometryFieldInput {
- public:
- NormalFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Normal node")
- {
- category_ = Category::Generated;
- }
-
- GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
- IndexMask 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 {};
- }
-
- 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 {};
- }
-
- uint64_t hash() const override
- {
- /* Some random constant hash. */
- return 669605641;
- }
-
- bool is_equal_to(const fn::FieldNode &other) const override
- {
- return dynamic_cast<const NormalFieldInput *>(&other) != nullptr;
- }
-};
-
static void node_geo_exec(GeoNodeExecParams params)
{
- Field<float3> normal_field{std::make_shared<NormalFieldInput>()};
+ Field<float3> normal_field{std::make_shared<bke::NormalFieldInput>()};
params.set_output("Normal", std::move(normal_field));
}
@@ -282,7 +45,7 @@ void register_node_type_geo_input_normal()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
index 8322831a871..beb528d2fd8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_position()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
index 26fb74f5a5b..c7777da08c6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_radius()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
index cfc1a81f7b9..4ed65e99a1c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
@@ -43,7 +43,7 @@ void register_node_type_geo_input_scene_time()
{
static bNodeType ntype;
namespace file_ns = blender::nodes::node_geo_input_scene_time_cc;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
index 3efe8577e51..b27ab097223 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_shade_smooth()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
index 5f833445a76..2db00a1ae68 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
@@ -37,8 +37,7 @@ void register_node_type_geo_input_spline_cyclic()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
index 810d6e2fddd..b8c8ce840eb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -156,7 +156,7 @@ void register_node_type_geo_input_spline_length()
namespace file_ns = blender::nodes::node_geo_input_spline_length_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
index 77b6e27e6a2..d79f2ffd64d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
@@ -38,7 +38,7 @@ void register_node_type_geo_input_spline_resolution()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
index 86f882df3cd..f80fdfbf334 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -161,7 +161,7 @@ void register_node_type_geo_input_tangent()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
index 486f90760f5..06f24113308 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
@@ -36,7 +36,8 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("Geometry that is instanced on the points"));
b.add_input<decl::Bool>(N_("Pick Instance"))
.supports_field()
- .description("Place different instances on different points");
+ .description(N_("Choose instances from the \"Instance\" input at each point instead of "
+ "instancing the entire geometry"));
b.add_input<decl::Int>(N_("Instance Index"))
.implicit_field()
.description(N_(
@@ -259,7 +260,7 @@ void register_node_type_geo_instance_on_points()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
index 9942e388ba5..f9beed956bb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
@@ -130,7 +130,7 @@ void register_node_type_geo_instances_to_points()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
index 5925d440317..c97bbad4665 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
@@ -42,7 +42,7 @@ void register_node_type_geo_is_viewport()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index bf7a9f49829..1e521af6b13 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -180,8 +180,7 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet
InstancesComponent &instances =
instances_geometry_set.get_component_for_write<InstancesComponent>();
- if constexpr (std::is_same_v<Component, InstancesComponent> ||
- std::is_same_v<Component, VolumeComponent>) {
+ if constexpr (is_same_any_v<Component, InstancesComponent, VolumeComponent>) {
join_components(components, result);
}
else {
@@ -221,7 +220,7 @@ void register_node_type_geo_join_geometry()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
index 5a334126350..0309121db74 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
@@ -63,8 +63,7 @@ void register_node_type_geo_material_replace()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
index 2aad68e7c25..0b5f0bf34c5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -122,7 +122,7 @@ void register_node_type_geo_material_selection()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
new file mode 100644
index 00000000000..deb149fd0f0
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
@@ -0,0 +1,108 @@
+/*
+ * 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_mesh_merge_by_distance.hh"
+#include "GEO_point_merge_by_distance.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_merge_by_distance_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Geometry"))
+ .supported_type({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_MESH});
+ b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
+ b.add_input<decl::Float>(N_("Distance")).default_value(0.1f).min(0.0f).subtype(PROP_DISTANCE);
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_points,
+ const float merge_distance,
+ const Field<bool> &selection_field)
+{
+ const int src_size = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
+ GeometryComponentFieldContext context{src_points, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{context, src_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+
+ const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+ if (selection.is_empty()) {
+ return nullptr;
+ }
+
+ return geometry::point_merge_by_distance(src_points, merge_distance, selection);
+}
+
+static std::optional<Mesh *> mesh_merge_by_distance(const MeshComponent &mesh_component,
+ const float merge_distance,
+ const Field<bool> &selection_field)
+{
+ const int src_size = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{context, src_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+
+ const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+ if (selection.is_empty()) {
+ return nullptr;
+ }
+
+ const Mesh &mesh = *mesh_component.get_for_read();
+ return geometry::mesh_merge_by_distance_all(mesh, selection, merge_distance);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ const Field<bool> selection = params.extract_input<Field<bool>>("Selection");
+ const float merge_distance = params.extract_input<float>("Distance");
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_pointcloud()) {
+ PointCloud *result = pointcloud_merge_by_distance(
+ *geometry_set.get_component_for_read<PointCloudComponent>(), merge_distance, selection);
+ geometry_set.replace_pointcloud(result);
+ }
+ if (geometry_set.has_mesh()) {
+ std::optional<Mesh *> result = mesh_merge_by_distance(
+ *geometry_set.get_component_for_read<MeshComponent>(), merge_distance, selection);
+ if (result) {
+ geometry_set.replace_mesh(*result);
+ }
+ }
+ });
+
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_merge_by_distance_cc
+
+void register_node_type_geo_merge_by_distance()
+{
+ namespace file_ns = blender::nodes::node_geo_merge_by_distance_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MERGE_BY_DISTANCE, "Merge by Distance", NODE_CLASS_GEOMETRY);
+
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index 7a1cb8a62a3..b3b11b2e0e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN(
- sizeof(NodeGeometryMeshCircle), __func__);
+ NodeGeometryMeshCircle *node_storage = MEM_cnew<NodeGeometryMeshCircle>(__func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NONE;
@@ -139,12 +138,6 @@ static Mesh *create_circle_mesh(const float radius,
copy_v3_v3(verts.last().co, float3(0));
}
- /* Point all vertex normals in the up direction. */
- const short up_normal[3] = {0, 0, SHRT_MAX};
- for (MVert &vert : verts) {
- copy_v3_v3_short(vert.no, up_normal);
- }
-
/* Create outer edges. */
const short edge_flag = (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE) ?
ME_LOOSEEDGE :
@@ -214,8 +207,6 @@ static void node_geo_exec(GeoNodeExecParams params)
Mesh *mesh = create_circle_mesh(radius, verts_num, fill);
- BLI_assert(BKE_mesh_is_valid(mesh));
-
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
@@ -227,8 +218,7 @@ void register_node_type_geo_mesh_primitive_circle()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index 70b093798f8..e0923344421 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
@@ -676,8 +676,6 @@ static Mesh *create_vertex_mesh()
/* Returns a mesh with a single vertex at the origin. */
Mesh *mesh = BKE_mesh_new_nomain(1, 0, 0, 0, 0);
copy_v3_fl3(mesh->mvert[0].co, 0.0f, 0.0f, 0.0f);
- const short up[3] = {0, 0, SHRT_MAX};
- copy_v3_v3_short(mesh->mvert[0].no, up);
return mesh;
}
@@ -720,8 +718,6 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
calculate_cone_uvs(mesh, config);
calculate_selection_outputs(mesh, config, attribute_outputs);
- BKE_mesh_normals_tag_dirty(mesh);
-
return mesh;
}
@@ -770,8 +766,7 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN(
- sizeof(NodeGeometryMeshCone), __func__);
+ NodeGeometryMeshCone *node_storage = MEM_cnew<NodeGeometryMeshCone>(__func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
@@ -879,7 +874,7 @@ void register_node_type_geo_mesh_primitive_cone()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
index 2542542c919..5b67258a947 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
@@ -155,7 +155,7 @@ static void calculate_polys(const CuboidConfig &config,
/* Calculate polys for Bottom faces. */
int vert_1_start = 0;
- for (const int UNUSED(y) : IndexRange(config.edges_y)) {
+ for ([[maybe_unused]] const int y : IndexRange(config.edges_y)) {
for (const int x : IndexRange(config.edges_x)) {
const int vert_1 = vert_1_start + x;
const int vert_2 = vert_1_start + config.verts_x + x;
@@ -173,7 +173,7 @@ static void calculate_polys(const CuboidConfig &config,
vert_1_start = 0;
int vert_2_start = config.verts_x * config.verts_y;
- for (const int UNUSED(z) : IndexRange(config.edges_z)) {
+ for ([[maybe_unused]] const int z : IndexRange(config.edges_z)) {
for (const int x : IndexRange(config.edges_x)) {
define_quad(polys,
loops,
@@ -196,7 +196,7 @@ static void calculate_polys(const CuboidConfig &config,
(config.verts_x - 2) * (config.verts_y - 2));
vert_2_start = vert_1_start + config.verts_x;
- for (const int UNUSED(y) : IndexRange(config.edges_y)) {
+ for ([[maybe_unused]] const int y : IndexRange(config.edges_y)) {
for (const int x : IndexRange(config.edges_x)) {
define_quad(polys,
loops,
@@ -527,7 +527,7 @@ void register_node_type_geo_mesh_primitive_cube()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
index b8d2ed3be92..73f21cf31fa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
@@ -71,8 +71,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN(
- sizeof(NodeGeometryMeshCylinder), __func__);
+ NodeGeometryMeshCylinder *node_storage = MEM_cnew<NodeGeometryMeshCylinder>(__func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
@@ -168,7 +167,7 @@ void register_node_type_geo_mesh_primitive_cylinder()
namespace file_ns = blender::nodes::node_geo_mesh_primitive_cylinder_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 77634a03af6..ecb3c785212 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_task.hh"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -38,11 +40,13 @@ static void calculate_uvs(
const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x;
const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y;
- for (const int i : loops.index_range()) {
- const float3 &co = verts[loops[i].v].co;
- uvs[i].x = (co.x + size_x * 0.5f) * dx;
- uvs[i].y = (co.y + size_y * 0.5f) * dy;
- }
+ threading::parallel_for(loops.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ const float3 &co = verts[loops[i].v].co;
+ uvs[i].x = (co.x + size_x * 0.5f) * dx;
+ uvs[i].y = (co.y + size_y * 0.5f) * dy;
+ }
+ });
uv_attribute.save();
}
@@ -70,72 +74,87 @@ Mesh *create_grid_mesh(const int verts_x,
const float dy = edges_y == 0 ? 0.0f : size_y / edges_y;
const float x_shift = edges_x / 2.0f;
const float y_shift = edges_y / 2.0f;
- for (const int x_index : IndexRange(verts_x)) {
- for (const int y_index : IndexRange(verts_y)) {
- const int vert_index = x_index * verts_y + y_index;
- verts[vert_index].co[0] = (x_index - x_shift) * dx;
- verts[vert_index].co[1] = (y_index - y_shift) * dy;
- verts[vert_index].co[2] = 0.0f;
+ threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_offset = x * verts_y;
+ threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int vert_index = y_offset + y;
+ verts[vert_index].co[0] = (x - x_shift) * dx;
+ verts[vert_index].co[1] = (y - y_shift) * dy;
+ verts[vert_index].co[2] = 0.0f;
+ }
+ });
}
- }
+ });
}
- /* Point all vertex normals in the up direction. */
- const short up_normal[3] = {0, 0, SHRT_MAX};
- for (MVert &vert : verts) {
- copy_v3_v3_short(vert.no, up_normal);
- }
-
- /* Build the horizontal edges in the X direction. */
const int y_edges_start = 0;
+ const int x_edges_start = verts_x * edges_y;
const short edge_flag = (edges_x == 0 || edges_y == 0) ? ME_LOOSEEDGE :
ME_EDGEDRAW | ME_EDGERENDER;
- int edge_index = 0;
- for (const int x : IndexRange(verts_x)) {
- for (const int y : IndexRange(edges_y)) {
- const int vert_index = x * verts_y + y;
- MEdge &edge = edges[edge_index++];
- edge.v1 = vert_index;
- edge.v2 = vert_index + 1;
- edge.flag = edge_flag;
+
+ /* Build the horizontal edges in the X direction. */
+ threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_vert_offset = x * verts_y;
+ const int y_edge_offset = y_edges_start + x * edges_y;
+ threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int vert_index = y_vert_offset + y;
+ MEdge &edge = edges[y_edge_offset + y];
+ edge.v1 = vert_index;
+ edge.v2 = vert_index + 1;
+ edge.flag = edge_flag;
+ }
+ });
}
- }
+ });
/* Build the vertical edges in the Y direction. */
- const int x_edges_start = edge_index;
- for (const int y : IndexRange(verts_y)) {
- for (const int x : IndexRange(edges_x)) {
- const int vert_index = x * verts_y + y;
- MEdge &edge = edges[edge_index++];
- edge.v1 = vert_index;
- edge.v2 = vert_index + verts_y;
- edge.flag = edge_flag;
+ threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int x_edge_offset = x_edges_start + y * edges_x;
+ threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int vert_index = x * verts_y + y;
+ MEdge &edge = edges[x_edge_offset + x];
+ edge.v1 = vert_index;
+ edge.v2 = vert_index + verts_y;
+ edge.flag = edge_flag;
+ }
+ });
}
- }
-
- int loop_index = 0;
- int poly_index = 0;
- for (const int x : IndexRange(edges_x)) {
- for (const int y : IndexRange(edges_y)) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = 4;
- const int vert_index = x * verts_y + y;
-
- MLoop &loop_a = loops[loop_index++];
- loop_a.v = vert_index;
- loop_a.e = x_edges_start + edges_x * y + x;
- MLoop &loop_b = loops[loop_index++];
- loop_b.v = vert_index + verts_y;
- loop_b.e = y_edges_start + edges_y * (x + 1) + y;
- MLoop &loop_c = loops[loop_index++];
- loop_c.v = vert_index + verts_y + 1;
- loop_c.e = x_edges_start + edges_x * (y + 1) + x;
- MLoop &loop_d = loops[loop_index++];
- loop_d.v = vert_index + 1;
- loop_d.e = y_edges_start + edges_y * x + y;
+ });
+
+ threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_offset = x * edges_y;
+ threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int poly_index = y_offset + y;
+ const int loop_index = poly_index * 4;
+ MPoly &poly = polys[poly_index];
+ poly.loopstart = loop_index;
+ poly.totloop = 4;
+ const int vert_index = x * verts_y + y;
+
+ MLoop &loop_a = loops[loop_index];
+ loop_a.v = vert_index;
+ loop_a.e = x_edges_start + edges_x * y + x;
+ MLoop &loop_b = loops[loop_index + 1];
+ loop_b.v = vert_index + verts_y;
+ loop_b.e = y_edges_start + edges_y * (x + 1) + y;
+ MLoop &loop_c = loops[loop_index + 2];
+ loop_c.v = vert_index + verts_y + 1;
+ loop_c.e = x_edges_start + edges_x * (y + 1) + x;
+ MLoop &loop_d = loops[loop_index + 3];
+ loop_d.v = vert_index + 1;
+ loop_d.e = y_edges_start + edges_y * x + y;
+ }
+ });
}
- }
+ });
if (mesh->totpoly != 0) {
calculate_uvs(mesh, verts, loops, size_x, size_y);
@@ -185,7 +204,6 @@ static void node_geo_exec(GeoNodeExecParams params)
}
Mesh *mesh = create_grid_mesh(verts_x, verts_y, size_x, size_y);
- BLI_assert(BKE_mesh_is_valid(mesh));
BKE_id_material_eval_ensure_default_slot(&mesh->id);
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
@@ -199,7 +217,7 @@ void register_node_type_geo_mesh_primitive_grid()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
index 5f483a95063..28a505c5bb8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
@@ -87,7 +87,7 @@ void register_node_type_geo_mesh_primitive_ico_sphere()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
index 05830098cc2..691267bccb8 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,6 +23,8 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_mesh_primitive_line_cc {
@@ -65,8 +67,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN(
- sizeof(NodeGeometryMeshLine), __func__);
+ NodeGeometryMeshLine *node_storage = MEM_cnew<NodeGeometryMeshLine>(__func__);
node_storage->mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
node_storage->count_mode = GEO_NODE_MESH_LINE_COUNT_TOTAL;
@@ -100,6 +101,43 @@ static void node_update(bNodeTree *ntree, bNode *node)
count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL);
}
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ if (params.in_out() == SOCK_OUT) {
+ search_link_ops_for_declarations(params, declaration.outputs());
+ return;
+ }
+ 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");
+ });
+ }
+}
+
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryMeshLine &storage = node_storage(params.node());
@@ -117,8 +155,8 @@ static void node_geo_exec(GeoNodeExecParams params)
if (count_mode == GEO_NODE_MESH_LINE_COUNT_RESOLUTION) {
/* Don't allow asymptotic count increase for low resolution values. */
const float resolution = std::max(params.extract_input<float>("Resolution"), 0.0001f);
- const int count = total_delta.length() / resolution + 1;
- const float3 delta = total_delta.normalized() * resolution;
+ const int count = math::length(total_delta) / resolution + 1;
+ const float3 delta = math::normalize(total_delta) * resolution;
mesh = create_line_mesh(start, delta, count);
}
else if (count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL) {
@@ -165,12 +203,8 @@ Mesh *create_line_mesh(const float3 start, const float3 delta, const int count)
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);
@@ -186,7 +220,7 @@ void register_node_type_geo_mesh_primitive_line()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
@@ -194,5 +228,6 @@ void register_node_type_geo_mesh_primitive_line()
&ntype, "NodeGeometryMeshLine", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
+ ntype.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 ce2e0923a30..751cf917f6f 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
@@ -71,7 +71,12 @@ static int sphere_face_total(const int segments, const int rings)
return quads + triangles;
}
+/**
+ * Also calculate vertex normals here, since the calculation is trivial, and it allows avoiding the
+ * calculation later, if it's necessary. The vertex normals are just the normalized positions.
+ */
static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
+ MutableSpan<float3> vert_normals,
const float radius,
const int segments,
const int rings)
@@ -80,7 +85,7 @@ static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
const float delta_phi = (2.0f * M_PI) / segments;
copy_v3_v3(verts[0].co, float3(0.0f, 0.0f, radius));
- normal_float_to_short_v3(verts[0].no, float3(0.0f, 0.0f, 1.0f));
+ vert_normals.first() = float3(0.0f, 0.0f, 1.0f);
int vert_index = 1;
for (const int ring : IndexRange(1, rings - 1)) {
@@ -92,13 +97,13 @@ static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
const float x = sin_theta * std::cos(phi);
const float y = sin_theta * std::sin(phi);
copy_v3_v3(verts[vert_index].co, float3(x, y, z) * radius);
- normal_float_to_short_v3(verts[vert_index].no, float3(x, y, z));
+ vert_normals[vert_index] = float3(x, y, z);
vert_index++;
}
}
copy_v3_v3(verts.last().co, float3(0.0f, 0.0f, -radius));
- normal_float_to_short_v3(verts.last().no, float3(0.0f, 0.0f, -1.0f));
+ vert_normals.last() = float3(0.0f, 0.0f, -1.0f);
}
static void calculate_sphere_edge_indices(MutableSpan<MEdge> edges,
@@ -178,7 +183,7 @@ static void calculate_sphere_faces(MutableSpan<MLoop> loops,
int ring_vert_index_start = 1;
int ring_edge_index_start = segments;
- for (const int UNUSED(ring) : IndexRange(1, rings - 2)) {
+ for ([[maybe_unused]] const int ring : IndexRange(1, rings - 2)) {
const int next_ring_vert_index_start = ring_vert_index_start + segments;
const int next_ring_edge_index_start = ring_edge_index_start + segments * 2;
const int ring_vertical_edge_index_start = ring_edge_index_start + segments;
@@ -279,7 +284,9 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
- calculate_sphere_vertex_data(verts, radius, segments, rings);
+ MutableSpan vert_normals{(float3 *)BKE_mesh_vertex_normals_for_write(mesh), mesh->totvert};
+ calculate_sphere_vertex_data(verts, vert_normals, radius, segments, rings);
+ BKE_mesh_vertex_normals_clear_dirty(mesh);
calculate_sphere_edge_indices(edges, segments, rings);
@@ -287,8 +294,6 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
calculate_sphere_uvs(mesh, segments, rings);
- BLI_assert(BKE_mesh_is_valid(mesh));
-
return mesh;
}
@@ -321,8 +326,7 @@ void register_node_type_geo_mesh_primitive_uv_sphere()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
index 1ec9808044f..6d8a2fac8ad 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
@@ -105,7 +105,7 @@ void register_node_type_geo_mesh_subdivide()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
index 90f0af75788..0f0fb3c230a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -64,7 +64,7 @@ void register_node_type_geo_mesh_to_curve()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
index 77314341fec..d0546cd2583 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN(
- sizeof(NodeGeometryMeshToPoints), __func__);
+ NodeGeometryMeshToPoints *data = MEM_cnew<NodeGeometryMeshToPoints>(__func__);
data->mode = GEO_NODE_MESH_TO_POINTS_VERTICES;
node->storage = data;
}
@@ -179,7 +178,7 @@ void register_node_type_geo_mesh_to_points()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
index 38c3b9cbcd9..d32875d2627 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -102,8 +102,7 @@ static void node_geo_exec(GeoNodeExecParams params)
static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryObjectInfo *data = (NodeGeometryObjectInfo *)MEM_callocN(
- sizeof(NodeGeometryObjectInfo), __func__);
+ NodeGeometryObjectInfo *data = MEM_cnew<NodeGeometryObjectInfo>(__func__);
data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
node->storage = data;
}
@@ -116,7 +115,7 @@ void register_node_type_geo_object_info()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT);
node_type_init(&ntype, file_ns::node_node_init);
node_type_storage(
&ntype, "NodeGeometryObjectInfo", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
index 5510773eabd..f3da591f684 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
@@ -113,7 +113,7 @@ void register_node_type_geo_points_to_vertices()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
index c356e1cf22b..c165bcf8e35 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
@@ -36,8 +36,19 @@ 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)
@@ -55,8 +66,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
- sizeof(NodeGeometryPointsToVolume), __func__);
+ NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__);
data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
node->storage = data;
}
@@ -156,7 +166,7 @@ static float compute_voxel_size(const GeoNodeExecParams &params,
}
/* The voxel size adapts to the final size of the volume. */
- const float diagonal = float3::distance(min, max);
+ const float diagonal = math::distance(min, max);
const float extended_diagonal = diagonal + 2.0f * radius;
const float voxel_size = extended_diagonal / voxel_amount;
return voxel_size;
@@ -259,8 +269,7 @@ void register_node_type_geo_points_to_volume()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY);
node_type_storage(&ntype,
"NodeGeometryPointsToVolume",
node_free_standard_storage,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
index aa3383e68be..3f509942f7c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
@@ -48,8 +48,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void geo_proximity_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryProximity *node_storage = (NodeGeometryProximity *)MEM_callocN(
- sizeof(NodeGeometryProximity), __func__);
+ NodeGeometryProximity *node_storage = MEM_cnew<NodeGeometryProximity>(__func__);
node_storage->target_element = GEO_NODE_PROX_TARGET_FACES;
node->storage = node_storage;
}
@@ -86,7 +85,7 @@ static bool calculate_mesh_proximity(const VArray<float3> &positions,
for (int i : range) {
const int index = mask[i];
/* Use the distance to the last found point as upper bound to speedup the bvh lookup. */
- nearest.dist_sq = float3::distance_squared(nearest.co, positions[index]);
+ nearest.dist_sq = math::distance_squared(float3(nearest.co), positions[index]);
BLI_bvhtree_find_nearest(
bvh_data.tree, positions[index], &nearest, bvh_data.nearest_callback, &bvh_data);
@@ -178,7 +177,7 @@ class ProximityFunction : public fn::MultiFunction {
* comparison per vertex, so it's likely not worth it. */
MutableSpan<float> distances = params.uninitialized_single_output<float>(2, "Distance");
- distances.fill(FLT_MAX);
+ distances.fill_indices(mask, FLT_MAX);
bool success = false;
if (target_.has_mesh()) {
@@ -192,8 +191,12 @@ class ProximityFunction : public fn::MultiFunction {
}
if (!success) {
- positions.fill(float3(0));
- distances.fill(0.0f);
+ if (!positions.is_empty()) {
+ positions.fill_indices(mask, float3(0));
+ }
+ if (!distances.is_empty()) {
+ distances.fill_indices(mask, 0.0f);
+ }
return;
}
@@ -239,7 +242,7 @@ void register_node_type_geo_proximity()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::geo_proximity_init);
node_type_storage(
&ntype, "NodeGeometryProximity", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index c33654b3f20..c38503f688c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -23,6 +23,8 @@
#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 {
@@ -73,8 +75,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
- __func__);
+ NodeGeometryRaycast *data = MEM_cnew<NodeGeometryRaycast>(__func__);
data->mapping = GEO_NODE_RAYCAST_INTERPOLATED;
data->data_type = CD_PROP_FLOAT;
node->storage = data;
@@ -110,6 +111,25 @@ static void node_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) {
@@ -143,7 +163,7 @@ static void raycast_to_mesh(IndexMask mask,
for (const int i : mask) {
const float ray_length = ray_lengths[i];
const float3 ray_origin = ray_origins[i];
- const float3 ray_direction = ray_directions[i].normalized();
+ const float3 ray_direction = math::normalize(ray_directions[i]);
BVHTreeRayHit hit;
hit.index = -1;
@@ -428,7 +448,7 @@ void register_node_type_geo_raycast()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
@@ -437,5 +457,6 @@ void register_node_type_geo_raycast()
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 fad35389823..48b88705ed2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
@@ -54,8 +54,7 @@ void register_node_type_geo_realize_instances()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.draw_buttons_ex = file_ns::node_layout;
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
index 335484c62b0..7d5c5b77ffd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
@@ -28,7 +28,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Vector>(N_("Pivot Point")).subtype(PROP_TRANSLATION).supports_field();
b.add_input<decl::Bool>(N_("Local Space")).default_value(true).supports_field();
b.add_output<decl::Geometry>(N_("Instances"));
-};
+}
static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
{
@@ -112,8 +112,7 @@ void register_node_type_geo_rotate_instances()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
new file mode 100644
index 00000000000..aaa2c156442
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
@@ -0,0 +1,485 @@
+/*
+ * 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_array.hh"
+#include "BLI_disjoint_set.hh"
+#include "BLI_task.hh"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_scale_elements_cc {
+
+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();
+ b.add_input<decl::Float>(N_("Scale"), "Scale").default_value(1.0f).min(0.0f).supports_field();
+ b.add_input<decl::Vector>(N_("Center"))
+ .subtype(PROP_TRANSLATION)
+ .implicit_field()
+ .description(N_("Origin of the scaling for each element. If multiple elements are "
+ "connected, their center is averaged"));
+ b.add_input<decl::Vector>(N_("Axis"))
+ .default_value({1.0f, 0.0f, 0.0f})
+ .supports_field()
+ .description(N_("Direction in which to scale the element"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
+};
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "scale_mode", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ node->custom1 = ATTR_DOMAIN_FACE;
+ node->custom2 = GEO_NODE_SCALE_ELEMENTS_UNIFORM;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *geometry_socket = static_cast<bNodeSocket *>(node->inputs.first);
+ bNodeSocket *selection_socket = geometry_socket->next;
+ bNodeSocket *scale_float_socket = selection_socket->next;
+ bNodeSocket *center_socket = scale_float_socket->next;
+ bNodeSocket *axis_socket = center_socket->next;
+
+ const GeometryNodeScaleElementsMode mode = static_cast<GeometryNodeScaleElementsMode>(
+ node->custom2);
+ const bool use_single_axis = mode == GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS;
+
+ nodeSetSocketAvailability(ntree, axis_socket, use_single_axis);
+}
+
+struct UniformScaleFields {
+ Field<bool> selection;
+ Field<float> scale;
+ Field<float3> center;
+};
+
+struct UniformScaleParams {
+ IndexMask selection;
+ VArray<float> scales;
+ VArray<float3> centers;
+};
+
+struct AxisScaleFields {
+ Field<bool> selection;
+ Field<float> scale;
+ Field<float3> center;
+ Field<float3> axis;
+};
+
+struct AxisScaleParams {
+ IndexMask selection;
+ VArray<float> scales;
+ VArray<float3> centers;
+ VArray<float3> axis_vectors;
+};
+
+/**
+ * When multiple elements share the same vertices, they are scaled together.
+ */
+struct ElementIsland {
+ /* Either face or edge indices. */
+ Vector<int> element_indices;
+};
+
+static float3 transform_with_uniform_scale(const float3 &position,
+ const float3 &center,
+ const float scale)
+{
+ const float3 diff = position - center;
+ const float3 scaled_diff = scale * diff;
+ const float3 new_position = center + scaled_diff;
+ return new_position;
+}
+
+static float4x4 create_single_axis_transform(const float3 &center,
+ const float3 &axis,
+ const float scale)
+{
+ /* Scale along x axis. The other axis need to be orthogonal, but their specific value does not
+ * matter. */
+ const float3 x_axis = math::normalize(axis);
+ float3 y_axis = math::cross(x_axis, float3(0.0f, 0.0f, 1.0f));
+ if (math::is_zero(y_axis)) {
+ y_axis = math::cross(x_axis, float3(0.0f, 1.0f, 0.0f));
+ }
+ y_axis = math::normalize(y_axis);
+ const float3 z_axis = math::cross(x_axis, y_axis);
+
+ float4x4 transform = float4x4::identity();
+
+ /* Move scaling center to the origin. */
+ sub_v3_v3(transform.values[3], center);
+
+ /* `base_change` and `base_change_inv` are used to rotate space so that scaling along the
+ * provided axis is the same as scaling along the x axis. */
+ float4x4 base_change = float4x4::identity();
+ copy_v3_v3(base_change.values[0], x_axis);
+ copy_v3_v3(base_change.values[1], y_axis);
+ copy_v3_v3(base_change.values[2], z_axis);
+
+ /* Can invert by transposing, because the matrix is orthonormal. */
+ float4x4 base_change_inv = base_change.transposed();
+
+ float4x4 scale_transform = float4x4::identity();
+ scale_transform.values[0][0] = scale;
+
+ transform = base_change * scale_transform * base_change_inv * transform;
+
+ /* Move scaling center back to where it was. */
+ add_v3_v3(transform.values[3], center);
+
+ return transform;
+}
+
+using GetVertexIndicesFn =
+ FunctionRef<void(const Mesh &mesh, int element_index, VectorSet<int> &r_vertex_indices)>;
+
+static void scale_vertex_islands_uniformly(Mesh &mesh,
+ const Span<ElementIsland> islands,
+ const UniformScaleParams &params,
+ const GetVertexIndicesFn get_vertex_indices)
+{
+ threading::parallel_for(islands.index_range(), 256, [&](const IndexRange range) {
+ for (const int island_index : range) {
+ const ElementIsland &island = islands[island_index];
+
+ float scale = 0.0f;
+ float3 center = {0.0f, 0.0f, 0.0f};
+
+ VectorSet<int> vertex_indices;
+ for (const int poly_index : island.element_indices) {
+ get_vertex_indices(mesh, poly_index, vertex_indices);
+ center += params.centers[poly_index];
+ scale += params.scales[poly_index];
+ }
+
+ /* Divide by number of elements to get the average. */
+ const float f = 1.0f / island.element_indices.size();
+ scale *= f;
+ center *= f;
+
+ for (const int vert_index : vertex_indices) {
+ MVert &vert = mesh.mvert[vert_index];
+ const float3 old_position = vert.co;
+ const float3 new_position = transform_with_uniform_scale(old_position, center, scale);
+ copy_v3_v3(vert.co, new_position);
+ }
+ }
+ });
+
+ /* Positions have changed, so the normals will have to be recomputed. */
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+static void scale_vertex_islands_on_axis(Mesh &mesh,
+ const Span<ElementIsland> islands,
+ const AxisScaleParams &params,
+ const GetVertexIndicesFn get_vertex_indices)
+{
+ threading::parallel_for(islands.index_range(), 256, [&](const IndexRange range) {
+ for (const int island_index : range) {
+ const ElementIsland &island = islands[island_index];
+
+ float scale = 0.0f;
+ float3 center = {0.0f, 0.0f, 0.0f};
+ float3 axis = {0.0f, 0.0f, 0.0f};
+
+ VectorSet<int> vertex_indices;
+ for (const int poly_index : island.element_indices) {
+ get_vertex_indices(mesh, poly_index, vertex_indices);
+ center += params.centers[poly_index];
+ scale += params.scales[poly_index];
+ axis += params.axis_vectors[poly_index];
+ }
+
+ /* Divide by number of elements to get the average. */
+ const float f = 1.0f / island.element_indices.size();
+ scale *= f;
+ center *= f;
+ axis *= f;
+
+ if (math::is_zero(axis)) {
+ axis = float3(1.0f, 0.0f, 0.0f);
+ }
+
+ const float4x4 transform = create_single_axis_transform(center, axis, scale);
+ for (const int vert_index : vertex_indices) {
+ MVert &vert = mesh.mvert[vert_index];
+ const float3 old_position = vert.co;
+ const float3 new_position = transform * old_position;
+ copy_v3_v3(vert.co, new_position);
+ }
+ }
+ });
+
+ /* Positions have changed, so the normals will have to be recomputed. */
+ BKE_mesh_normals_tag_dirty(&mesh);
+}
+
+static Vector<ElementIsland> prepare_face_islands(const Mesh &mesh, const IndexMask face_selection)
+{
+ /* Use the disjoint set data structure to determine which vertices have to be scaled together. */
+ DisjointSet disjoint_set(mesh.totvert);
+ for (const int poly_index : face_selection) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ const Span<MLoop> poly_loops{mesh.mloop + poly.loopstart, poly.totloop};
+ for (const int loop_index : IndexRange(poly.totloop - 1)) {
+ const int v1 = poly_loops[loop_index].v;
+ const int v2 = poly_loops[loop_index + 1].v;
+ disjoint_set.join(v1, v2);
+ }
+ disjoint_set.join(poly_loops.first().v, poly_loops.last().v);
+ }
+
+ VectorSet<int> island_ids;
+ Vector<ElementIsland> islands;
+ /* There are at most as many islands as there are selected faces. */
+ islands.reserve(face_selection.size());
+
+ /* Gather all of the face indices in each island into separate vectors. */
+ for (const int poly_index : face_selection) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ const Span<MLoop> poly_loops{mesh.mloop + poly.loopstart, poly.totloop};
+ const int island_id = disjoint_set.find_root(poly_loops[0].v);
+ const int island_index = island_ids.index_of_or_add(island_id);
+ if (island_index == islands.size()) {
+ islands.append_as();
+ }
+ ElementIsland &island = islands[island_index];
+ island.element_indices.append(poly_index);
+ }
+
+ return islands;
+}
+
+static void get_face_vertices(const Mesh &mesh, int face_index, VectorSet<int> &r_vertex_indices)
+{
+ const MPoly &poly = mesh.mpoly[face_index];
+ const Span<MLoop> poly_loops{mesh.mloop + poly.loopstart, poly.totloop};
+ for (const MLoop &loop : poly_loops) {
+ r_vertex_indices.add(loop.v);
+ }
+}
+
+static AxisScaleParams evaluate_axis_scale_fields(FieldEvaluator &evaluator,
+ const AxisScaleFields &fields)
+{
+ AxisScaleParams out;
+ evaluator.set_selection(fields.selection);
+ evaluator.add(fields.scale, &out.scales);
+ evaluator.add(fields.center, &out.centers);
+ evaluator.add(fields.axis, &out.axis_vectors);
+ evaluator.evaluate();
+ out.selection = evaluator.get_evaluated_selection_as_mask();
+ return out;
+}
+
+static void scale_faces_on_axis(MeshComponent &mesh_component, const AxisScaleFields &fields)
+{
+ Mesh &mesh = *mesh_component.get_for_write();
+ mesh.mvert = static_cast<MVert *>(
+ CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
+
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
+ FieldEvaluator evaluator{field_context, mesh.totpoly};
+ AxisScaleParams params = evaluate_axis_scale_fields(evaluator, fields);
+
+ Vector<ElementIsland> island = prepare_face_islands(mesh, params.selection);
+ scale_vertex_islands_on_axis(mesh, island, params, get_face_vertices);
+}
+
+static UniformScaleParams evaluate_uniform_scale_fields(FieldEvaluator &evaluator,
+ const UniformScaleFields &fields)
+{
+ UniformScaleParams out;
+ evaluator.set_selection(fields.selection);
+ evaluator.add(fields.scale, &out.scales);
+ evaluator.add(fields.center, &out.centers);
+ evaluator.evaluate();
+ out.selection = evaluator.get_evaluated_selection_as_mask();
+ return out;
+}
+
+static void scale_faces_uniformly(MeshComponent &mesh_component, const UniformScaleFields &fields)
+{
+ Mesh &mesh = *mesh_component.get_for_write();
+ mesh.mvert = static_cast<MVert *>(
+ CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
+
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_FACE};
+ FieldEvaluator evaluator{field_context, mesh.totpoly};
+ UniformScaleParams params = evaluate_uniform_scale_fields(evaluator, fields);
+
+ Vector<ElementIsland> island = prepare_face_islands(mesh, params.selection);
+ scale_vertex_islands_uniformly(mesh, island, params, get_face_vertices);
+}
+
+static Vector<ElementIsland> prepare_edge_islands(const Mesh &mesh, const IndexMask edge_selection)
+{
+ /* Use the disjoint set data structure to determine which vertices have to be scaled together. */
+ DisjointSet disjoint_set(mesh.totvert);
+ for (const int edge_index : edge_selection) {
+ const MEdge &edge = mesh.medge[edge_index];
+ disjoint_set.join(edge.v1, edge.v2);
+ }
+
+ VectorSet<int> island_ids;
+ Vector<ElementIsland> islands;
+ /* There are at most as many islands as there are selected edges. */
+ islands.reserve(edge_selection.size());
+
+ /* Gather all of the edge indices in each island into separate vectors. */
+ for (const int edge_index : edge_selection) {
+ const MEdge &edge = mesh.medge[edge_index];
+ const int island_id = disjoint_set.find_root(edge.v1);
+ const int island_index = island_ids.index_of_or_add(island_id);
+ if (island_index == islands.size()) {
+ islands.append_as();
+ }
+ ElementIsland &island = islands[island_index];
+ island.element_indices.append(edge_index);
+ }
+
+ return islands;
+}
+
+static void get_edge_vertices(const Mesh &mesh, int edge_index, VectorSet<int> &r_vertex_indices)
+{
+ const MEdge &edge = mesh.medge[edge_index];
+ r_vertex_indices.add(edge.v1);
+ r_vertex_indices.add(edge.v2);
+}
+
+static void scale_edges_uniformly(MeshComponent &mesh_component, const UniformScaleFields &fields)
+{
+ Mesh &mesh = *mesh_component.get_for_write();
+ mesh.mvert = static_cast<MVert *>(
+ CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
+
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
+ FieldEvaluator evaluator{field_context, mesh.totedge};
+ UniformScaleParams params = evaluate_uniform_scale_fields(evaluator, fields);
+
+ Vector<ElementIsland> island = prepare_edge_islands(mesh, params.selection);
+ scale_vertex_islands_uniformly(mesh, island, params, get_edge_vertices);
+}
+
+static void scale_edges_on_axis(MeshComponent &mesh_component, const AxisScaleFields &fields)
+{
+ Mesh &mesh = *mesh_component.get_for_write();
+ mesh.mvert = static_cast<MVert *>(
+ CustomData_duplicate_referenced_layer(&mesh.vdata, CD_MVERT, mesh.totvert));
+
+ GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
+ FieldEvaluator evaluator{field_context, mesh.totedge};
+ AxisScaleParams params = evaluate_axis_scale_fields(evaluator, fields);
+
+ Vector<ElementIsland> island = prepare_edge_islands(mesh, params.selection);
+ scale_vertex_islands_on_axis(mesh, island, params, get_edge_vertices);
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const bNode &node = params.node();
+ const AttributeDomain domain = static_cast<AttributeDomain>(node.custom1);
+ const GeometryNodeScaleElementsMode scale_mode = static_cast<GeometryNodeScaleElementsMode>(
+ node.custom2);
+
+ GeometrySet geometry = params.extract_input<GeometrySet>("Geometry");
+
+ Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
+ Field<float> scale_field = params.get_input<Field<float>>("Scale");
+ Field<float3> center_field = params.get_input<Field<float3>>("Center");
+ Field<float3> axis_field;
+ if (scale_mode == GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS) {
+ axis_field = params.get_input<Field<float3>>("Axis");
+ }
+
+ geometry.modify_geometry_sets([&](GeometrySet &geometry) {
+ if (!geometry.has_mesh()) {
+ return;
+ }
+ MeshComponent &mesh_component = geometry.get_component_for_write<MeshComponent>();
+ switch (domain) {
+ case ATTR_DOMAIN_FACE: {
+ switch (scale_mode) {
+ case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
+ scale_faces_uniformly(mesh_component, {selection_field, scale_field, center_field});
+ break;
+ }
+ case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
+ scale_faces_on_axis(mesh_component,
+ {selection_field, scale_field, center_field, axis_field});
+ break;
+ }
+ }
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ switch (scale_mode) {
+ case GEO_NODE_SCALE_ELEMENTS_UNIFORM: {
+ scale_edges_uniformly(mesh_component, {selection_field, scale_field, center_field});
+ break;
+ }
+ case GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS: {
+ scale_edges_on_axis(mesh_component,
+ {selection_field, scale_field, center_field, axis_field});
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ });
+
+ params.set_output("Geometry", std::move(geometry));
+}
+
+} // namespace blender::nodes::node_geo_scale_elements_cc
+
+void register_node_type_geo_scale_elements()
+{
+ namespace file_ns = blender::nodes::node_geo_scale_elements_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SCALE_ELEMENTS, "Scale Elements", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.initfunc = file_ns::node_init;
+ ntype.updatefunc = file_ns::node_update;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
index 1779ac8bff7..5bd2028ff41 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
@@ -31,7 +31,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Vector>(N_("Center")).subtype(PROP_TRANSLATION).supports_field();
b.add_input<decl::Bool>(N_("Local Space")).default_value(true).supports_field();
b.add_output<decl::Geometry>(N_("Instances"));
-};
+}
static void scale_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
{
@@ -91,7 +91,7 @@ void register_node_type_geo_scale_instances()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
index e4adfe6587d..3e34378d3e0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
@@ -70,7 +70,7 @@ void register_node_type_geo_separate_components()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
index 7f1cc1be421..fec1ac1363e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -44,8 +44,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometrySeparateGeometry *data = (NodeGeometrySeparateGeometry *)MEM_callocN(
- sizeof(NodeGeometrySeparateGeometry), __func__);
+ NodeGeometrySeparateGeometry *data = MEM_cnew<NodeGeometrySeparateGeometry>(__func__);
data->domain = ATTR_DOMAIN_POINT;
node->storage = data;
@@ -60,38 +59,38 @@ static void node_geo_exec(GeoNodeExecParams params)
const NodeGeometrySeparateGeometry &storage = node_storage(params.node());
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
- bool all_is_error = false;
- GeometrySet second_set(geometry_set);
- if (params.output_is_required("Selection")) {
- geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- bool this_is_error = false;
+ auto separate_geometry_maybe_recursively = [&](GeometrySet &geometry_set, bool invert) {
+ bool is_error;
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ /* Only delete top level instances. */
separate_geometry(geometry_set,
domain,
GEO_NODE_DELETE_GEOMETRY_MODE_ALL,
selection_field,
- false,
- this_is_error);
- all_is_error &= this_is_error;
- });
+ invert,
+ is_error);
+ }
+ else {
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ separate_geometry(geometry_set,
+ domain,
+ GEO_NODE_DELETE_GEOMETRY_MODE_ALL,
+ selection_field,
+ invert,
+ is_error);
+ });
+ }
+ };
+
+ GeometrySet second_set(geometry_set);
+ if (params.output_is_required("Selection")) {
+ separate_geometry_maybe_recursively(geometry_set, false);
params.set_output("Selection", std::move(geometry_set));
}
if (params.output_is_required("Inverted")) {
- second_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- bool this_is_error = false;
- separate_geometry(geometry_set,
- domain,
- GEO_NODE_DELETE_GEOMETRY_MODE_ALL,
- selection_field,
- true,
- this_is_error);
- all_is_error &= this_is_error;
- });
+ separate_geometry_maybe_recursively(second_set, true);
params.set_output("Inverted", std::move(second_set));
}
- if (all_is_error) {
- /* Only show this if none of the instances/components actually changed. */
- params.error_message_add(NodeWarningType::Info, TIP_("No geometry with given domain"));
- }
}
} // namespace blender::nodes::node_geo_separate_geometry_cc
@@ -102,8 +101,7 @@ void register_node_type_geo_separate_geometry()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_SEPARATE_GEOMETRY, "Separate Geometry", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SEPARATE_GEOMETRY, "Separate Geometry", NODE_CLASS_GEOMETRY);
node_type_storage(&ntype,
"NodeGeometrySeparateGeometry",
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
index 30a61574e19..82d09bbc208 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
@@ -41,8 +41,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometrySetCurveHandlePositions *data = (NodeGeometrySetCurveHandlePositions *)MEM_callocN(
- sizeof(NodeGeometrySetCurveHandlePositions), __func__);
+ NodeGeometrySetCurveHandlePositions *data = MEM_cnew<NodeGeometrySetCurveHandlePositions>(
+ __func__);
data->mode = GEO_NODE_CURVE_HANDLE_LEFT;
node->storage = data;
@@ -65,7 +65,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
evaluator.add(position_field);
evaluator.add(offset_field);
evaluator.evaluate();
- const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
CurveComponent *curve_component = static_cast<CurveComponent *>(&component);
CurveEval *curve = curve_component->get_for_write();
@@ -106,7 +106,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
}
}
else {
- for (int UNUSED(i) : spline->positions().index_range()) {
+ for ([[maybe_unused]] int i : spline->positions().index_range()) {
if (current_mask < selection.size() && selection[current_mask] == current_point) {
current_mask++;
}
@@ -167,7 +167,7 @@ void register_node_type_geo_set_curve_handles()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
ntype.minwidth = 100.0f;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
index 7d99f42c487..06fe4427520 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
@@ -75,8 +75,7 @@ void register_node_type_geo_set_curve_radius()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
index 447310e1ad7..0854d0a4549 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
@@ -71,7 +71,7 @@ void register_node_type_geo_set_curve_tilt()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
index db4083acd4b..110b8206944 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -87,7 +87,7 @@ void register_node_type_geo_set_id()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
index fd65bcc235a..ab2c778d6fc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
@@ -21,6 +21,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_pointcloud_types.h"
#include "DNA_volume_types.h"
#include "BKE_material.h"
@@ -30,7 +31,8 @@ namespace blender::nodes::node_geo_set_material_cc {
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"));
@@ -38,6 +40,12 @@ static void node_declare(NodeDeclarationBuilder &b)
static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Material *material)
{
+ if (selection.size() != mesh.totpoly) {
+ /* If the entire mesh isn't selected, and there is no material slot yet, add an empty
+ * slot so that the faces that aren't selected can still refer to the default material. */
+ BKE_id_material_eval_ensure_default_slot(&mesh.id);
+ }
+
int new_material_index = -1;
for (const int i : IndexRange(mesh.totcol)) {
Material *other_material = mesh.mat[i];
@@ -66,39 +74,47 @@ static void node_geo_exec(GeoNodeExecParams params)
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));
}
@@ -111,7 +127,7 @@ void register_node_type_geo_set_material()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set Material", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set Material", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
index 4451907132a..ca6d78adc80 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
@@ -70,7 +70,7 @@ void register_node_type_geo_set_material_index()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
index 98adff7c939..b7dd091da44 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
@@ -76,8 +76,7 @@ void register_node_type_geo_set_point_radius()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
index 93073c2436d..4a8e4e6eab8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -159,7 +159,7 @@ void register_node_type_geo_set_position()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
index 879a868cc0e..d442cd37e81 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
@@ -70,8 +70,7 @@ void register_node_type_geo_set_shade_smooth()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
index 694491d7e6d..13230e185a3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
@@ -71,8 +71,7 @@ void register_node_type_geo_set_spline_cyclic()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
index 0f93db5e6f6..e472e14671c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
@@ -88,7 +88,7 @@ void register_node_type_geo_set_spline_resolution()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
index 5308b43afb2..176fcf3178a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
@@ -23,7 +23,7 @@ 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 node_geo_exec(GeoNodeExecParams params)
{
@@ -48,7 +48,7 @@ void register_node_type_geo_string_join()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER, 0);
+ geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index 912552c7ce9..c4bd6c6157f 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
@@ -57,9 +57,16 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Text Box Height"))
.default_value(0.0f)
.min(0.0f)
- .subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>(N_("Curves"));
- b.add_output<decl::String>(N_("Remainder"));
+ .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_("Curve Instances"));
+ b.add_output<decl::String>(N_("Remainder")).make_available([](bNode &node) {
+ node_storage(node).overflow = GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE;
+ });
+ b.add_output<decl::Int>(N_("Line")).field_source();
+ b.add_output<decl::Vector>(N_("Pivot Point")).field_source();
}
static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
@@ -79,16 +86,17 @@ static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
uiItemR(layout, ptr, "overflow", 0, "", ICON_NONE);
uiItemR(layout, ptr, "align_x", 0, "", ICON_NONE);
uiItemR(layout, ptr, "align_y", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "pivot_mode", 0, IFACE_("Pivot Point"), ICON_NONE);
}
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryStringToCurves *data = (NodeGeometryStringToCurves *)MEM_callocN(
- sizeof(NodeGeometryStringToCurves), __func__);
+ NodeGeometryStringToCurves *data = MEM_cnew<NodeGeometryStringToCurves>(__func__);
data->overflow = GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW;
data->align_x = GEO_NODE_STRING_TO_CURVES_ALIGN_X_LEFT;
data->align_y = GEO_NODE_STRING_TO_CURVES_ALIGN_Y_TOP_BASELINE;
+ data->pivot_mode = GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_LEFT;
node->storage = data;
node->id = (ID *)BKE_vfont_builtin_get();
}
@@ -111,10 +119,51 @@ static void node_update(bNodeTree *ntree, bNode *node)
N_("Text Box Width"));
}
+static float3 get_pivot_point(GeoNodeExecParams &params, CurveEval &curve)
+{
+ const NodeGeometryStringToCurves &storage = node_storage(params.node());
+ const GeometryNodeStringToCurvesPivotMode pivot_mode = (GeometryNodeStringToCurvesPivotMode)
+ storage.pivot_mode;
+
+ float3 min(FLT_MAX), max(FLT_MIN);
+
+ /* Check if curve is empty. */
+ if (!curve.bounds_min_max(min, max, false)) {
+ return {0.0f, 0.0f, 0.0f};
+ }
+
+ switch (pivot_mode) {
+ case GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_MIDPOINT:
+ return (min + max) / 2;
+ case GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_LEFT:
+ return float3(min.x, min.y, 0.0f);
+ case GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_CENTER:
+ return float3((min.x + max.x) / 2, min.y, 0.0f);
+ case GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_BOTTOM_RIGHT:
+ return float3(max.x, min.y, 0.0f);
+ case GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_LEFT:
+ return float3(min.x, max.y, 0.0f);
+ case GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_CENTER:
+ return float3((min.x + max.x) / 2, max.y, 0.0f);
+ case GEO_NODE_STRING_TO_CURVES_PIVOT_MODE_TOP_RIGHT:
+ return float3(max.x, max.y, 0.0f);
+ }
+ return {0.0f, 0.0f, 0.0f};
+}
+
struct TextLayout {
/* Position of each character. */
Vector<float2> positions;
+ /* Line number of each character. */
+ Array<int> line_numbers;
+
+ /* Map of Pivot point for each character code. */
+ Map<int, float3> pivot_points;
+
+ /* UTF-32 Character codes. */
+ Vector<char32_t> char_codes;
+
/* The text that fit into the text box, with newline character sequences replaced. */
std::string text;
@@ -208,6 +257,20 @@ static TextLayout get_text_layout(GeoNodeExecParams &params)
}
}
+ if (params.output_is_required("Line")) {
+ layout.line_numbers.reinitialize(layout.positions.size());
+ for (const int i : layout.positions.index_range()) {
+ CharTrans &ct = chartransdata[i];
+ layout.line_numbers[i] = ct.linenr;
+ }
+ }
+
+ /* Convert UTF-8 encoded string to UTF-32. */
+ len_chars = BLI_strlen_utf8_ex(layout.text.c_str(), &len_bytes);
+ layout.char_codes.resize(len_chars + 1);
+ BLI_str_utf8_as_utf32(layout.char_codes.data(), layout.text.c_str(), layout.char_codes.size());
+ layout.char_codes.remove_last();
+
MEM_SAFE_FREE(chartransdata);
MEM_SAFE_FREE(cu.str);
MEM_SAFE_FREE(cu.strinfo);
@@ -218,15 +281,15 @@ static TextLayout get_text_layout(GeoNodeExecParams &params)
/* Returns a mapping of UTF-32 character code to instance handle. */
static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
- const float fontsize,
- const Span<char32_t> charcodes,
+ TextLayout &layout,
InstancesComponent &instance_component)
{
VFont *vfont = (VFont *)params.node().id;
Map<int, int> handles;
+ bool pivot_required = params.output_is_required("Pivot Point");
- for (int i : charcodes.index_range()) {
- if (handles.contains(charcodes[i])) {
+ for (int i : layout.char_codes.index_range()) {
+ if (handles.contains(layout.char_codes[i])) {
continue;
}
Curve cu = {{nullptr}};
@@ -236,36 +299,75 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
CharInfo charinfo = {0};
charinfo.mat_nr = 1;
- BKE_vfont_build_char(&cu, &cu.nurb, charcodes[i], &charinfo, 0, 0, 0, i, 1);
+ BKE_vfont_build_char(&cu, &cu.nurb, layout.char_codes[i], &charinfo, 0, 0, 0, i, 1);
std::unique_ptr<CurveEval> curve_eval = curve_eval_from_dna_curve(cu);
BKE_nurbList_free(&cu.nurb);
+
float4x4 size_matrix = float4x4::identity();
- size_matrix.apply_scale(fontsize);
+ size_matrix.apply_scale(layout.final_font_size);
curve_eval->transform(size_matrix);
+ if (pivot_required) {
+ float3 pivot_point = get_pivot_point(params, *curve_eval);
+ layout.pivot_points.add_new(layout.char_codes[i], pivot_point);
+ }
+
GeometrySet geometry_set_curve = GeometrySet::create_with_curve(curve_eval.release());
- handles.add_new(charcodes[i], instance_component.add_reference(std::move(geometry_set_curve)));
+ handles.add_new(layout.char_codes[i],
+ instance_component.add_reference(std::move(geometry_set_curve)));
}
return handles;
}
static void add_instances_from_handles(InstancesComponent &instances,
const Map<int, int> &char_handles,
- const Span<char32_t> charcodes,
- const Span<float2> positions)
+ const TextLayout &layout)
{
- instances.resize(positions.size());
+ instances.resize(layout.positions.size());
MutableSpan<int> handles = instances.instance_reference_handles();
MutableSpan<float4x4> transforms = instances.instance_transforms();
- threading::parallel_for(IndexRange(positions.size()), 256, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(layout.positions.size()), 256, [&](IndexRange range) {
for (const int i : range) {
- handles[i] = char_handles.lookup(charcodes[i]);
- transforms[i] = float4x4::from_location({positions[i].x, positions[i].y, 0});
+ handles[i] = char_handles.lookup(layout.char_codes[i]);
+ transforms[i] = float4x4::from_location({layout.positions[i].x, layout.positions[i].y, 0});
}
});
}
+static void create_attributes(GeoNodeExecParams &params,
+ const TextLayout &layout,
+ InstancesComponent &instances)
+{
+ if (params.output_is_required("Line")) {
+ StrongAnonymousAttributeID line_id = StrongAnonymousAttributeID("Line");
+ OutputAttribute_Typed<int> line_attribute = instances.attribute_try_get_for_output_only<int>(
+ line_id.get(), ATTR_DOMAIN_INSTANCE);
+ MutableSpan<int> lines = line_attribute.as_span();
+ lines.copy_from(layout.line_numbers);
+ line_attribute.save();
+ params.set_output("Line",
+ AnonymousAttributeFieldInput::Create<int>(std::move(line_id),
+ params.attribute_producer_name()));
+ }
+
+ if (params.output_is_required("Pivot Point")) {
+ StrongAnonymousAttributeID pivot_id = StrongAnonymousAttributeID("Pivot");
+ OutputAttribute_Typed<float3> pivot_attribute =
+ instances.attribute_try_get_for_output_only<float3>(pivot_id.get(), ATTR_DOMAIN_INSTANCE);
+ MutableSpan<float3> pivots = pivot_attribute.as_span();
+
+ for (const int i : layout.char_codes.index_range()) {
+ pivots[i] = layout.pivot_points.lookup(layout.char_codes[i]);
+ }
+
+ pivot_attribute.save();
+ params.set_output("Pivot Point",
+ AnonymousAttributeFieldInput::Create<float3>(
+ std::move(pivot_id), params.attribute_producer_name()));
+ }
+}
+
static void node_geo_exec(GeoNodeExecParams params)
{
TextLayout layout = get_text_layout(params);
@@ -277,25 +379,19 @@ static void node_geo_exec(GeoNodeExecParams params)
}
if (layout.positions.size() == 0) {
- params.set_output("Curves", GeometrySet());
+ params.set_output("Curve Instances", GeometrySet());
+ params.set_default_remaining_outputs();
return;
}
- /* Convert UTF-8 encoded string to UTF-32. */
- size_t len_bytes;
- size_t len_chars = BLI_strlen_utf8_ex(layout.text.c_str(), &len_bytes);
- Array<char32_t> char_codes_with_null(len_chars + 1);
- BLI_str_utf8_as_utf32(char_codes_with_null.data(), layout.text.c_str(), len_chars + 1);
- const Span<char32_t> char_codes = char_codes_with_null.as_span().drop_back(1);
-
/* Create and add instances. */
GeometrySet geometry_set_out;
InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
- Map<int, int> char_handles = create_curve_instances(
- params, layout.final_font_size, char_codes, instances);
- add_instances_from_handles(instances, char_handles, char_codes, layout.positions);
+ Map<int, int> char_handles = create_curve_instances(params, layout, instances);
+ add_instances_from_handles(instances, char_handles, layout);
+ create_attributes(params, layout, instances);
- params.set_output("Curves", std::move(geometry_set_out));
+ params.set_output("Curve Instances", std::move(geometry_set_out));
}
} // namespace blender::nodes::node_geo_string_to_curves_cc
@@ -306,8 +402,7 @@ void register_node_type_geo_string_to_curves()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 74e0560b32f..eb1a5496845 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN(
- sizeof(NodeGeometrySubdivisionSurface), __func__);
+ NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__);
data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL;
node->storage = data;
@@ -153,7 +152,7 @@ void register_node_type_geo_subdivision_surface()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index 146407e0c33..a2f05677310 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -24,6 +24,8 @@
#include "BKE_material.h"
+#include "NOD_socket_search_link.hh"
+
#include "FN_multi_function_signature.hh"
namespace blender::nodes::node_geo_switch_cc {
@@ -92,7 +94,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__);
+ NodeSwitch *data = MEM_cnew<NodeSwitch>(__func__);
data->input_type = SOCK_GEOMETRY;
node->storage = data;
}
@@ -122,6 +124,35 @@ static void node_update(bNodeTree *ntree, bNode *node)
}
}
+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");
+ });
+ }
+}
+
template<typename T> class SwitchFieldsFunction : public fn::MultiFunction {
public:
SwitchFieldsFunction()
@@ -296,13 +327,14 @@ void register_node_type_geo_switch()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.geometry_node_execute_supports_laziness = true;
+ 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 cfa6b752993..5a8d9ab470d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -31,6 +31,8 @@
#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 {
@@ -42,7 +44,7 @@ NODE_STORAGE_FUNCS(NodeGeometryTransferAttribute)
static void node_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Geometry>(N_("Target"))
+ b.add_input<decl::Geometry>(N_("Source"))
.supported_type({GEO_COMPONENT_TYPE_MESH,
GEO_COMPONENT_TYPE_POINT_CLOUD,
GEO_COMPONENT_TYPE_CURVE,
@@ -54,8 +56,14 @@ static void node_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});
@@ -80,8 +88,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryTransferAttribute *data = (NodeGeometryTransferAttribute *)MEM_callocN(
- sizeof(NodeGeometryTransferAttribute), __func__);
+ NodeGeometryTransferAttribute *data = MEM_cnew<NodeGeometryTransferAttribute>(__func__);
data->data_type = CD_PROP_FLOAT;
data->mode = GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED;
node->storage = data;
@@ -126,6 +133,24 @@ static void node_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,
@@ -271,7 +296,7 @@ static void get_closest_mesh_corners(const Mesh &mesh,
const MLoop &loop = mesh.mloop[loop_index];
const int vertex_index = loop.v;
const MVert &mvert = mesh.mvert[vertex_index];
- const float distance_sq = float3::distance_squared(position, mvert.co);
+ const float distance_sq = math::distance_squared(position, float3(mvert.co));
if (distance_sq < min_distance_sq) {
min_distance_sq = distance_sq;
closest_loop_index = loop_index;
@@ -724,7 +749,7 @@ static void output_attribute_field(GeoNodeExecParams &params, GField field)
static void node_geo_exec(GeoNodeExecParams params)
{
- GeometrySet geometry = params.extract_input<GeometrySet>("Target");
+ GeometrySet geometry = params.extract_input<GeometrySet>("Source");
const NodeGeometryTransferAttribute &storage = node_storage(params.node());
const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
storage.mode;
@@ -802,7 +827,7 @@ void register_node_type_geo_transfer_attribute()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
@@ -812,5 +837,6 @@ void register_node_type_geo_transfer_attribute()
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 8322de20d20..6187a2eacf9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -37,7 +37,7 @@ namespace blender::nodes {
static bool use_translate(const float3 rotation, const float3 scale)
{
- if (compare_ff(rotation.length_squared(), 0.0f, 1e-9f) != 1) {
+ if (compare_ff(math::length_squared(rotation), 0.0f, 1e-9f) != 1) {
return false;
}
if (compare_ff(scale.x, 1.0f, 1e-9f) != 1 || compare_ff(scale.y, 1.0f, 1e-9f) != 1 ||
@@ -49,7 +49,7 @@ static bool use_translate(const float3 rotation, const float3 scale)
static void translate_mesh(Mesh &mesh, const float3 translation)
{
- if (!translation.is_zero()) {
+ if (!math::is_zero(translation)) {
BKE_mesh_translate(&mesh, translation, false);
}
}
@@ -226,7 +226,7 @@ void register_node_type_geo_transform()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
index 59049ecf0ed..91c503ff047 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
@@ -27,7 +27,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION).supports_field();
b.add_input<decl::Bool>(N_("Local Space")).default_value(true).supports_field();
b.add_output<decl::Geometry>(N_("Instances"));
-};
+}
static void translate_instances(GeoNodeExecParams &params, InstancesComponent &instances_component)
{
@@ -77,7 +77,7 @@ void register_node_type_geo_translate_instances()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index f8deaaa4a14..e78c4d7bc35 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -14,24 +14,25 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "DNA_mesh_types.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_geometry_util.hh"
-extern "C" {
-Mesh *triangulate_mesh(Mesh *mesh,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const int flag);
-}
-
namespace blender::nodes::node_geo_triangulate_cc {
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();
b.add_input<decl::Int>(N_("Minimum Vertices")).default_value(4).min(4).max(10000);
b.add_output<decl::Geometry>(N_("Mesh"));
}
@@ -48,9 +49,35 @@ static void geo_triangulate_init(bNodeTree *UNUSED(ntree), bNode *node)
node->custom2 = GEO_NODE_TRIANGULATE_NGON_BEAUTY;
}
+static Mesh *triangulate_mesh_selection(const Mesh &mesh,
+ const int quad_method,
+ const int ngon_method,
+ const IndexMask selection,
+ const int min_vertices)
+{
+ CustomData_MeshMasks cd_mask_extra = {
+ CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, 0, CD_MASK_ORIGINDEX};
+ BMeshCreateParams create_params{0};
+ BMeshFromMeshParams from_mesh_params{true, 1, 1, 1, cd_mask_extra};
+ BMesh *bm = BKE_mesh_to_bmesh_ex(&mesh, &create_params, &from_mesh_params);
+
+ /* Tag faces to be triangulated from the selection mask. */
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+ for (int i_face : selection) {
+ BM_elem_flag_set(BM_face_at_index(bm, i_face), BM_ELEM_TAG, true);
+ }
+
+ BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, true, NULL, NULL, NULL);
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cd_mask_extra, &mesh);
+ BM_mesh_free(bm);
+ BKE_mesh_normals_tag_dirty(result);
+ return result;
+}
+
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+ Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
const int min_vertices = std::max(params.extract_input<int>("Minimum Vertices"), 4);
GeometryNodeTriangulateQuads quad_method = static_cast<GeometryNodeTriangulateQuads>(
@@ -59,12 +86,22 @@ static void node_geo_exec(GeoNodeExecParams params)
params.node().custom2);
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- /* #triangulate_mesh might modify the input mesh currently. */
- Mesh *mesh_in = geometry_set.get_mesh_for_write();
- if (mesh_in != nullptr) {
- Mesh *mesh_out = triangulate_mesh(mesh_in, quad_method, ngon_method, min_vertices, 0);
- geometry_set.replace_mesh(mesh_out);
+ if (!geometry_set.has_mesh()) {
+ return;
}
+ GeometryComponent &component = geometry_set.get_component_for_write<MeshComponent>();
+ const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
+
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ GeometryComponentFieldContext context{component, ATTR_DOMAIN_FACE};
+ FieldEvaluator evaluator{context, domain_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+
+ Mesh *mesh_out = triangulate_mesh_selection(
+ mesh_in, quad_method, ngon_method, selection, min_vertices);
+ geometry_set.replace_mesh(mesh_out);
});
params.set_output("Mesh", std::move(geometry_set));
@@ -77,7 +114,7 @@ void register_node_type_geo_triangulate()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::geo_triangulate_init);
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index ad9737ac24b..c717d90f7cc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -14,9 +14,16 @@
* 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::node_geo_viewer_cc {
@@ -35,8 +42,7 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(sizeof(NodeGeometryViewer),
- __func__);
+ NodeGeometryViewer *data = MEM_cnew<NodeGeometryViewer>(__func__);
data->data_type = CD_PROP_FLOAT;
node->storage = data;
@@ -80,6 +86,52 @@ static void node_update(bNodeTree *ntree, bNode *node)
}
}
+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()
@@ -88,12 +140,13 @@ void register_node_type_geo_viewer()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT);
node_type_storage(
&ntype, "NodeGeometryViewer", node_free_standard_storage, node_copy_standard_storage);
node_type_update(&ntype, file_ns::node_update);
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 04a1a8e04b8..c7dc73f8a91 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -42,8 +42,19 @@ 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"));
@@ -58,8 +69,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
- sizeof(NodeGeometryVolumeToMesh), __func__);
+ NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
node->storage = data;
}
@@ -204,7 +214,7 @@ void register_node_type_geo_volume_to_mesh()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
node_type_storage(
&ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc
index dc223f07a26..449c6598307 100644
--- a/source/blender/nodes/intern/derived_node_tree.cc
+++ b/source/blender/nodes/intern/derived_node_tree.cc
@@ -270,6 +270,9 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
}
}
else if (linked_node->is_group_output_node()) {
+ if (linked_node.node_ref() != context_->tree().group_output_node()) {
+ continue;
+ }
if (context_->is_root()) {
/* This is a group output in the root node group. */
path_info.sockets.append(linked_socket);
diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc
index c302b1081af..21dec8489b4 100644
--- a/source/blender/nodes/intern/node_common.cc
+++ b/source/blender/nodes/intern/node_common.cc
@@ -38,6 +38,7 @@
#include "BLT_translation.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "RNA_types.h"
@@ -153,8 +154,6 @@ static void update_socket_to_match_interface(bNodeTree &node_tree,
/* Update socket type if necessary */
if (socket_to_update.typeinfo != interface_socket.typeinfo) {
nodeModifySocketType(&node_tree, &node, &socket_to_update, interface_socket.idname);
- /* Flag the tree to make sure link validity is updated after type changes. */
- node_tree.update |= NTREE_UPDATE_LINKS;
}
if (interface_socket.typeinfo->interface_verify_socket) {
@@ -225,7 +224,7 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node)
static void node_frame_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeFrame *data = (NodeFrame *)MEM_callocN(sizeof(NodeFrame), "frame node storage");
+ NodeFrame *data = MEM_cnew<NodeFrame>("frame node storage");
node->storage = data;
data->flag |= NODE_FRAME_SHRINK;
@@ -233,16 +232,17 @@ static void node_frame_init(bNodeTree *UNUSED(ntree), bNode *node)
data->label_size = 20;
}
-void register_node_type_frame(void)
+void register_node_type_frame()
{
/* frame type is used for all tree types, needs dynamic allocation */
- bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "frame node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("frame node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_FRAME, "Frame", NODE_CLASS_LAYOUT, NODE_BACKGROUND);
+ node_type_base(ntype, NODE_FRAME, "Frame", NODE_CLASS_LAYOUT);
node_type_init(ntype, node_frame_init);
node_type_storage(ntype, "NodeFrame", node_free_standard_storage, node_copy_standard_storage);
node_type_size(ntype, 150, 100, 0);
+ ntype->flag |= NODE_BACKGROUND;
nodeRegisterType(ntype);
}
@@ -262,13 +262,13 @@ static void node_reroute_init(bNodeTree *ntree, bNode *node)
nodeAddStaticSocket(ntree, node, SOCK_OUT, SOCK_RGBA, PROP_NONE, "Output", "Output");
}
-void register_node_type_reroute(void)
+void register_node_type_reroute()
{
/* frame type is used for all tree types, needs dynamic allocation */
- bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "frame node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("frame node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT, 0);
+ node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT);
node_type_init(ntype, node_reroute_init);
nodeRegisterType(ntype);
@@ -420,6 +420,11 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree)
/** \name Node #GROUP_INPUT / #GROUP_OUTPUT
* \{ */
+static bool is_group_extension_socket(const bNode *node, const bNodeSocket *socket)
+{
+ return socket->type == SOCK_CUSTOM && ELEM(node->type, NODE_GROUP_OUTPUT, NODE_GROUP_INPUT);
+}
+
static void node_group_input_init(bNodeTree *ntree, bNode *node)
{
node_group_input_update(ntree, node);
@@ -455,7 +460,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
}
if (link->fromsock == extsock) {
- bNodeLink *tlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "temporary link");
+ bNodeLink *tlink = MEM_cnew<bNodeLink>("temporary link");
*tlink = *link;
BLI_addtail(&tmplinks, tlink);
@@ -471,7 +476,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
* This could be improved by choosing the "best" type among all links,
* whatever that means.
*/
- if (link->tosock->type != SOCK_CUSTOM) {
+ if (!is_group_extension_socket(link->tonode, link->tosock)) {
exposelink = link;
break;
}
@@ -503,13 +508,13 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
}
}
-void register_node_type_group_input(void)
+void register_node_type_group_input()
{
/* used for all tree types, needs dynamic allocation */
- bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE, 0);
+ node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE);
node_type_size(ntype, 140, 80, 400);
node_type_init(ntype, node_group_input_init);
node_type_update(ntype, node_group_input_update);
@@ -552,7 +557,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
}
if (link->tosock == extsock) {
- bNodeLink *tlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "temporary link");
+ bNodeLink *tlink = MEM_cnew<bNodeLink>("temporary link");
*tlink = *link;
BLI_addtail(&tmplinks, tlink);
@@ -568,7 +573,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
* This could be improved by choosing the "best" type among all links,
* whatever that means.
*/
- if (link->fromsock->type != SOCK_CUSTOM) {
+ if (!is_group_extension_socket(link->fromnode, link->fromsock)) {
exposelink = link;
break;
}
@@ -601,13 +606,13 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
}
}
-void register_node_type_group_output(void)
+void register_node_type_group_output()
{
/* used for all tree types, needs dynamic allocation */
- bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE, 0);
+ node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE);
node_type_size(ntype, 140, 80, 400);
node_type_init(ntype, node_group_output_init);
node_type_update(ntype, node_group_output_update);
diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc
index 7a19acd2510..28e8bf5a4b7 100644
--- a/source/blender/nodes/intern/node_declaration.cc
+++ b/source/blender/nodes/intern/node_declaration.cc
@@ -51,7 +51,9 @@ 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
@@ -61,6 +63,7 @@ void SocketDeclaration::set_common_flags(bNodeSocket &socket) const
SET_FLAG_FROM_TEST(socket.flag, hide_label_, SOCK_HIDE_LABEL);
SET_FLAG_FROM_TEST(socket.flag, is_multi_input_, SOCK_MULTI_INPUT);
SET_FLAG_FROM_TEST(socket.flag, no_mute_links_, SOCK_NO_INTERNAL_LINK);
+ SET_FLAG_FROM_TEST(socket.flag, is_unavailable_, SOCK_UNAVAIL);
}
bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
@@ -86,6 +89,9 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
if (((socket.flag & SOCK_NO_INTERNAL_LINK) != 0) != no_mute_links_) {
return false;
}
+ if (((socket.flag & SOCK_UNAVAIL) != 0) != is_unavailable_) {
+ return false;
+ }
return true;
}
diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc
index 95070bf735e..788d938ca6f 100644
--- a/source/blender/nodes/intern/node_exec.cc
+++ b/source/blender/nodes/intern/node_exec.cc
@@ -28,13 +28,14 @@
#include "BKE_global.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "MEM_guardedalloc.h"
#include "node_exec.h"
#include "node_util.h"
-int node_exec_socket_use_stack(bNodeSocket *sock)
+static 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);
@@ -170,13 +171,13 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
/* Using global main here is likely totally wrong, not sure what to do about that one though...
* We cannot even check ntree is in global main,
* since most of the time it won't be (thanks to ntree design)!!! */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
/* get a dependency-sorted list of nodes */
ntreeGetDependencyList(ntree, &nodelist, &totnodes);
/* XXX could let callbacks do this for specialized data */
- exec = (bNodeTreeExec *)MEM_callocN(sizeof(bNodeTreeExec), "node tree execution data");
+ exec = MEM_cnew<bNodeTreeExec>("node tree execution data");
/* backpointer to node tree */
exec->nodetree = ntree;
@@ -275,60 +276,3 @@ void ntree_exec_end(bNodeTreeExec *exec)
MEM_freeN(exec);
}
-
-/**** Material/Texture trees ****/
-
-bNodeThreadStack *ntreeGetThreadStack(bNodeTreeExec *exec, int thread)
-{
- ListBase *lb = &exec->threadstack[thread];
- bNodeThreadStack *nts;
-
- for (nts = (bNodeThreadStack *)lb->first; nts; nts = nts->next) {
- if (!nts->used) {
- nts->used = true;
- break;
- }
- }
-
- if (!nts) {
- nts = (bNodeThreadStack *)MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack");
- nts->stack = (bNodeStack *)MEM_dupallocN(exec->stack);
- nts->used = true;
- BLI_addtail(lb, nts);
- }
-
- return nts;
-}
-
-void ntreeReleaseThreadStack(bNodeThreadStack *nts)
-{
- nts->used = false;
-}
-
-bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *callerdata, int thread)
-{
- bNodeStack *nsin[MAX_SOCKET] = {nullptr}; /* arbitrary... watch this */
- bNodeStack *nsout[MAX_SOCKET] = {nullptr}; /* arbitrary... watch this */
- bNodeExec *nodeexec;
- bNode *node;
- int n;
-
- /* nodes are presorted, so exec is in order of list */
-
- for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
- node = nodeexec->node;
- if (node->need_exec) {
- node_get_stack(node, nts->stack, nsin, nsout);
- /* Handle muted nodes...
- * If the mute func is not set, assume the node should never be muted,
- * and hence execute it!
- */
- if (node->typeinfo->exec_fn && !(node->flag & NODE_MUTED)) {
- node->typeinfo->exec_fn(callerdata, thread, node, &nodeexec->data, nsin, nsout);
- }
- }
- }
-
- /* signal to that all went OK, for render */
- return true;
-}
diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h
index b2e1c6564b6..115389afd67 100644
--- a/source/blender/nodes/intern/node_exec.h
+++ b/source/blender/nodes/intern/node_exec.h
@@ -71,9 +71,6 @@ 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,
@@ -86,23 +83,6 @@ struct bNodeTreeExec *ntree_exec_begin(struct bNodeExecContext *context,
bNodeInstanceKey parent_key);
void ntree_exec_end(struct bNodeTreeExec *exec);
-struct bNodeThreadStack *ntreeGetThreadStack(struct bNodeTreeExec *exec, int thread);
-void ntreeReleaseThreadStack(struct bNodeThreadStack *nts);
-bool ntreeExecThreadNodes(struct bNodeTreeExec *exec,
- struct bNodeThreadStack *nts,
- void *callerdata,
- int thread);
-
-struct bNodeTreeExec *ntreeShaderBeginExecTree_internal(struct bNodeExecContext *context,
- struct bNodeTree *ntree,
- bNodeInstanceKey parent_key);
-void ntreeShaderEndExecTree_internal(struct bNodeTreeExec *exec);
-
-struct bNodeTreeExec *ntreeTexBeginExecTree_internal(struct bNodeExecContext *context,
- struct bNodeTree *ntree,
- bNodeInstanceKey parent_key);
-void ntreeTexEndExecTree_internal(struct bNodeTreeExec *exec);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index dbc4f489a88..ed72580ccf1 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -26,8 +26,8 @@
#include "DNA_node_types.h"
#include "BLI_color.hh"
-#include "BLI_float3.hh"
#include "BLI_listbase.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -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());
@@ -237,6 +236,14 @@ static void refresh_socket_list(bNodeTree &ntree,
link->tosock = new_socket;
}
}
+ LISTBASE_FOREACH (bNodeLink *, internal_link, &node.internal_links) {
+ if (internal_link->fromsock == old_socket_with_same_identifier) {
+ internal_link->fromsock = new_socket;
+ }
+ else if (internal_link->tosock == old_socket_with_same_identifier) {
+ internal_link->tosock = new_socket;
+ }
+ }
}
}
}
@@ -258,8 +265,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)
@@ -302,8 +309,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
switch (type) {
case SOCK_FLOAT: {
- bNodeSocketValueFloat *dval = (bNodeSocketValueFloat *)MEM_callocN(
- sizeof(bNodeSocketValueFloat), "node socket value float");
+ bNodeSocketValueFloat *dval = MEM_cnew<bNodeSocketValueFloat>("node socket value float");
dval->subtype = subtype;
dval->value = 0.0f;
dval->min = -FLT_MAX;
@@ -313,8 +319,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
break;
}
case SOCK_INT: {
- bNodeSocketValueInt *dval = (bNodeSocketValueInt *)MEM_callocN(sizeof(bNodeSocketValueInt),
- "node socket value int");
+ bNodeSocketValueInt *dval = MEM_cnew<bNodeSocketValueInt>("node socket value int");
dval->subtype = subtype;
dval->value = 0;
dval->min = INT_MIN;
@@ -324,8 +329,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
break;
}
case SOCK_BOOLEAN: {
- bNodeSocketValueBoolean *dval = (bNodeSocketValueBoolean *)MEM_callocN(
- sizeof(bNodeSocketValueBoolean), "node socket value bool");
+ bNodeSocketValueBoolean *dval = MEM_cnew<bNodeSocketValueBoolean>("node socket value bool");
dval->value = false;
sock->default_value = dval;
@@ -333,8 +337,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
}
case SOCK_VECTOR: {
static float default_value[] = {0.0f, 0.0f, 0.0f};
- bNodeSocketValueVector *dval = (bNodeSocketValueVector *)MEM_callocN(
- sizeof(bNodeSocketValueVector), "node socket value vector");
+ bNodeSocketValueVector *dval = MEM_cnew<bNodeSocketValueVector>("node socket value vector");
dval->subtype = subtype;
copy_v3_v3(dval->value, default_value);
dval->min = -FLT_MAX;
@@ -345,16 +348,14 @@ void node_socket_init_default_value(bNodeSocket *sock)
}
case SOCK_RGBA: {
static float default_value[] = {0.0f, 0.0f, 0.0f, 1.0f};
- bNodeSocketValueRGBA *dval = (bNodeSocketValueRGBA *)MEM_callocN(
- sizeof(bNodeSocketValueRGBA), "node socket value color");
+ bNodeSocketValueRGBA *dval = MEM_cnew<bNodeSocketValueRGBA>("node socket value color");
copy_v4_v4(dval->value, default_value);
sock->default_value = dval;
break;
}
case SOCK_STRING: {
- bNodeSocketValueString *dval = (bNodeSocketValueString *)MEM_callocN(
- sizeof(bNodeSocketValueString), "node socket value string");
+ bNodeSocketValueString *dval = MEM_cnew<bNodeSocketValueString>("node socket value string");
dval->subtype = subtype;
dval->value[0] = '\0';
@@ -362,40 +363,38 @@ void node_socket_init_default_value(bNodeSocket *sock)
break;
}
case SOCK_OBJECT: {
- bNodeSocketValueObject *dval = (bNodeSocketValueObject *)MEM_callocN(
- sizeof(bNodeSocketValueObject), "node socket value object");
+ bNodeSocketValueObject *dval = MEM_cnew<bNodeSocketValueObject>("node socket value object");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_IMAGE: {
- bNodeSocketValueImage *dval = (bNodeSocketValueImage *)MEM_callocN(
- sizeof(bNodeSocketValueImage), "node socket value image");
+ bNodeSocketValueImage *dval = MEM_cnew<bNodeSocketValueImage>("node socket value image");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_COLLECTION: {
- bNodeSocketValueCollection *dval = (bNodeSocketValueCollection *)MEM_callocN(
- sizeof(bNodeSocketValueCollection), "node socket value object");
+ bNodeSocketValueCollection *dval = MEM_cnew<bNodeSocketValueCollection>(
+ "node socket value object");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_TEXTURE: {
- bNodeSocketValueTexture *dval = (bNodeSocketValueTexture *)MEM_callocN(
- sizeof(bNodeSocketValueTexture), "node socket value texture");
+ bNodeSocketValueTexture *dval = MEM_cnew<bNodeSocketValueTexture>(
+ "node socket value texture");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_MATERIAL: {
- bNodeSocketValueMaterial *dval = (bNodeSocketValueMaterial *)MEM_callocN(
- sizeof(bNodeSocketValueMaterial), "node socket value material");
+ bNodeSocketValueMaterial *dval = MEM_cnew<bNodeSocketValueMaterial>(
+ "node socket value material");
dval->value = nullptr;
sock->default_value = dval;
@@ -630,7 +629,7 @@ static bNodeSocketType *make_standard_socket_type(int type, int subtype)
bNodeSocketType *stype;
StructRNA *srna;
- stype = (bNodeSocketType *)MEM_callocN(sizeof(bNodeSocketType), "node socket C type");
+ stype = MEM_cnew<bNodeSocketType>("node socket C type");
stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN;
BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
BLI_strncpy(stype->label, socket_label, sizeof(stype->label));
@@ -674,7 +673,7 @@ static bNodeSocketType *make_socket_type_virtual()
bNodeSocketType *stype;
StructRNA *srna;
- stype = (bNodeSocketType *)MEM_callocN(sizeof(bNodeSocketType), "node socket C type");
+ stype = MEM_cnew<bNodeSocketType>("node socket C type");
stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN;
BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
@@ -873,7 +872,7 @@ static bNodeSocketType *make_socket_type_material()
return socktype;
}
-void register_standard_node_socket_types(void)
+void register_standard_node_socket_types()
{
/* Draw callbacks are set in `drawnode.c` to avoid bad-level calls. */
diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc
index 1795cc339e7..1e6b77a9620 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_;
@@ -380,10 +483,10 @@ GeometryBuilder &GeometryBuilder::only_instances(bool value)
/** \name #Shader
* \{ */
-bNodeSocket &Shader::build(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) const
+bNodeSocket &Shader::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddSocket(
- &ntree, &node, in_out, "NodeSocketShader", identifier_.c_str(), name_.c_str());
+ &ntree, &node, in_out_, "NodeSocketShader", identifier_.c_str(), name_.c_str());
this->set_common_flags(socket);
return socket;
}
@@ -399,6 +502,19 @@ bool Shader::matches(const bNodeSocket &socket) const
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, SOCK_SHADER);
+ }
+ 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 912d5e5322c..bc78533d45c 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -70,6 +70,8 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
break;
}
}
+ BLI_assert(internal_link.from_ != nullptr);
+ BLI_assert(internal_link.to_ != nullptr);
node.internal_links_.append(&internal_link);
}
@@ -115,6 +117,22 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
const bNodeType *nodetype = node->bnode_->typeinfo;
nodes_by_type_.add(nodetype, node);
}
+
+ const Span<const NodeRef *> group_output_nodes = this->nodes_by_type("NodeGroupOutput");
+ if (group_output_nodes.is_empty()) {
+ group_output_node_ = nullptr;
+ }
+ else if (group_output_nodes.size() == 1) {
+ group_output_node_ = group_output_nodes.first();
+ }
+ else {
+ for (const NodeRef *group_output : group_output_nodes) {
+ if (group_output->bnode_->flag & NODE_DO_OUTPUT) {
+ group_output_node_ = group_output;
+ break;
+ }
+ }
+ }
}
NodeTreeRef::~NodeTreeRef()
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 7620c8fa1a8..5c2d84cf605 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -35,6 +35,7 @@
#include "BKE_colortools.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
@@ -340,188 +341,6 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Internal Links (mute and disconnect)
- * \{ */
-
-/**
- * Common datatype priorities, works for compositor, shader and texture nodes alike
- * defines priority of datatype connection based on output type (to):
- * `< 0`: never connect these types.
- * `>= 0`: priority of connection (higher values chosen first).
- */
-static int node_datatype_priority(const bNodeSocketType *from, const bNodeSocketType *to)
-{
- switch (to->type) {
- case SOCK_RGBA:
- switch (from->type) {
- case SOCK_RGBA:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_INT:
- return 2;
- case SOCK_BOOLEAN:
- return 1;
- }
- return -1;
- case SOCK_VECTOR:
- switch (from->type) {
- case SOCK_VECTOR:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_INT:
- return 2;
- case SOCK_BOOLEAN:
- return 1;
- }
- return -1;
- case SOCK_FLOAT:
- switch (from->type) {
- case SOCK_FLOAT:
- return 5;
- case SOCK_INT:
- return 4;
- case SOCK_BOOLEAN:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- }
- return -1;
- case SOCK_INT:
- switch (from->type) {
- case SOCK_INT:
- return 5;
- case SOCK_FLOAT:
- return 4;
- case SOCK_BOOLEAN:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- }
- return -1;
- case SOCK_BOOLEAN:
- switch (from->type) {
- case SOCK_BOOLEAN:
- return 5;
- case SOCK_INT:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- }
- return -1;
- }
-
- /* The rest of the socket types only allow an internal link if both the input and output socket
- * have the same type. If the sockets are custom, we check the idname instead. */
- if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) {
- return 1;
- }
-
- return -1;
-}
-
-/* select a suitable input socket for an output */
-static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output)
-{
- if (node->type == NODE_REROUTE) {
- return node->inputs.first;
- }
-
- bNodeSocket *selected = NULL, *input;
- int i;
- int sel_priority = -1;
- bool sel_is_linked = false;
-
- for (input = node->inputs.first, i = 0; input; input = input->next, i++) {
- int priority = node_datatype_priority(input->typeinfo, output->typeinfo);
- bool is_linked = (input->link != NULL);
- bool preferred;
-
- if (nodeSocketIsHidden(input) || /* ignore hidden sockets */
- input->flag &
- SOCK_NO_INTERNAL_LINK || /* ignore if input is not allowed for internal connections */
- priority < 0 || /* ignore incompatible types */
- priority < sel_priority) /* ignore if we already found a higher priority input */
- {
- continue;
- }
-
- /* determine if this input is preferred over the currently selected */
- preferred = (priority > sel_priority) || /* prefer higher datatype priority */
- (is_linked && !sel_is_linked); /* prefer linked over unlinked */
-
- if (preferred) {
- selected = input;
- sel_is_linked = is_linked;
- sel_priority = priority;
- }
- }
-
- return selected;
-}
-
-void node_internal_links_create(bNodeTree *ntree, bNode *node)
-{
- bNodeLink *link;
- bNodeSocket *output, *input;
-
- /* sanity check */
- if (!ntree) {
- return;
- }
-
- /* use link pointer as a tag for handled sockets (for outputs is unused anyway) */
- for (output = node->outputs.first; output; output = output->next) {
- output->link = NULL;
- }
-
- for (link = ntree->links.first; link; link = link->next) {
- if (nodeLinkIsHidden(link)) {
- continue;
- }
-
- output = link->fromsock;
- if (link->fromnode != node || output->link) {
- continue;
- }
- if (nodeSocketIsHidden(output) || output->flag & SOCK_NO_INTERNAL_LINK) {
- continue;
- }
- output->link = link; /* not really used, just for tagging handled sockets */
-
- /* look for suitable input */
- input = select_internal_link_input(node, output);
-
- if (input) {
- bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link");
- ilink->fromnode = node;
- ilink->fromsock = input;
- ilink->tonode = node;
- ilink->tosock = output;
- /* internal link is always valid */
- ilink->flag |= NODE_LINK_VALID;
- BLI_addtail(&node->internal_links, ilink);
- }
- }
-
- /* clean up */
- for (output = node->outputs.first; output; output = output->next) {
- output->link = NULL;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Default value RNA access
* \{ */
diff --git a/source/blender/nodes/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
index 7d99c233197..c8eb0b8d570 100644
--- a/source/blender/nodes/shader/CMakeLists.txt
+++ b/source/blender/nodes/shader/CMakeLists.txt
@@ -20,12 +20,13 @@
set(INC
.
- ../
+ ..
../intern
../../blenkernel
../../blenlib
../../blentranslation
../../depsgraph
+ ../../editors/include
../../functions
../../gpu
../../imbuf
@@ -39,101 +40,103 @@ set(INC
set(SRC
- nodes/node_shader_add_shader.c
- nodes/node_shader_ambient_occlusion.c
- nodes/node_shader_attribute.c
- nodes/node_shader_background.c
- nodes/node_shader_bevel.c
- nodes/node_shader_blackbody.c
- nodes/node_shader_brightness.c
- nodes/node_shader_bsdf_anisotropic.c
- nodes/node_shader_bsdf_diffuse.c
- nodes/node_shader_bsdf_glass.c
- nodes/node_shader_bsdf_glossy.c
- nodes/node_shader_bsdf_hair.c
- nodes/node_shader_bsdf_hair_principled.c
- nodes/node_shader_bsdf_principled.c
- nodes/node_shader_bsdf_refraction.c
- nodes/node_shader_bsdf_toon.c
- nodes/node_shader_bsdf_translucent.c
- nodes/node_shader_bsdf_transparent.c
- nodes/node_shader_bsdf_velvet.c
- nodes/node_shader_bump.c
- nodes/node_shader_camera.c
+ nodes/node_shader_add_shader.cc
+ nodes/node_shader_ambient_occlusion.cc
+ nodes/node_shader_attribute.cc
+ nodes/node_shader_background.cc
+ nodes/node_shader_bevel.cc
+ nodes/node_shader_blackbody.cc
+ nodes/node_shader_brightness.cc
+ nodes/node_shader_bsdf_anisotropic.cc
+ nodes/node_shader_bsdf_diffuse.cc
+ nodes/node_shader_bsdf_glass.cc
+ nodes/node_shader_bsdf_glossy.cc
+ nodes/node_shader_bsdf_hair.cc
+ nodes/node_shader_bsdf_hair_principled.cc
+ nodes/node_shader_bsdf_principled.cc
+ nodes/node_shader_bsdf_refraction.cc
+ nodes/node_shader_bsdf_toon.cc
+ nodes/node_shader_bsdf_translucent.cc
+ nodes/node_shader_bsdf_transparent.cc
+ nodes/node_shader_bsdf_velvet.cc
+ nodes/node_shader_bump.cc
+ nodes/node_shader_camera.cc
nodes/node_shader_clamp.cc
- nodes/node_shader_common.c
+ nodes/node_shader_color_ramp.cc
+ nodes/node_shader_common.cc
nodes/node_shader_curves.cc
- nodes/node_shader_displacement.c
- nodes/node_shader_eevee_specular.c
- nodes/node_shader_emission.c
- nodes/node_shader_fresnel.c
- nodes/node_shader_gamma.c
- nodes/node_shader_geometry.c
- nodes/node_shader_hair_info.c
- nodes/node_shader_holdout.c
- nodes/node_shader_hueSatVal.c
- nodes/node_shader_ies_light.c
- nodes/node_shader_invert.c
- nodes/node_shader_layer_weight.c
- nodes/node_shader_light_falloff.c
- nodes/node_shader_light_path.c
+ nodes/node_shader_displacement.cc
+ nodes/node_shader_eevee_specular.cc
+ nodes/node_shader_emission.cc
+ nodes/node_shader_fresnel.cc
+ nodes/node_shader_gamma.cc
+ nodes/node_shader_geometry.cc
+ nodes/node_shader_hair_info.cc
+ nodes/node_shader_holdout.cc
+ nodes/node_shader_hueSatVal.cc
+ nodes/node_shader_ies_light.cc
+ nodes/node_shader_invert.cc
+ nodes/node_shader_layer_weight.cc
+ nodes/node_shader_light_falloff.cc
+ nodes/node_shader_light_path.cc
nodes/node_shader_map_range.cc
- nodes/node_shader_mapping.c
+ nodes/node_shader_mapping.cc
nodes/node_shader_math.cc
nodes/node_shader_mix_rgb.cc
- nodes/node_shader_mix_shader.c
- nodes/node_shader_normal.c
- nodes/node_shader_normal_map.c
- nodes/node_shader_object_info.c
- nodes/node_shader_output_aov.c
- nodes/node_shader_output_light.c
- nodes/node_shader_output_linestyle.c
- nodes/node_shader_output_material.c
- nodes/node_shader_output_world.c
- nodes/node_shader_particle_info.c
+ nodes/node_shader_mix_shader.cc
+ nodes/node_shader_normal.cc
+ nodes/node_shader_normal_map.cc
+ nodes/node_shader_object_info.cc
+ nodes/node_shader_output_aov.cc
+ nodes/node_shader_output_light.cc
+ nodes/node_shader_output_linestyle.cc
+ nodes/node_shader_output_material.cc
+ nodes/node_shader_output_world.cc
+ nodes/node_shader_particle_info.cc
+ nodes/node_shader_point_info.cc
+ nodes/node_shader_rgb.cc
nodes/node_shader_rgb_to_bw.cc
- nodes/node_shader_rgb.c
- nodes/node_shader_script.c
- nodes/node_shader_sepcomb_hsv.c
+ nodes/node_shader_script.cc
+ nodes/node_shader_sepcomb_hsv.cc
nodes/node_shader_sepcomb_rgb.cc
nodes/node_shader_sepcomb_xyz.cc
- nodes/node_shader_shader_to_rgb.c
- nodes/node_shader_squeeze.c
- nodes/node_shader_subsurface_scattering.c
- nodes/node_shader_tangent.c
+ nodes/node_shader_shader_to_rgb.cc
+ nodes/node_shader_squeeze.cc
+ nodes/node_shader_subsurface_scattering.cc
+ nodes/node_shader_tangent.cc
nodes/node_shader_tex_brick.cc
nodes/node_shader_tex_checker.cc
- nodes/node_shader_tex_coord.c
- nodes/node_shader_tex_environment.c
+ nodes/node_shader_tex_coord.cc
+ nodes/node_shader_tex_environment.cc
nodes/node_shader_tex_gradient.cc
nodes/node_shader_tex_image.cc
nodes/node_shader_tex_magic.cc
nodes/node_shader_tex_musgrave.cc
nodes/node_shader_tex_noise.cc
- nodes/node_shader_tex_pointdensity.c
- nodes/node_shader_tex_sky.c
+ nodes/node_shader_tex_pointdensity.cc
+ nodes/node_shader_tex_sky.cc
nodes/node_shader_tex_voronoi.cc
nodes/node_shader_tex_wave.cc
nodes/node_shader_tex_white_noise.cc
- nodes/node_shader_uv_along_stroke.c
- nodes/node_shader_uvmap.c
+ nodes/node_shader_uv_along_stroke.cc
+ nodes/node_shader_uvmap.cc
nodes/node_shader_value.cc
- nodes/node_shader_vector_displacement.c
+ nodes/node_shader_vector_displacement.cc
nodes/node_shader_vector_math.cc
nodes/node_shader_vector_rotate.cc
- nodes/node_shader_vector_transform.c
- nodes/node_shader_vertex_color.c
- nodes/node_shader_volume_absorption.c
- nodes/node_shader_volume_info.c
- nodes/node_shader_volume_principled.c
- nodes/node_shader_volume_scatter.c
- nodes/node_shader_wavelength.c
- nodes/node_shader_wireframe.c
+ nodes/node_shader_vector_transform.cc
+ nodes/node_shader_vertex_color.cc
+ nodes/node_shader_volume_absorption.cc
+ nodes/node_shader_volume_info.cc
+ nodes/node_shader_volume_principled.cc
+ nodes/node_shader_volume_scatter.cc
+ nodes/node_shader_wavelength.cc
+ nodes/node_shader_wireframe.cc
- node_shader_tree.c
+ node_shader_tree.cc
node_shader_util.cc
- node_shader_util.h
+ node_shader_util.hh
)
set(LIB
@@ -164,3 +167,8 @@ if(WITH_FREESTYLE)
endif()
blender_add_lib(bf_nodes_shader "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_nodes_shader PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_nodes_shader PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.cc
index 40023ca80d8..5c3c5889c98 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.cc
@@ -21,7 +21,7 @@
* \ingroup nodes
*/
-#include <string.h>
+#include <cstring>
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
@@ -44,6 +44,7 @@
#include "BKE_lib_id.h"
#include "BKE_linestyle.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_scene.h"
#include "RNA_access.h"
@@ -52,16 +53,18 @@
#include "RE_texture.h"
+#include "UI_resources.h"
+
#include "NOD_common.h"
#include "node_common.h"
#include "node_exec.h"
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "node_util.h"
-typedef struct nTreeTags {
+struct nTreeTags {
float ssr_id, sss_id;
-} nTreeTags;
+};
static void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tags);
@@ -91,7 +94,7 @@ static void shader_get_from_context(const bContext *C,
if (ob) {
*r_from = &ob->id;
if (ob->type == OB_LAMP) {
- *r_id = ob->data;
+ *r_id = static_cast<ID *>(ob->data);
*r_ntree = ((Light *)ob->data)->nodetree;
}
else {
@@ -107,7 +110,7 @@ static void shader_get_from_context(const bContext *C,
else if (snode->shaderfrom == SNODE_SHADER_LINESTYLE) {
FreestyleLineStyle *linestyle = BKE_linestyle_active_from_view_layer(view_layer);
if (linestyle) {
- *r_from = NULL;
+ *r_from = nullptr;
*r_id = &linestyle->id;
*r_ntree = linestyle->nodetree;
}
@@ -115,7 +118,7 @@ static void shader_get_from_context(const bContext *C,
#endif
else { /* SNODE_SHADER_WORLD */
if (scene->world) {
- *r_from = NULL;
+ *r_from = nullptr;
*r_id = &scene->world->id;
*r_ntree = scene->world->nodetree;
}
@@ -148,34 +151,19 @@ static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree))
}
}
-static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_sync_tree(ntree, localtree);
-}
-
-static void local_merge(Main *UNUSED(bmain), bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_merge_tree(ntree, localtree, true);
-}
-
static void update(bNodeTree *ntree)
{
ntreeSetOutput(ntree);
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
-static bool shader_validate_link(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;
}
@@ -189,21 +177,18 @@ static bool shader_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
bNodeTreeType *ntreeType_Shader;
-void register_node_tree_type_sh(void)
+void register_node_tree_type_sh()
{
- bNodeTreeType *tt = ntreeType_Shader = MEM_callocN(sizeof(bNodeTreeType),
- "shader node tree type");
+ bNodeTreeType *tt = ntreeType_Shader = MEM_cnew<bNodeTreeType>("shader node tree type");
tt->type = NTREE_SHADER;
strcpy(tt->idname, "ShaderNodeTree");
strcpy(tt->ui_name, N_("Shader Editor"));
- tt->ui_icon = 0; /* Defined in `drawnode.c`. */
+ tt->ui_icon = ICON_NODE_MATERIAL;
strcpy(tt->ui_description, N_("Shader nodes"));
tt->foreach_nodeclass = foreach_nodeclass;
tt->localize = localize;
- tt->local_sync = local_sync;
- tt->local_merge = local_merge;
tt->update = update;
tt->poll = shader_tree_poll;
tt->get_from_context = shader_get_from_context;
@@ -224,7 +209,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
/* Find output node that matches type and target. If there are
* multiple, we prefer exact target match and active nodes. */
- bNode *output_node = NULL;
+ bNode *output_node = nullptr;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (!ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT)) {
@@ -232,7 +217,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
}
if (node->custom1 == SHD_OUTPUT_ALL) {
- if (output_node == NULL) {
+ if (output_node == nullptr) {
output_node = node;
}
else if (output_node->custom1 == SHD_OUTPUT_ALL) {
@@ -242,7 +227,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
}
}
else if (node->custom1 == target) {
- if (output_node == NULL) {
+ if (output_node == nullptr) {
output_node = node;
}
else if (output_node->custom1 == SHD_OUTPUT_ALL) {
@@ -260,12 +245,12 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
/* Find socket with a specified identifier. */
static bNodeSocket *ntree_shader_node_find_socket(ListBase *sockets, const char *identifier)
{
- for (bNodeSocket *sock = sockets->first; sock != NULL; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
if (STREQ(sock->identifier, identifier)) {
return sock;
}
}
- return NULL;
+ return nullptr;
}
/* Find input socket with a specified identifier. */
@@ -294,37 +279,37 @@ static bool ntree_shader_expand_socket_default(bNodeTree *localtree,
switch (socket->type) {
case SOCK_VECTOR:
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_RGB);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGB);
value_socket = ntree_shader_node_find_output(value_node, "Color");
- BLI_assert(value_socket != NULL);
- src_vector = socket->default_value;
- dst_rgba = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_vector = static_cast<bNodeSocketValueVector *>(socket->default_value);
+ dst_rgba = static_cast<bNodeSocketValueRGBA *>(value_socket->default_value);
copy_v3_v3(dst_rgba->value, src_vector->value);
dst_rgba->value[3] = 1.0f; /* should never be read */
break;
case SOCK_RGBA:
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_RGB);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGB);
value_socket = ntree_shader_node_find_output(value_node, "Color");
- BLI_assert(value_socket != NULL);
- src_rgba = socket->default_value;
- dst_rgba = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_rgba = static_cast<bNodeSocketValueRGBA *>(socket->default_value);
+ dst_rgba = static_cast<bNodeSocketValueRGBA *>(value_socket->default_value);
copy_v4_v4(dst_rgba->value, src_rgba->value);
break;
case SOCK_INT:
/* HACK: Support as float. */
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_VALUE);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_VALUE);
value_socket = ntree_shader_node_find_output(value_node, "Value");
- BLI_assert(value_socket != NULL);
- src_int = socket->default_value;
- dst_float = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_int = static_cast<bNodeSocketValueInt *>(socket->default_value);
+ dst_float = static_cast<bNodeSocketValueFloat *>(value_socket->default_value);
dst_float->value = (float)(src_int->value);
break;
case SOCK_FLOAT:
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_VALUE);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_VALUE);
value_socket = ntree_shader_node_find_output(value_node, "Value");
- BLI_assert(value_socket != NULL);
- src_float = socket->default_value;
- dst_float = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_float = static_cast<bNodeSocketValueFloat *>(socket->default_value);
+ dst_float = static_cast<bNodeSocketValueFloat *>(value_socket->default_value);
dst_float->value = src_float->value;
break;
default:
@@ -337,11 +322,10 @@ static bool ntree_shader_expand_socket_default(bNodeTree *localtree,
static void ntree_shader_unlink_hidden_value_sockets(bNode *group_node, bNodeSocket *isock)
{
bNodeTree *group_ntree = (bNodeTree *)group_node->id;
- bNode *node;
bool removed_link = false;
- for (node = group_ntree->nodes.first; node; node = node->next) {
- const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != NULL);
+ LISTBASE_FOREACH (bNode *, node, &group_ntree->nodes) {
+ const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != nullptr);
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (!is_group && (sock->flag & SOCK_HIDE_VALUE) == 0) {
@@ -364,7 +348,7 @@ static void ntree_shader_unlink_hidden_value_sockets(bNode *group_node, bNodeSoc
}
if (removed_link) {
- ntreeUpdateTree(G.main, group_ntree);
+ BKE_ntree_update_main_tree(G.main, group_ntree, nullptr);
}
}
@@ -375,7 +359,7 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
bool link_added = false;
LISTBASE_FOREACH (bNode *, node, &localtree->nodes) {
- const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != NULL);
+ const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != nullptr);
const bool is_group_output = node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT);
if (is_group) {
@@ -385,25 +369,32 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
if (is_group || is_group_output) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (socket->link != NULL && !(socket->link->flag & NODE_LINK_MUTED)) {
+ if (socket->link != nullptr && !(socket->link->flag & NODE_LINK_MUTED)) {
bNodeLink *link = socket->link;
/* Fix the case where the socket is actually converting the data. (see T71374)
* We only do the case of lossy conversion to float. */
if ((socket->type == SOCK_FLOAT) && (link->fromsock->type != link->tosock->type)) {
if (link->fromsock->type == SOCK_RGBA) {
- bNode *tmp = nodeAddStaticNode(NULL, localtree, SH_NODE_RGBTOBW);
- nodeAddLink(localtree, link->fromnode, link->fromsock, tmp, tmp->inputs.first);
- nodeAddLink(localtree, tmp, tmp->outputs.first, node, socket);
+ bNode *tmp = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGBTOBW);
+ nodeAddLink(localtree,
+ link->fromnode,
+ link->fromsock,
+ tmp,
+ static_cast<bNodeSocket *>(tmp->inputs.first));
+ nodeAddLink(
+ localtree, tmp, static_cast<bNodeSocket *>(tmp->outputs.first), node, socket);
}
else if (link->fromsock->type == SOCK_VECTOR) {
- bNode *tmp = nodeAddStaticNode(NULL, localtree, SH_NODE_VECTOR_MATH);
+ bNode *tmp = nodeAddStaticNode(nullptr, localtree, SH_NODE_VECTOR_MATH);
tmp->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
- bNodeSocket *dot_input1 = tmp->inputs.first;
- bNodeSocket *dot_input2 = dot_input1->next;
- bNodeSocketValueVector *input2_socket_value = dot_input2->default_value;
+ bNodeSocket *dot_input1 = static_cast<bNodeSocket *>(tmp->inputs.first);
+ bNodeSocket *dot_input2 = static_cast<bNodeSocket *>(dot_input1->next);
+ bNodeSocketValueVector *input2_socket_value = static_cast<bNodeSocketValueVector *>(
+ dot_input2->default_value);
copy_v3_fl(input2_socket_value->value, 1.0f / 3.0f);
nodeAddLink(localtree, link->fromnode, link->fromsock, tmp, dot_input1);
- nodeAddLink(localtree, tmp, tmp->outputs.last, node, socket);
+ nodeAddLink(
+ localtree, tmp, static_cast<bNodeSocket *>(tmp->outputs.last), node, socket);
}
}
continue;
@@ -423,22 +414,33 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
}
if (link_added) {
- ntreeUpdateTree(G.main, localtree);
+ BKE_ntree_update_main_tree(G.main, localtree, nullptr);
}
}
-static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
+static void ntree_shader_groups_remove_muted_links(bNodeTree *ntree)
{
- bNodeLink *link, *linkn, *tlink;
- bNode *node, *nextnode;
- bNodeTree *ngroup;
- LinkNode *group_interface_nodes = NULL;
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == NODE_GROUP) {
+ if (node->id != nullptr) {
+ ntree_shader_groups_remove_muted_links(reinterpret_cast<bNodeTree *>(node->id));
+ }
+ }
+ }
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
+ if (link->flag & NODE_LINK_MUTED) {
+ nodeRemLink(ntree, link);
+ }
+ }
+}
- ngroup = (bNodeTree *)gnode->id;
+static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
+{
+ LinkNode *group_interface_nodes = nullptr;
+ bNodeTree *ngroup = (bNodeTree *)gnode->id;
/* Add the nodes into the ntree */
- for (node = ngroup->nodes.first; node; node = nextnode) {
- nextnode = node->next;
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup->nodes) {
/* Remove interface nodes.
* This also removes remaining links to and from interface nodes.
* We must delay removal since sockets will reference this node. see: T52092 */
@@ -454,25 +456,26 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
}
/* Save first and last link to iterate over flattened group links. */
- bNodeLink *glinks_first = ntree->links.last;
+ bNodeLink *glinks_first = static_cast<bNodeLink *>(ntree->links.last);
/* Add internal links to the ntree */
- for (link = ngroup->links.first; link; link = linkn) {
- linkn = link->next;
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup->links) {
BLI_remlink(&ngroup->links, link);
BLI_addtail(&ntree->links, link);
}
- bNodeLink *glinks_last = ntree->links.last;
+ bNodeLink *glinks_last = static_cast<bNodeLink *>(ntree->links.last);
/* restore external links to and from the gnode */
- if (glinks_first != NULL) {
+ if (glinks_first != nullptr) {
/* input links */
- for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ for (bNodeLink *link = glinks_first->next; link != glinks_last->next; link = link->next) {
if (link->fromnode->type == NODE_GROUP_INPUT) {
const char *identifier = link->fromsock->identifier;
/* find external links to this input */
- for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ for (bNodeLink *tlink = static_cast<bNodeLink *>(ntree->links.first);
+ tlink != glinks_first->next;
+ tlink = tlink->next) {
if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
}
@@ -480,13 +483,15 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
}
}
/* Also iterate over the new links to cover passthrough links. */
- glinks_last = ntree->links.last;
+ glinks_last = static_cast<bNodeLink *>(ntree->links.last);
/* output links */
- for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ for (bNodeLink *tlink = static_cast<bNodeLink *>(ntree->links.first);
+ tlink != glinks_first->next;
+ tlink = tlink->next) {
if (tlink->fromnode == gnode) {
const char *identifier = tlink->fromsock->identifier;
/* find internal links to this output */
- for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ for (bNodeLink *link = glinks_first->next; link != glinks_last->next; link = link->next) {
/* only use active output node */
if (link->tonode->type == NODE_GROUP_OUTPUT && (link->tonode->flag & NODE_DO_OUTPUT)) {
if (STREQ(link->tosock->identifier, identifier)) {
@@ -499,11 +504,11 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
}
while (group_interface_nodes) {
- node = BLI_linklist_pop(&group_interface_nodes);
+ bNode *node = static_cast<bNode *>(BLI_linklist_pop(&group_interface_nodes));
ntreeFreeLocalNode(ntree, node);
}
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(ntree);
}
/* Flatten group to only have a simple single tree */
@@ -511,8 +516,9 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree)
{
/* This is effectively recursive as the flattened groups will add
* nodes at the end of the list, which will also get evaluated. */
- for (bNode *node = localtree->nodes.first, *node_next; node; node = node_next) {
- if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) {
+ for (bNode *node = static_cast<bNode *>(localtree->nodes.first), *node_next; node;
+ node = node_next) {
+ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != nullptr) {
flatten_group_do(localtree, node);
/* Continue even on new flattened nodes. */
node_next = node->next;
@@ -528,7 +534,7 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree)
}
}
- ntreeUpdateTree(G.main, localtree);
+ BKE_ntree_update_main_tree(G.main, localtree, nullptr);
}
/* Check whether shader has a displacement.
@@ -543,20 +549,20 @@ static bool ntree_shader_has_displacement(bNodeTree *ntree,
bNodeSocket **r_socket,
bNodeLink **r_link)
{
- if (output_node == NULL) {
+ if (output_node == nullptr) {
/* We can't have displacement without output node, apparently. */
return false;
}
/* Make sure sockets links pointers are correct. */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
bNodeSocket *displacement = ntree_shader_node_find_input(output_node, "Displacement");
- if (displacement == NULL) {
+ if (displacement == nullptr) {
/* Non-cycles node is used as an output. */
return false;
}
- if ((displacement->link != NULL) && !(displacement->link->flag & NODE_LINK_MUTED)) {
+ if ((displacement->link != nullptr) && !(displacement->link->flag & NODE_LINK_MUTED)) {
*r_node = displacement->link->fromnode;
*r_socket = displacement->link->fromsock;
*r_link = displacement->link;
@@ -574,7 +580,7 @@ static void ntree_shader_relink_node_normal(bNodeTree *ntree,
* matching?
*/
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- if (STREQ(sock->identifier, "Normal") && sock->link == NULL) {
+ if (STREQ(sock->identifier, "Normal") && sock->link == nullptr) {
/* It's a normal input and nothing is connected to it. */
nodeAddLink(ntree, node_from, socket_from, node, sock);
}
@@ -594,7 +600,7 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
bNode *node_from,
bNodeSocket *socket_from)
{
- for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node == node_from) {
/* Don't connect node itself! */
continue;
@@ -619,7 +625,7 @@ static void ntree_shader_bypass_bump_link(bNodeTree *ntree, bNode *bump_node, bN
fromnode = bump_normal_input->link->fromnode;
}
else {
- fromnode = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
+ fromnode = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY);
fromsock = ntree_shader_node_find_output(fromnode, "Normal");
}
/* Bypass the bump node by creating a link between the previous and next node. */
@@ -637,7 +643,7 @@ static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree)
ntree_shader_bypass_bump_link(ntree, node, link);
}
}
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
}
static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata)
@@ -671,19 +677,19 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
int node_count = 1;
nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, 1);
/* Make a full copy of the branch */
- bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__);
+ bNode **nodes_copy = static_cast<bNode **>(MEM_mallocN(sizeof(bNode *) * node_count, __func__));
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->tmp_flag >= 0) {
int id = node->tmp_flag;
- nodes_copy[id] = BKE_node_copy_ex(
- ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN, false);
+ nodes_copy[id] = blender::bke::node_copy(
+ ntree, *node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN, false);
nodes_copy[id]->tmp_flag = -2; /* Copy */
/* Make sure to clear all sockets links as they are invalid. */
LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->inputs) {
- sock->link = NULL;
+ sock->link = nullptr;
}
LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->outputs) {
- sock->link = NULL;
+ sock->link = nullptr;
}
}
}
@@ -716,13 +722,13 @@ static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
/* Replace displacement socket/node/link. */
bNode *tonode = displacement_link->tonode;
bNodeSocket *tosock = displacement_link->tosock;
- displacement_node = ntree_shader_copy_branch(ntree, displacement_node, NULL, 0);
+ displacement_node = ntree_shader_copy_branch(ntree, displacement_node, nullptr, 0);
displacement_socket = ntree_shader_node_find_output(displacement_node,
displacement_socket->identifier);
nodeRemLink(ntree, displacement_link);
nodeAddLink(ntree, displacement_node, displacement_socket, tonode, tosock);
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
}
/* Re-link displacement output to unconnected normal sockets via bump node.
@@ -756,11 +762,11 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
nodeRemLink(ntree, displacement_link);
/* Convert displacement vector to bump height. */
- bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
- bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
+ bNode *dot_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_VECTOR_MATH);
+ bNode *geo_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY);
bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal");
- bNodeSocket *dot_input1 = dot_node->inputs.first;
- bNodeSocket *dot_input2 = dot_input1->next;
+ bNodeSocket *dot_input1 = static_cast<bNodeSocket *>(dot_node->inputs.first);
+ bNodeSocket *dot_input2 = static_cast<bNodeSocket *>(dot_input1->next);
dot_node->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
nodeAddLink(ntree, displacement_node, displacement_socket, dot_node, dot_input1);
@@ -771,11 +777,11 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
/* We can't connect displacement to normal directly, use bump node for that
* and hope that it gives good enough approximation.
*/
- bNode *bump_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BUMP);
+ bNode *bump_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_BUMP);
bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height");
bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal");
- BLI_assert(bump_input_socket != NULL);
- BLI_assert(bump_output_socket != NULL);
+ BLI_assert(bump_input_socket != nullptr);
+ BLI_assert(bump_output_socket != nullptr);
/* Connect bump node to where displacement output was originally
* connected to.
*/
@@ -786,12 +792,12 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
geo_node->tmp_flag = -2;
bump_node->tmp_flag = -2;
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
/* Connect all free-standing Normal inputs and relink geometry/coordinate nodes. */
ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket);
/* We modified the tree, it needs to be updated now. */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
}
static void node_tag_branch_as_derivative(bNode *node, int dx)
@@ -855,7 +861,7 @@ static bool ntree_tag_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *user
default:
/* We could return false here but since we
* allow the use of Closure as RGBA, we can have
- * Bsdf nodes linked to other Bsdf nodes. */
+ * BSDF nodes linked to other BSDF nodes. */
break;
}
@@ -867,11 +873,11 @@ static bool ntree_tag_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *user
*/
void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tags)
{
- if (output_node == NULL) {
+ if (output_node == nullptr) {
return;
}
/* Make sure sockets links pointers are correct. */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0);
}
@@ -885,11 +891,12 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
+ ntree_shader_groups_remove_muted_links(localtree);
ntree_shader_groups_expand_inputs(localtree);
ntree_shader_groups_flatten(localtree);
- if (output == NULL) {
+ if (output == nullptr) {
/* Search again, now including flattened nodes. */
output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
}
@@ -905,19 +912,17 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
LISTBASE_FOREACH (bNode *, node, &localtree->nodes) {
if (node->type == SH_NODE_OUTPUT_AOV) {
nodeChainIterBackwards(localtree, node, ntree_shader_bump_branches, localtree, 0);
- nTreeTags tags = {
- .ssr_id = 1.0,
- .sss_id = 1.0,
- };
+ nTreeTags tags = {};
+ tags.ssr_id = 1.0;
+ tags.sss_id = 1.0;
ntree_shader_tag_nodes(localtree, node, &tags);
}
}
/* TODO(fclem): consider moving this to the gpu shader tree evaluation. */
- nTreeTags tags = {
- .ssr_id = 1.0,
- .sss_id = 1.0,
- };
+ nTreeTags tags = {};
+ tags.ssr_id = 1.0;
+ tags.sss_id = 1.0;
ntree_shader_tag_nodes(localtree, output, &tags);
exec = ntreeShaderBeginExecTree(localtree);
@@ -933,15 +938,15 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
*has_surface_output = false;
*has_volume_output = false;
- if (output != NULL) {
+ if (output != nullptr) {
bNodeSocket *surface_sock = ntree_shader_node_find_input(output, "Surface");
bNodeSocket *volume_sock = ntree_shader_node_find_input(output, "Volume");
- if (surface_sock != NULL) {
+ if (surface_sock != nullptr) {
*has_surface_output = (nodeCountSocketLinks(localtree, surface_sock) > 0);
}
- if (volume_sock != NULL) {
+ if (volume_sock != nullptr) {
*has_volume_output = (nodeCountSocketLinks(localtree, volume_sock) > 0);
}
}
@@ -951,19 +956,17 @@ bNodeTreeExec *ntreeShaderBeginExecTree_internal(bNodeExecContext *context,
bNodeTree *ntree,
bNodeInstanceKey parent_key)
{
- bNodeTreeExec *exec;
- bNode *node;
-
/* ensures only a single output node is enabled */
ntreeSetOutput(ntree);
/* common base initialization */
- exec = ntree_exec_begin(context, ntree, parent_key);
+ bNodeTreeExec *exec = ntree_exec_begin(context, ntree, parent_key);
/* allocate the thread stack listbase array */
- exec->threadstack = MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array");
+ exec->threadstack = static_cast<ListBase *>(
+ MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array"));
- for (node = exec->nodetree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &exec->nodetree->nodes) {
node->need_exec = 1;
}
@@ -986,8 +989,8 @@ bNodeTreeExec *ntreeShaderBeginExecTree(bNodeTree *ntree)
exec = ntreeShaderBeginExecTree_internal(&context, ntree, NODE_INSTANCE_KEY_BASE);
- /* XXX this should not be necessary, but is still used for cmp/sha/tex nodes,
- * which only store the ntree pointer. Should be fixed at some point!
+ /* XXX: this should not be necessary, but is still used for compositor/shader/texture nodes,
+ * which only store the `ntree` pointer. Should be fixed at some point!
*/
ntree->execdata = exec;
@@ -996,12 +999,9 @@ bNodeTreeExec *ntreeShaderBeginExecTree(bNodeTree *ntree)
void ntreeShaderEndExecTree_internal(bNodeTreeExec *exec)
{
- bNodeThreadStack *nts;
- int a;
-
if (exec->threadstack) {
- for (a = 0; a < BLENDER_MAX_THREADS; a++) {
- for (nts = exec->threadstack[a].first; nts; nts = nts->next) {
+ for (int a = 0; a < BLENDER_MAX_THREADS; a++) {
+ LISTBASE_FOREACH (bNodeThreadStack *, nts, &exec->threadstack[a]) {
if (nts->stack) {
MEM_freeN(nts->stack);
}
@@ -1010,7 +1010,7 @@ void ntreeShaderEndExecTree_internal(bNodeTreeExec *exec)
}
MEM_freeN(exec->threadstack);
- exec->threadstack = NULL;
+ exec->threadstack = nullptr;
}
ntree_exec_end(exec);
@@ -1024,6 +1024,6 @@ void ntreeShaderEndExecTree(bNodeTreeExec *exec)
ntreeShaderEndExecTree_internal(exec);
/* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */
- ntree->execdata = NULL;
+ ntree->execdata = nullptr;
}
}
diff --git a/source/blender/nodes/shader/node_shader_util.cc b/source/blender/nodes/shader/node_shader_util.cc
index 8b7e72fbcc9..bb377e2607a 100644
--- a/source/blender/nodes/shader/node_shader_util.cc
+++ b/source/blender/nodes/shader/node_shader_util.cc
@@ -23,7 +23,9 @@
#include "DNA_node_types.h"
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+#include "NOD_socket_search_link.hh"
#include "node_exec.h"
@@ -47,24 +49,25 @@ static bool sh_fn_poll_default(bNodeType *UNUSED(ntype),
return true;
}
-void sh_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = sh_node_poll_default;
ntype->insert_link = node_insert_link_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
-void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- sh_node_type_base(ntype, type, name, nclass, flag);
+ sh_node_type_base(ntype, type, name, nclass);
ntype->poll = sh_fn_poll_default;
+ ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
/* ****** */
-void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
+static void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
{
const float *from = ns->vec;
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.hh
index c647b86a19a..31229c8693b 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.hh
@@ -23,29 +23,21 @@
#pragma once
-#include <float.h>
-#include <math.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_ID.h"
-#include "DNA_color_types.h"
-#include "DNA_customdata_types.h"
-#include "DNA_image_types.h"
-#include "DNA_material_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
+#include <cfloat>
+#include <cmath>
+#include <cstring>
#include "BLI_blenlib.h"
+#include "BLI_color.hh"
#include "BLI_math.h"
#include "BLI_math_base_safe.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_rand.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
@@ -55,53 +47,46 @@
#include "BKE_node.h"
#include "BKE_texture.h"
-#include "NOD_shader.h"
-#include "node_util.h"
-
-#include "BLT_translation.h"
-
-#include "IMB_colormanagement.h"
+#include "DNA_ID.h"
+#include "DNA_color_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
-#include "RE_pipeline.h"
-#include "RE_texture.h"
+#include "FN_multi_function_builder.hh"
#include "GPU_material.h"
#include "GPU_texture.h"
#include "GPU_uniform_buffer.h"
-#ifdef __cplusplus
-# include "FN_multi_function_builder.hh"
+#include "IMB_colormanagement.h"
-# include "NOD_multi_function.hh"
-# include "NOD_socket_declarations.hh"
+#include "MEM_guardedalloc.h"
-# include "BLI_color.hh"
-# include "BLI_float3.hh"
+#include "NOD_multi_function.hh"
+#include "NOD_shader.h"
+#include "NOD_socket_declarations.hh"
+#include "node_util.h"
-extern "C" {
-#endif
+#include "RE_pipeline.h"
+#include "RE_texture.h"
bool sh_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
-void sh_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
-void sh_fn_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
+void sh_fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
/* ********* exec data struct, remains internal *********** */
-typedef struct ShaderCallData {
- /* Empty for now, may be reused if we convert shader to texture nodes. */
- int dummy;
-} ShaderCallData;
-
-typedef struct XYZ_to_RGB /* Transposed #imbuf_xyz_to_rgb, passed as 3x vec3. */
+struct XYZ_to_RGB /* Transposed #imbuf_xyz_to_rgb, passed as 3x vec3. */
{
float r[3], g[3], b[3];
-} XYZ_to_RGB;
-
-void nodestack_get_vec(float *in, short type_in, bNodeStack *ns);
+};
void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, struct bNodeStack *ns);
void node_data_from_gpu_stack(struct bNodeStack *ns, struct GPUNodeStack *gs);
@@ -116,11 +101,12 @@ void node_shader_gpu_tex_mapping(struct GPUMaterial *mat,
struct GPUNodeStack *in,
struct GPUNodeStack *out);
+struct bNodeTreeExec *ntreeShaderBeginExecTree_internal(struct bNodeExecContext *context,
+ struct bNodeTree *ntree,
+ bNodeInstanceKey parent_key);
+void ntreeShaderEndExecTree_internal(struct bNodeTreeExec *exec);
+
void ntreeExecGPUNodes(struct bNodeTreeExec *exec,
struct GPUMaterial *mat,
struct bNode *output_node);
void get_XYZ_to_RGB_for_gpu(XYZ_to_RGB *data);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/nodes/shader/nodes/node_shader_add_shader.c b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc
index 12c138ac9d5..73d5c12ce96 100644
--- a/source/blender/nodes/shader/nodes/node_shader_add_shader.c
+++ b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc
@@ -17,20 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_add_shader_cc {
-static bNodeSocketTemplate sh_node_add_shader_in[] = {
- {SOCK_SHADER, N_("Shader")},
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_add_shader_out[] = {
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Shader>(N_("Shader"));
+ b.add_input<decl::Shader>(N_("Shader"), "Shader_001");
+ b.add_output<decl::Shader>(N_("Shader"));
+}
static int node_shader_gpu_add_shader(GPUMaterial *mat,
bNode *node,
@@ -41,16 +37,18 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_add_shader", in, out);
}
+} // namespace blender::nodes::node_shader_add_shader_cc
+
/* node type definition */
-void register_node_type_sh_add_shader(void)
+void register_node_type_sh_add_shader()
{
+ namespace file_ns = blender::nodes::node_shader_add_shader_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_ADD_SHADER, "Add Shader", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_add_shader_in, sh_node_add_shader_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_add_shader);
+ sh_node_type_base(&ntype, SH_NODE_ADD_SHADER, "Add Shader", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_add_shader);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc
index abe80ebcefb..9c64594aab8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
+++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc
@@ -17,22 +17,30 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_ambient_occlusion_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_ambient_occlusion_cc {
-static bNodeSocketTemplate sh_node_ambient_occlusion_out[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("AO"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Distance")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).min(-1.0f).max(1.0f).hide_value();
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("AO"));
+}
+
+static void node_shader_buts_ambient_occlusion(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "inside", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "only_local", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat,
bNode *node,
@@ -64,16 +72,20 @@ static void node_shader_init_ambient_occlusion(bNodeTree *UNUSED(ntree), bNode *
node->custom2 = 0;
}
+} // namespace blender::nodes::node_shader_ambient_occlusion_cc
+
/* node type definition */
-void register_node_type_sh_ambient_occlusion(void)
+void register_node_type_sh_ambient_occlusion()
{
+ namespace file_ns = blender::nodes::node_shader_ambient_occlusion_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_ambient_occlusion_in, sh_node_ambient_occlusion_out);
- node_type_init(&ntype, node_shader_init_ambient_occlusion);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_ambient_occlusion);
+ sh_node_type_base(&ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_ambient_occlusion;
+ node_type_init(&ntype, file_ns::node_shader_init_ambient_occlusion);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_ambient_occlusion);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.cc
index 9b3122e38e0..cf1b49ba29c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.cc
@@ -17,21 +17,30 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_attribute_out[] = {
- {SOCK_RGBA, N_("Color")},
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Fac"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_FACTOR},
- {SOCK_FLOAT, N_("Alpha"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_FACTOR},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_attribute_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Vector>(N_("Vector"));
+ b.add_output<decl::Float>(N_("Fac"));
+ b.add_output<decl::Float>(N_("Alpha"));
+}
+
+static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "attribute_type", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Type"), ICON_NONE);
+ uiItemR(layout, ptr, "attribute_name", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Name"), ICON_NONE);
+}
static void node_shader_init_attribute(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderAttribute *attr = MEM_callocN(sizeof(NodeShaderAttribute), "NodeShaderAttribute");
+ NodeShaderAttribute *attr = MEM_cnew<NodeShaderAttribute>("NodeShaderAttribute");
node->storage = attr;
}
@@ -41,7 +50,7 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderAttribute *attr = node->storage;
+ NodeShaderAttribute *attr = static_cast<NodeShaderAttribute *>(node->storage);
bool is_varying = attr->type == SHD_ATTRIBUTE_GEOMETRY;
if (GPU_material_is_volume_shader(mat) && is_varying) {
@@ -73,25 +82,30 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
GPU_stack_link(mat, node, "node_attribute", in, out, cd_attr);
- /* for each output. */
- for (int i = 0; sh_node_attribute_out[i].type != -1; i++) {
+ int i;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) {
node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
}
return 1;
}
+} // namespace blender::nodes::node_shader_attribute_cc
+
/* node type definition */
-void register_node_type_sh_attribute(void)
+void register_node_type_sh_attribute()
{
+ namespace file_ns = blender::nodes::node_shader_attribute_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_ATTRIBUTE, "Attribute", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_attribute_out);
- node_type_init(&ntype, node_shader_init_attribute);
+ sh_node_type_base(&ntype, SH_NODE_ATTRIBUTE, "Attribute", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_attribute;
+ node_type_init(&ntype, file_ns::node_shader_init_attribute);
node_type_storage(
&ntype, "NodeShaderAttribute", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_attribute);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_attribute);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_background.c b/source/blender/nodes/shader/nodes/node_shader_background.cc
index 5281a9fecb1..3b9e71cf842 100644
--- a/source/blender/nodes/shader/nodes/node_shader_background.c
+++ b/source/blender/nodes/shader/nodes/node_shader_background.cc
@@ -17,20 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_background_cc {
-static bNodeSocketTemplate sh_node_background_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000000.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_background_out[] = {
- {SOCK_SHADER, N_("Background")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Strength")).default_value(1.0f).min(0.0f).max(1000000.0f);
+ b.add_output<decl::Shader>(N_("Background"));
+}
static int node_shader_gpu_background(GPUMaterial *mat,
bNode *node,
@@ -41,16 +37,18 @@ static int node_shader_gpu_background(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_background", in, out);
}
+} // namespace blender::nodes::node_shader_background_cc
+
/* node type definition */
-void register_node_type_sh_background(void)
+void register_node_type_sh_background()
{
+ namespace file_ns = blender::nodes::node_shader_background_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BACKGROUND, "Background", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_background_in, sh_node_background_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_background);
+ sh_node_type_base(&ntype, SH_NODE_BACKGROUND, "Background", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_background);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.c b/source/blender/nodes/shader/nodes/node_shader_bevel.cc
index 347d82c5506..c4fa61753f5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bevel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bevel.cc
@@ -17,20 +17,24 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_bevel_in[] = {
- {SOCK_FLOAT, N_("Radius"), 0.05f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_bevel_cc {
-static bNodeSocketTemplate sh_node_bevel_out[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Radius")).default_value(0.05f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Vector>(N_("Normal"));
+}
+
+static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
static void node_shader_init_bevel(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -54,16 +58,20 @@ static int gpu_shader_bevel(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bevel", in, out);
}
+} // namespace blender::nodes::node_shader_bevel_cc
+
/* node type definition */
-void register_node_type_sh_bevel(void)
+void register_node_type_sh_bevel()
{
+ namespace file_ns = blender::nodes::node_shader_bevel_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BEVEL, "Bevel", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_bevel_in, sh_node_bevel_out);
- node_type_init(&ntype, node_shader_init_bevel);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_bevel);
+ sh_node_type_base(&ntype, SH_NODE_BEVEL, "Bevel", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_bevel;
+ node_type_init(&ntype, file_ns::node_shader_init_bevel);
+ node_type_gpu(&ntype, file_ns::gpu_shader_bevel);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.c b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
index 95c35affc27..85e2ed08403 100644
--- a/source/blender/nodes/shader/nodes/node_shader_blackbody.c
+++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
@@ -17,18 +17,15 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Blackbody ******************** */
-static bNodeSocketTemplate sh_node_blackbody_in[] = {
- {SOCK_FLOAT, N_("Temperature"), 1500.0f, 0.0f, 0.0f, 0.0f, 800.0f, 12000.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_blackbody_cc {
-static bNodeSocketTemplate sh_node_blackbody_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Temperature")).default_value(1500.0f).min(800.0f).max(12000.0f);
+ b.add_output<decl::Color>(N_("Color"));
+}
static int node_shader_gpu_blackbody(GPUMaterial *mat,
bNode *node,
@@ -37,7 +34,7 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat,
GPUNodeStack *out)
{
const int size = CM_TABLE + 1;
- float *data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
+ float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "blackbody texture"));
blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
@@ -47,17 +44,19 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_blackbody", in, out, ramp_texture, GPU_constant(&layer));
}
+} // namespace blender::nodes::node_shader_blackbody_cc
+
/* node type definition */
-void register_node_type_sh_blackbody(void)
+void register_node_type_sh_blackbody()
{
+ namespace file_ns = blender::nodes::node_shader_blackbody_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BLACKBODY, "Blackbody", NODE_CLASS_CONVERTER, 0);
+ sh_node_type_base(&ntype, SH_NODE_BLACKBODY, "Blackbody", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_socket_templates(&ntype, sh_node_blackbody_in, sh_node_blackbody_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_blackbody);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_blackbody);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.cc
index 4f375c666de..66bfaba2785 100644
--- a/source/blender/nodes/shader/nodes/node_shader_brightness.c
+++ b/source/blender/nodes/shader/nodes/node_shader_brightness.cc
@@ -17,21 +17,17 @@
* All rights reserved.
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Bright and contrast ******************** */
+namespace blender::nodes::node_shader_brightness_cc {
-static bNodeSocketTemplate sh_node_brightcontrast_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Bright"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Contrast"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_brightcontrast_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Bright")).default_value(0.0f).min(-100.0f).max(100.0f);
+ b.add_input<decl::Float>(N_("Contrast")).default_value(0.0f).min(-100.0f).max(100.0f);
+ b.add_output<decl::Color>(N_("Color"));
+}
static int gpu_shader_brightcontrast(GPUMaterial *mat,
bNode *node,
@@ -42,15 +38,17 @@ static int gpu_shader_brightcontrast(GPUMaterial *mat,
return GPU_stack_link(mat, node, "brightness_contrast", in, out);
}
-void register_node_type_sh_brightcontrast(void)
+} // namespace blender::nodes::node_shader_brightness_cc
+
+void register_node_type_sh_brightcontrast()
{
+ namespace file_ns = blender::nodes::node_shader_brightness_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_brightcontrast_in, sh_node_brightcontrast_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_brightcontrast);
+ sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_brightcontrast);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc
index 499f62da683..3f0749ab2af 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc
@@ -17,24 +17,36 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_bsdf_anisotropic_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Anisotropy"), 0.5f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f},
- {SOCK_FLOAT, N_("Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_VECTOR, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_bsdf_anisotropic_cc {
-static bNodeSocketTemplate sh_node_bsdf_anisotropic_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Anisotropy")).default_value(0.5f).min(-1.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Rotation"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Vector>(N_("Tangent")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "distribution", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_anisotropic(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -64,17 +76,21 @@ static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat,
GPU_constant(&node->ssr_id));
}
+} // namespace blender::nodes::node_shader_bsdf_anisotropic_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_anisotropic(void)
+void register_node_type_sh_bsdf_anisotropic()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_anisotropic_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_ANISOTROPIC, "Anisotropic BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_anisotropic_in, sh_node_bsdf_anisotropic_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_ANISOTROPIC, "Anisotropic BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_anisotropic;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_anisotropic);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_anisotropic);
+ node_type_init(&ntype, file_ns::node_shader_init_anisotropic);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_anisotropic);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc
index f4f1d274826..5848ca76cdd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc
@@ -17,21 +17,21 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_diffuse_cc {
-static bNodeSocketTemplate sh_node_bsdf_diffuse_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_diffuse_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat,
bNode *node,
@@ -48,17 +48,19 @@ static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_diffuse", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_diffuse_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_diffuse(void)
+void register_node_type_sh_bsdf_diffuse()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_diffuse_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_DIFFUSE, "Diffuse BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_diffuse_in, sh_node_bsdf_diffuse_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_DIFFUSE, "Diffuse BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_diffuse);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_diffuse);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc
index 5fc946e3509..47d4b87198b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc
@@ -17,22 +17,22 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_glass_cc {
-static bNodeSocketTemplate sh_node_bsdf_glass_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_glass_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static void node_shader_init_glass(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -53,7 +53,7 @@ static int node_shader_gpu_bsdf_glass(GPUMaterial *mat,
GPU_link(mat, "set_value_zero", &in[1].link);
}
- GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT);
+ GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT));
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
@@ -66,17 +66,20 @@ static int node_shader_gpu_bsdf_glass(GPUMaterial *mat,
GPU_constant(&node->ssr_id));
}
+} // namespace blender::nodes::node_shader_bsdf_glass_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_glass(void)
+void register_node_type_sh_bsdf_glass()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_glass_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_GLASS, "Glass BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_glass_in, sh_node_bsdf_glass_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_GLASS, "Glass BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_glass);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_glass);
+ node_type_init(&ntype, file_ns::node_shader_init_glass);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_glass);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc
index 13b1b21c7fc..03a3e634f56 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc
@@ -17,21 +17,21 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_glossy_cc {
-static bNodeSocketTemplate sh_node_bsdf_glossy_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_glossy_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static void node_shader_init_glossy(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -65,17 +65,20 @@ static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat,
GPU_constant(&node->ssr_id));
}
+} // namespace blender::nodes::node_shader_bsdf_glossy_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_glossy(void)
+void register_node_type_sh_bsdf_glossy()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_glossy_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_GLOSSY, "Glossy BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_glossy_in, sh_node_bsdf_glossy_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_GLOSSY, "Glossy BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_glossy);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_glossy);
+ node_type_init(&ntype, file_ns::node_shader_init_glossy);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_glossy);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc
index fb2decec5f4..3be2bd22f60 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc
@@ -17,23 +17,39 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_bsdf_hair_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Offset"), 0.0f, 0.0f, 0.0f, 0.0f, -M_PI_2, M_PI_2, PROP_ANGLE},
- {SOCK_FLOAT, N_("RoughnessU"), 0.1f, 0.1f, 0.1f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("RoughnessV"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_bsdf_hair_cc {
-static bNodeSocketTemplate sh_node_bsdf_hair_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Offset"))
+ .default_value(0.0f)
+ .min(-M_PI_2)
+ .max(M_PI_2)
+ .subtype(PROP_ANGLE);
+ b.add_input<decl::Float>(N_("RoughnessU"))
+ .default_value(0.1f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("RoughnessV"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Tangent")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "component", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static int node_shader_gpu_bsdf_hair(GPUMaterial *mat,
bNode *node,
@@ -44,17 +60,20 @@ static int node_shader_gpu_bsdf_hair(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_hair", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_hair_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_hair(void)
+void register_node_type_sh_bsdf_hair()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_hair_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_hair_in, sh_node_bsdf_hair_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_hair;
node_type_size(&ntype, 150, 60, 200);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_hair);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_hair);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
deleted file mode 100644
index d2b40a7ec39..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2018 Blender Foundation.
- * All rights reserved.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-/* Color, melanin and absorption coefficient default to approximately same brownish hair. */
-static bNodeSocketTemplate sh_node_bsdf_hair_principled_in[] = {
- {SOCK_RGBA, N_("Color"), 0.017513f, 0.005763f, 0.002059f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Melanin"), 0.8f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Melanin Redness"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Tint"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Absorption Coefficient"), 0.245531f, 0.52f, 1.365f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.3f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Radial Roughness"), 0.3f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Coat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("IOR"), 1.55f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT,
- N_("Offset"),
- 2.0f * ((float)M_PI) / 180.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- -M_PI_2,
- M_PI_2,
- PROP_ANGLE},
- {SOCK_FLOAT, N_("Random Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Random Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Random"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_hair_principled_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
-
-/* Initialize the custom Parametrization property to Color. */
-static void node_shader_init_hair_principled(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->custom1 = SHD_PRINCIPLED_HAIR_REFLECTANCE;
-}
-
-/* Triggers (in)visibility of some sockets when changing Parametrization. */
-static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node)
-{
- bNodeSocket *sock;
- int parametrization = node->custom1;
-
- for (sock = node->inputs.first; sock; sock = sock->next) {
- if (STREQ(sock->name, "Color")) {
- nodeSetSocketAvailability(ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE);
- }
- else if (STREQ(sock->name, "Melanin")) {
- nodeSetSocketAvailability(
- ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
- }
- else if (STREQ(sock->name, "Melanin Redness")) {
- nodeSetSocketAvailability(
- ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
- }
- else if (STREQ(sock->name, "Tint")) {
- nodeSetSocketAvailability(
- ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
- }
- else if (STREQ(sock->name, "Absorption Coefficient")) {
- nodeSetSocketAvailability(
- ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION);
- }
- else if (STREQ(sock->name, "Random Color")) {
- nodeSetSocketAvailability(
- ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
- }
- }
-}
-
-/* node type definition */
-void register_node_type_sh_bsdf_hair_principled(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(
- &ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(
- &ntype, sh_node_bsdf_hair_principled_in, sh_node_bsdf_hair_principled_out);
- node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, node_shader_init_hair_principled);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_update(&ntype, node_shader_update_hair_principled);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
new file mode 100644
index 00000000000..7062888b5fb
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
@@ -0,0 +1,145 @@
+/*
+ * 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) 2018 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_bsdf_hair_principled_cc {
+
+/* Color, melanin and absorption coefficient default to approximately same brownish hair. */
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.017513f, 0.005763f, 0.002059f, 1.0f});
+ b.add_input<decl::Float>(N_("Melanin"))
+ .default_value(0.8f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Melanin Redness"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Tint")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Absorption Coefficient"))
+ .default_value({0.245531f, 0.52f, 1.365f})
+ .min(0.0f)
+ .max(1000.0f);
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.3f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Radial Roughness"))
+ .default_value(0.3f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Coat"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.55f).min(0.0f).max(1000.0f).subtype(
+ PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Offset"))
+ .default_value(2.0f * ((float)M_PI) / 180.0f)
+ .min(-M_PI_2)
+ .max(M_PI_2)
+ .subtype(PROP_ANGLE);
+ b.add_input<decl::Float>(N_("Random Color"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Random Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Random")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static void node_shader_buts_principled_hair(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "parametrization", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+/* Initialize the custom Parametrization property to Color. */
+static void node_shader_init_hair_principled(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_PRINCIPLED_HAIR_REFLECTANCE;
+}
+
+/* Triggers (in)visibility of some sockets when changing Parametrization. */
+static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node)
+{
+ int parametrization = node->custom1;
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ if (STREQ(sock->name, "Color")) {
+ nodeSetSocketAvailability(ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE);
+ }
+ else if (STREQ(sock->name, "Melanin")) {
+ nodeSetSocketAvailability(
+ ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
+ }
+ else if (STREQ(sock->name, "Melanin Redness")) {
+ nodeSetSocketAvailability(
+ ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
+ }
+ else if (STREQ(sock->name, "Tint")) {
+ nodeSetSocketAvailability(
+ ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
+ }
+ else if (STREQ(sock->name, "Absorption Coefficient")) {
+ nodeSetSocketAvailability(
+ ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION);
+ }
+ else if (STREQ(sock->name, "Random Color")) {
+ nodeSetSocketAvailability(
+ ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
+ }
+ }
+}
+
+} // namespace blender::nodes::node_shader_bsdf_hair_principled_cc
+
+/* node type definition */
+void register_node_type_sh_bsdf_hair_principled()
+{
+ namespace file_ns = blender::nodes::node_shader_bsdf_hair_principled_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(
+ &ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_principled_hair;
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_init(&ntype, file_ns::node_shader_init_hair_principled);
+ node_type_update(&ntype, file_ns::node_shader_update_hair_principled);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc
index b9f4106c79a..4c378d9bc09 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc
@@ -17,61 +17,116 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_bsdf_principled_in[] = {
- {SOCK_RGBA, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Subsurface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR,
- N_("Subsurface Radius"),
- 1.0f,
- 0.2f,
- 0.1f,
- 0.0f,
- 0.0f,
- 100.0f,
- PROP_NONE,
- SOCK_COMPACT},
- {SOCK_RGBA, N_("Subsurface Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Subsurface IOR"), 1.4f, 0.0f, 0.0f, 0.0f, 1.01f, 3.8f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Subsurface Anisotropy"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Metallic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Specular"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Specular Tint"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Anisotropic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Anisotropic Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Sheen"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Sheen Tint"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Clearcoat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Clearcoat Roughness"), 0.03f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Transmission"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Transmission Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Emission"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Emission Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000000.0f},
- {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_VECTOR,
- N_("Clearcoat Normal"),
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- -1.0f,
- 1.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {SOCK_VECTOR, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_principled_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_bsdf_principled_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Base Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Subsurface"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Subsurface Radius"))
+ .default_value({1.0f, 0.2f, 0.1f})
+ .min(0.0f)
+ .max(100.0f)
+ .compact();
+ b.add_input<decl::Color>(N_("Subsurface Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Subsurface IOR"))
+ .default_value(1.4f)
+ .min(1.01f)
+ .max(3.8f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Subsurface Anisotropy"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Metallic"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Specular"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Specular Tint"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Anisotropic"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Anisotropic Rotation"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Sheen"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Sheen Tint"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Clearcoat"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Clearcoat Roughness"))
+ .default_value(0.03f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Transmission"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Transmission Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Emission")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Emission Strength")).default_value(1.0).min(0.0f).max(1000000.0f);
+ b.add_input<decl::Float>(N_("Alpha"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Vector>(N_("Clearcoat Normal")).hide_value();
+ b.add_input<decl::Vector>(N_("Tangent")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "distribution", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "subsurface_method", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -122,8 +177,8 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
/* SSS Profile */
if (use_subsurf) {
- bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
- bNodeSocketValueRGBA *socket_data = socket->default_value;
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2);
+ bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value;
/* For some reason it seems that the socket value is in ARGB format. */
GPU_material_sss_profile_create(mat, &socket_data->value[1]);
}
@@ -151,7 +206,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
float f_use_refraction = use_refract ? 1.0f : 0.0f;
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
- GPU_material_flag_set(mat, flag);
+ GPU_material_flag_set(mat, (eGPUMatFlag)flag);
return GPU_stack_link(mat,
node,
@@ -172,7 +227,7 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
const int distribution = node->custom1;
const int sss_method = node->custom2;
- for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (STREQ(sock->name, "Transmission Roughness")) {
nodeSetSocketAvailability(ntree, sock, distribution == SHD_GLOSSY_GGX);
}
@@ -183,18 +238,22 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
}
}
+} // namespace blender::nodes::node_shader_bsdf_principled_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_principled(void)
+void register_node_type_sh_bsdf_principled()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_principled_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_principled_in, sh_node_bsdf_principled_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_principled;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, node_shader_init_principled);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_principled);
- node_type_update(&ntype, node_shader_update_principled);
+ node_type_init(&ntype, file_ns::node_shader_init_principled);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_principled);
+ node_type_update(&ntype, file_ns::node_shader_update_principled);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc
index ff33b3456db..0d588c82869 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc
@@ -17,22 +17,22 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_refraction_cc {
-static bNodeSocketTemplate sh_node_bsdf_refraction_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_refraction_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static void node_shader_init_refraction(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -58,17 +58,20 @@ static int node_shader_gpu_bsdf_refraction(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_refraction", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_refraction_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_refraction(void)
+void register_node_type_sh_bsdf_refraction()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_refraction_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_refraction_in, sh_node_bsdf_refraction_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_refraction);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_refraction);
+ node_type_init(&ntype, file_ns::node_shader_init_refraction);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_refraction);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc
index 2d04fcee40c..5093b896764 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc
@@ -17,22 +17,34 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_bsdf_toon_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Size"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Smooth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_bsdf_toon_cc {
-static bNodeSocketTemplate sh_node_bsdf_toon_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Size"))
+ .default_value(0.5f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Smooth"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
+
+static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "component", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static int node_shader_gpu_bsdf_toon(GPUMaterial *mat,
bNode *node,
@@ -49,17 +61,20 @@ static int node_shader_gpu_bsdf_toon(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_toon", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_toon_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_toon(void)
+void register_node_type_sh_bsdf_toon()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_toon_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_TOON, "Toon BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_toon_in, sh_node_bsdf_toon_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_TOON, "Toon BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_toon;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_toon);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_toon);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc
index d2e1a276645..22891738299 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc
@@ -17,20 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_translucent_cc {
-static bNodeSocketTemplate sh_node_bsdf_translucent_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_translucent_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat,
bNode *node,
@@ -47,16 +43,18 @@ static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_translucent", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_translucent_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_translucent(void)
+void register_node_type_sh_bsdf_translucent()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_translucent_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSLUCENT, "Translucent BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_translucent_in, sh_node_bsdf_translucent_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_translucent);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSLUCENT, "Translucent BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_translucent);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc
index 45f8ebf1d52..d764f4dd76b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc
@@ -17,19 +17,15 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_transparent_cc {
-static bNodeSocketTemplate sh_node_bsdf_transparent_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_transparent_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static int node_shader_gpu_bsdf_transparent(GPUMaterial *mat,
bNode *node,
@@ -40,16 +36,18 @@ static int node_shader_gpu_bsdf_transparent(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_transparent", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_transparent_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_transparent(void)
+void register_node_type_sh_bsdf_transparent()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_transparent_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSPARENT, "Transparent BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_transparent_in, sh_node_bsdf_transparent_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_transparent);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSPARENT, "Transparent BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_transparent);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc
index 59e8bbd3c63..dd090236c08 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc
@@ -17,21 +17,21 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_bsdf_velvet_cc {
-static bNodeSocketTemplate sh_node_bsdf_velvet_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Sigma"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_bsdf_velvet_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Sigma"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static int node_shader_gpu_bsdf_velvet(GPUMaterial *mat,
bNode *node,
@@ -48,16 +48,18 @@ static int node_shader_gpu_bsdf_velvet(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_velvet", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_velvet_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_velvet(void)
+void register_node_type_sh_bsdf_velvet()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_velvet_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_VELVET, "Velvet BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_velvet_in, sh_node_bsdf_velvet_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_velvet);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_VELVET, "Velvet BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_velvet);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.cc
index 7444ea3952a..252abd02ad7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.cc
@@ -21,22 +21,38 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
/* **************** BUMP ******************** */
-/* clang-format off */
-static bNodeSocketTemplate sh_node_bump_in[] = {
- {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Height"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Height_dx"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL},
- {SOCK_FLOAT, N_("Height_dy"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""}
-};
-/* clang-format on */
-static bNodeSocketTemplate sh_node_bump_out[] = {{SOCK_VECTOR, "Normal"}, {-1, ""}};
+namespace blender::nodes::node_shader_bump_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Strength"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Distance")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Height"))
+ .default_value(1.0f)
+ .min(-1000.0f)
+ .max(1000.0f)
+ .hide_value();
+ b.add_input<decl::Float>(N_("Height_dx")).default_value(1.0f).unavailable();
+ b.add_input<decl::Float>(N_("Height_dy")).default_value(1.0f).unavailable();
+ b.add_input<decl::Vector>(N_("Normal")).min(-1.0f).max(1.0f).hide_value();
+ b.add_output<decl::Vector>(N_("Normal"));
+}
+
+static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "invert", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+}
static int gpu_shader_bump(GPUMaterial *mat,
bNode *node,
@@ -54,15 +70,19 @@ static int gpu_shader_bump(GPUMaterial *mat,
mat, node, "node_bump", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_constant(&invert));
}
+} // namespace blender::nodes::node_shader_bump_cc
+
/* node type definition */
-void register_node_type_sh_bump(void)
+void register_node_type_sh_bump()
{
+ namespace file_ns = blender::nodes::node_shader_bump_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BUMP, "Bump", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_bump_in, sh_node_bump_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_bump);
+ sh_node_type_base(&ntype, SH_NODE_BUMP, "Bump", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_bump;
+ node_type_gpu(&ntype, file_ns::gpu_shader_bump);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.cc
index 5148104700a..b9c624faed9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_camera.c
+++ b/source/blender/nodes/shader/nodes/node_shader_camera.cc
@@ -21,15 +21,16 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** CAMERA INFO ******************** */
-static bNodeSocketTemplate sh_node_camera_out[] = {
- {SOCK_VECTOR, N_("View Vector")},
- {SOCK_FLOAT, N_("View Z Depth")},
- {SOCK_FLOAT, N_("View Distance")},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_camera_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("View Vector"));
+ b.add_output<decl::Float>(N_("View Z Depth"));
+ b.add_output<decl::Float>(N_("View Distance"));
+}
static int gpu_shader_camera(GPUMaterial *mat,
bNode *node,
@@ -44,14 +45,17 @@ static int gpu_shader_camera(GPUMaterial *mat,
return GPU_stack_link(mat, node, "camera", in, out, viewvec);
}
-void register_node_type_sh_camera(void)
+} // namespace blender::nodes::node_shader_camera_cc
+
+void register_node_type_sh_camera()
{
+ namespace file_ns = blender::nodes::node_shader_camera_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_CAMERA, "Camera Data", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_camera_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_camera);
+ sh_node_type_base(&ntype, SH_NODE_CAMERA, "Camera Data", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_camera);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
index 6c3457151e5..cd0f1b3c44d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
@@ -21,20 +21,26 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_clamp_cc {
static void sh_node_clamp_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>(N_("Value")).min(0.0f).max(1.0f).default_value(1.0f);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f);
b.add_input<decl::Float>(N_("Min")).default_value(0.0f).min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>(N_("Max")).default_value(1.0f).min(-10000.0f).max(10000.0f);
b.add_output<decl::Float>(N_("Result"));
-};
+}
-} // namespace blender::nodes
+static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "clamp_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_clamp(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -75,15 +81,20 @@ static void sh_node_clamp_build_multi_function(blender::nodes::NodeMultiFunction
}
}
+} // namespace blender::nodes::node_shader_clamp_cc
+
void register_node_type_sh_clamp()
{
+ namespace file_ns = blender::nodes::node_shader_clamp_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_clamp_declare;
- node_type_init(&ntype, node_shader_init_clamp);
- node_type_gpu(&ntype, gpu_shader_clamp);
- ntype.build_multi_function = sh_node_clamp_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_clamp_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_clamp;
+ node_type_init(&ntype, file_ns::node_shader_init_clamp);
+ node_type_gpu(&ntype, file_ns::gpu_shader_clamp);
+ ntype.build_multi_function = file_ns::sh_node_clamp_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc
new file mode 100644
index 00000000000..d8c43e1d66b
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc
@@ -0,0 +1,169 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "DNA_texture_types.h"
+
+#include "BLI_color.hh"
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_color_ramp_cc {
+
+static void sh_node_valtorgb_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Alpha"));
+}
+
+static void node_shader_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->storage = BKE_colorband_add(true);
+}
+
+static int gpu_shader_valtorgb(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ struct ColorBand *coba = (ColorBand *)node->storage;
+ float *array, layer;
+ int size;
+
+ /* Common / easy case optimization. */
+ if ((coba->tot <= 2) && (coba->color_mode == COLBAND_BLEND_RGB)) {
+ float mul_bias[2];
+ switch (coba->ipotype) {
+ case COLBAND_INTERP_LINEAR:
+ mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos);
+ mul_bias[1] = -mul_bias[0] * coba->data[0].pos;
+ return GPU_stack_link(mat,
+ node,
+ "valtorgb_opti_linear",
+ in,
+ out,
+ GPU_uniform(mul_bias),
+ GPU_uniform(&coba->data[0].r),
+ GPU_uniform(&coba->data[1].r));
+ case COLBAND_INTERP_CONSTANT:
+ mul_bias[1] = max_ff(coba->data[0].pos, coba->data[1].pos);
+ return GPU_stack_link(mat,
+ node,
+ "valtorgb_opti_constant",
+ in,
+ out,
+ GPU_uniform(&mul_bias[1]),
+ GPU_uniform(&coba->data[0].r),
+ GPU_uniform(&coba->data[1].r));
+ case COLBAND_INTERP_EASE:
+ mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos);
+ mul_bias[1] = -mul_bias[0] * coba->data[0].pos;
+ return GPU_stack_link(mat,
+ node,
+ "valtorgb_opti_ease",
+ in,
+ out,
+ GPU_uniform(mul_bias),
+ GPU_uniform(&coba->data[0].r),
+ GPU_uniform(&coba->data[1].r));
+ default:
+ break;
+ }
+ }
+
+ BKE_colorband_evaluate_table_rgba(coba, &array, &size);
+ GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
+
+ if (coba->ipotype == COLBAND_INTERP_CONSTANT) {
+ return GPU_stack_link(mat, node, "valtorgb_nearest", in, out, tex, GPU_constant(&layer));
+ }
+
+ return GPU_stack_link(mat, node, "valtorgb", in, out, tex, GPU_constant(&layer));
+}
+
+class ColorBandFunction : public blender::fn::MultiFunction {
+ private:
+ const ColorBand &color_band_;
+
+ public:
+ ColorBandFunction(const ColorBand &color_band) : color_band_(color_band)
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Color Band"};
+ signature.single_input<float>("Value");
+ signature.single_output<blender::ColorGeometry4f>("Color");
+ signature.single_output<float>("Alpha");
+ return signature.build();
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
+ blender::MutableSpan<blender::ColorGeometry4f> colors =
+ params.uninitialized_single_output<blender::ColorGeometry4f>(1, "Color");
+ blender::MutableSpan<float> alphas = params.uninitialized_single_output<float>(2, "Alpha");
+
+ for (int64_t i : mask) {
+ blender::ColorGeometry4f color;
+ BKE_colorband_evaluate(&color_band_, values[i], color);
+ colors[i] = color;
+ alphas[i] = color.a;
+ }
+ }
+};
+
+static void sh_node_valtorgb_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ bNode &bnode = builder.node();
+ const ColorBand *color_band = (const ColorBand *)bnode.storage;
+ builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
+}
+
+} // namespace blender::nodes::node_shader_color_ramp_cc
+
+void register_node_type_sh_valtorgb()
+{
+ namespace file_ns = blender::nodes::node_shader_color_ramp_cc;
+
+ static bNodeType ntype;
+
+ sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_valtorgb_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_valtorgb);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, file_ns::gpu_shader_valtorgb);
+ ntype.build_multi_function = file_ns::sh_node_valtorgb_build_multi_function;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
deleted file mode 100644
index 190e0cfad4c..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2006 Blender Foundation.
- * All rights reserved.
- * Juho Vepsäläinen
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "DNA_node_types.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_node.h"
-
-#include "NOD_common.h"
-#include "node_common.h"
-#include "node_exec.h"
-#include "node_shader_util.h"
-
-#include "RNA_access.h"
-
-static void copy_stack(bNodeStack *to, bNodeStack *from)
-{
- if (to != from) {
- copy_v4_v4(to->vec, from->vec);
- to->data = from->data;
- to->datatype = from->datatype;
-
- /* tag as copy to prevent freeing */
- to->is_copy = 1;
- }
-}
-
-static void move_stack(bNodeStack *to, bNodeStack *from)
-{
- if (to != from) {
- copy_v4_v4(to->vec, from->vec);
- to->data = from->data;
- to->datatype = from->datatype;
- to->is_copy = from->is_copy;
-
- from->data = NULL;
- from->is_copy = 0;
- }
-}
-
-/**** GROUP ****/
-
-static void *group_initexec(bNodeExecContext *context, bNode *node, bNodeInstanceKey key)
-{
- bNodeTree *ngroup = (bNodeTree *)node->id;
- bNodeTreeExec *exec;
-
- if (!ngroup) {
- return NULL;
- }
-
- /* initialize the internal node tree execution */
- exec = ntreeShaderBeginExecTree_internal(context, ngroup, key);
-
- return exec;
-}
-
-static void group_freeexec(void *nodedata)
-{
- bNodeTreeExec *gexec = (bNodeTreeExec *)nodedata;
-
- if (gexec) {
- ntreeShaderEndExecTree_internal(gexec);
- }
-}
-
-/* Copy inputs to the internal stack.
- */
-static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack)
-{
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
-
- for (node = ngroup->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
- if (ns) {
- copy_stack(ns, in[a]);
- }
- }
- }
- }
-}
-
-/* Copy internal results to the external outputs.
- */
-static void group_move_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstack)
-{
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
-
- for (node = ngroup->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
- if (ns) {
- move_stack(out[a], ns);
- }
- }
- break; /* only one active output node */
- }
- }
-}
-
-static void group_execute(void *data,
- int thread,
- struct bNode *node,
- bNodeExecData *execdata,
- struct bNodeStack **in,
- struct bNodeStack **out)
-{
- bNodeTreeExec *exec = execdata->data;
- bNodeThreadStack *nts;
-
- if (!exec) {
- return;
- }
-
- /* XXX same behavior as trunk: all nodes inside group are executed.
- * it's stupid, but just makes it work. compo redesign will do this better.
- */
- {
- bNode *inode;
- for (inode = exec->nodetree->nodes.first; inode; inode = inode->next) {
- inode->need_exec = 1;
- }
- }
-
- nts = ntreeGetThreadStack(exec, thread);
-
- group_copy_inputs(node, in, nts->stack);
- ntreeExecThreadNodes(exec, nts, data, thread);
- group_move_outputs(node, out, nts->stack);
-
- ntreeReleaseThreadStack(nts);
-}
-
-static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gstack)
-{
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
-
- for (node = ngroup->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
- if (ns) {
- /* convert the external gpu stack back to internal node stack data */
- node_data_from_gpu_stack(ns, &in[a]);
- }
- }
- }
- }
-}
-
-/* Copy internal results to the external outputs.
- */
-static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack *gstack)
-{
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
-
- for (node = ngroup->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
- if (ns) {
- /* convert the node stack data result back to gpu stack */
- node_gpu_stack_from_data(&out[a], sock->type, ns);
- }
- }
- break; /* only one active output node */
- }
- }
-}
-
-static int gpu_group_execute(
- GPUMaterial *mat, bNode *node, bNodeExecData *execdata, GPUNodeStack *in, GPUNodeStack *out)
-{
- bNodeTreeExec *exec = execdata->data;
-
- if (!node->id) {
- return 0;
- }
-
- group_gpu_copy_inputs(node, in, exec->stack);
- ntreeExecGPUNodes(exec, mat, NULL);
- group_gpu_move_outputs(node, out, exec->stack);
-
- return 1;
-}
-
-void register_node_type_sh_group(void)
-{
- static bNodeType ntype;
-
- /* NOTE: cannot use #sh_node_type_base for node group, because it would map the node type
- * to the shared #NODE_GROUP integer type id. */
-
- node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, 0);
- ntype.type = NODE_GROUP;
- ntype.poll = sh_node_poll_default;
- ntype.poll_instance = node_group_poll_instance;
- ntype.insert_link = node_insert_link_default;
- ntype.rna_ext.srna = RNA_struct_find("ShaderNodeGroup");
- BLI_assert(ntype.rna_ext.srna != NULL);
- RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
-
- node_type_socket_templates(&ntype, NULL, NULL);
- node_type_size(&ntype, 140, 60, 400);
- 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);
-
- nodeRegisterType(&ntype);
-}
-
-void register_node_type_sh_custom_group(bNodeType *ntype)
-{
- /* These methods can be overridden but need a default implementation otherwise. */
- if (ntype->poll == NULL) {
- ntype->poll = sh_node_poll_default;
- }
- if (ntype->insert_link == NULL) {
- ntype->insert_link = node_insert_link_default;
- }
-
- 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_common.cc b/source/blender/nodes/shader/nodes/node_shader_common.cc
new file mode 100644
index 00000000000..3f0fff34533
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_common.cc
@@ -0,0 +1,130 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ * Juho Vepsäläinen
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "DNA_node_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_node.h"
+
+#include "NOD_common.h"
+#include "node_common.h"
+#include "node_exec.h"
+#include "node_shader_util.hh"
+
+#include "RNA_access.h"
+
+/**** GROUP ****/
+
+static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gstack)
+{
+ bNodeTree *ngroup = (bNodeTree *)gnode->id;
+
+ LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
+ if (node->type == NODE_GROUP_INPUT) {
+ int a;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, a) {
+ bNodeStack *ns = node_get_socket_stack(gstack, sock);
+ if (ns) {
+ /* convert the external gpu stack back to internal node stack data */
+ node_data_from_gpu_stack(ns, &in[a]);
+ }
+ }
+ }
+ }
+}
+
+/* Copy internal results to the external outputs.
+ */
+static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack *gstack)
+{
+ bNodeTree *ngroup = (bNodeTree *)gnode->id;
+
+ LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
+ if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
+ int a;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->inputs, a) {
+ bNodeStack *ns = node_get_socket_stack(gstack, sock);
+ if (ns) {
+ /* convert the node stack data result back to gpu stack */
+ node_gpu_stack_from_data(&out[a], sock->type, ns);
+ }
+ }
+ break; /* only one active output node */
+ }
+ }
+}
+
+static int gpu_group_execute(
+ GPUMaterial *mat, bNode *node, bNodeExecData *execdata, GPUNodeStack *in, GPUNodeStack *out)
+{
+ bNodeTreeExec *exec = static_cast<bNodeTreeExec *>(execdata->data);
+
+ if (!node->id) {
+ return 0;
+ }
+
+ group_gpu_copy_inputs(node, in, exec->stack);
+ ntreeExecGPUNodes(exec, mat, nullptr);
+ group_gpu_move_outputs(node, out, exec->stack);
+
+ return 1;
+}
+
+void register_node_type_sh_group()
+{
+ static bNodeType ntype;
+
+ /* NOTE: cannot use #sh_node_type_base for node group, because it would map the node type
+ * to the shared #NODE_GROUP integer type id. */
+
+ node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP);
+ ntype.type = NODE_GROUP;
+ ntype.poll = sh_node_poll_default;
+ ntype.poll_instance = node_group_poll_instance;
+ ntype.insert_link = node_insert_link_default;
+ ntype.rna_ext.srna = RNA_struct_find("ShaderNodeGroup");
+ BLI_assert(ntype.rna_ext.srna != nullptr);
+ RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
+
+ node_type_size(&ntype, 140, 60, 400);
+ ntype.labelfunc = node_group_label;
+ node_type_group_update(&ntype, node_group_update);
+ node_type_gpu(&ntype, gpu_group_execute);
+
+ nodeRegisterType(&ntype);
+}
+
+void register_node_type_sh_custom_group(bNodeType *ntype)
+{
+ /* These methods can be overridden but need a default implementation otherwise. */
+ if (ntype->poll == nullptr) {
+ ntype->poll = sh_node_poll_default;
+ }
+ if (ntype->insert_link == nullptr) {
+ ntype->insert_link = node_insert_link_default;
+ }
+
+ 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 09bbf3d851c..bce59a60033 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc
@@ -21,9 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_curves_cc {
static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b)
{
@@ -31,23 +31,6 @@ static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Fac")).min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
b.add_input<decl::Vector>(N_("Vector")).min(-1.0f).max(1.0f);
b.add_output<decl::Vector>(N_("Vector"));
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_curve_vec(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float vec[3];
-
- /* stack order input: vec */
- /* stack order output: vec */
- nodestack_get_vec(vec, SOCK_VECTOR, in[1]);
- BKE_curvemapping_evaluate3F((CurveMapping *)node->storage, out[0]->vec, vec);
}
static void node_shader_init_curve_vec(bNodeTree *UNUSED(ntree), bNode *node)
@@ -152,25 +135,28 @@ static void sh_node_curve_vec_build_multi_function(
builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap);
}
+} // namespace blender::nodes::node_shader_curves_cc
+
void register_node_type_sh_curve_vec()
{
+ namespace file_ns = blender::nodes::node_shader_curves_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::sh_node_curve_vec_declare;
- node_type_init(&ntype, node_shader_init_curve_vec);
+ sh_fn_node_type_base(&ntype, SH_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::sh_node_curve_vec_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_curve_vec);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
- node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_vec);
- node_type_gpu(&ntype, gpu_shader_curve_vec);
- ntype.build_multi_function = sh_node_curve_vec_build_multi_function;
+ node_type_gpu(&ntype, file_ns::gpu_shader_curve_vec);
+ ntype.build_multi_function = file_ns::sh_node_curve_vec_build_multi_function;
nodeRegisterType(&ntype);
}
/* **************** CURVE RGB ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_shader_curves_cc {
static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b)
{
@@ -178,28 +164,6 @@ static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Fac")).min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR);
b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
b.add_output<decl::Color>(N_("Color"));
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_curve_rgb(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float vec[3];
- float fac;
-
- /* stack order input: vec */
- /* stack order output: vec */
- nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
- nodestack_get_vec(vec, SOCK_VECTOR, in[1]);
- BKE_curvemapping_evaluateRGBF((CurveMapping *)node->storage, out[0]->vec, vec);
- if (fac != 1.0f) {
- interp_v3_v3v3(out[0]->vec, vec, out[0]->vec, fac);
- }
}
static void node_shader_init_curve_rgb(bNodeTree *UNUSED(ntree), bNode *node)
@@ -329,25 +293,28 @@ static void sh_node_curve_rgb_build_multi_function(
builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap);
}
+} // namespace blender::nodes::node_shader_curves_cc
+
void register_node_type_sh_curve_rgb()
{
+ namespace file_ns = blender::nodes::node_shader_curves_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::sh_node_curve_rgb_declare;
- node_type_init(&ntype, node_shader_init_curve_rgb);
+ sh_fn_node_type_base(&ntype, SH_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::sh_node_curve_rgb_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_curve_rgb);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
- node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_rgb);
- node_type_gpu(&ntype, gpu_shader_curve_rgb);
- ntype.build_multi_function = sh_node_curve_rgb_build_multi_function;
+ node_type_gpu(&ntype, file_ns::gpu_shader_curve_rgb);
+ ntype.build_multi_function = file_ns::sh_node_curve_rgb_build_multi_function;
nodeRegisterType(&ntype);
}
/* **************** CURVE FLOAT ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_shader_curves_cc {
static void sh_node_curve_float_declare(NodeDeclarationBuilder &b)
{
@@ -359,26 +326,6 @@ static void sh_node_curve_float_declare(NodeDeclarationBuilder &b)
.subtype(PROP_FACTOR);
b.add_input<decl::Float>(N_("Value")).default_value(1.0f).is_default_link_socket();
b.add_output<decl::Float>(N_("Value"));
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_curve_float(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float value;
- float fac;
-
- nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
- nodestack_get_vec(&value, SOCK_FLOAT, in[1]);
- out[0]->vec[0] = BKE_curvemapping_evaluateF((CurveMapping *)node->storage, 0, value);
- if (fac != 1.0f) {
- out[0]->vec[0] = (1.0f - fac) * value + fac * out[0]->vec[0];
- }
}
static void node_shader_init_curve_float(bNodeTree *UNUSED(ntree), bNode *node)
@@ -473,18 +420,21 @@ static void sh_node_curve_float_build_multi_function(
builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap);
}
+} // namespace blender::nodes::node_shader_curves_cc
+
void register_node_type_sh_curve_float()
{
+ namespace file_ns = blender::nodes::node_shader_curves_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_CURVE_FLOAT, "Float Curve", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_curve_float_declare;
- node_type_init(&ntype, node_shader_init_curve_float);
+ sh_fn_node_type_base(&ntype, SH_NODE_CURVE_FLOAT, "Float Curve", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_curve_float_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_curve_float);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
- node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_float);
- node_type_gpu(&ntype, gpu_shader_curve_float);
- ntype.build_multi_function = sh_node_curve_float_build_multi_function;
+ node_type_gpu(&ntype, file_ns::gpu_shader_curve_float);
+ ntype.build_multi_function = file_ns::sh_node_curve_float_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.c b/source/blender/nodes/shader/nodes/node_shader_displacement.cc
index e7deef23428..c56218e795a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_displacement.c
+++ b/source/blender/nodes/shader/nodes/node_shader_displacement.cc
@@ -17,22 +17,18 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_displacement_cc {
-static bNodeSocketTemplate sh_node_displacement_in[] = {
- {SOCK_FLOAT, N_("Height"), 0.00f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Midlevel"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Scale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_displacement_out[] = {
- {SOCK_VECTOR, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Height")).default_value(0.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Midlevel")).default_value(0.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Vector>(N_("Displacement"));
+}
static void node_shader_init_displacement(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -68,16 +64,19 @@ static int gpu_shader_displacement(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_displacement_world", in, out);
}
+} // namespace blender::nodes::node_shader_displacement_cc
+
/* node type definition */
-void register_node_type_sh_displacement(void)
+void register_node_type_sh_displacement()
{
+ namespace file_ns = blender::nodes::node_shader_displacement_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_displacement_in, sh_node_displacement_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_init(&ntype, node_shader_init_displacement);
- node_type_gpu(&ntype, gpu_shader_displacement);
+ sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_displacement);
+ node_type_gpu(&ntype, file_ns::gpu_shader_displacement);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc
index 015af19abb2..e4c80725c8e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c
+++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc
@@ -17,46 +17,40 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_eevee_specular_cc {
-static bNodeSocketTemplate sh_node_eevee_specular_in[] = {
- {SOCK_RGBA, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f},
- {SOCK_RGBA, N_("Specular"), 0.03f, 0.03f, 0.03f, 1.0f},
- {SOCK_FLOAT, N_("Roughness"), 0.2f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Emissive Color"), 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Transparency"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Clear Coat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Clear Coat Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR,
- N_("Clear Coat Normal"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {SOCK_FLOAT,
- N_("Ambient Occlusion"),
- 1.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_eevee_specular_out[] = {
- {SOCK_SHADER, N_("BSDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Base Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Color>(N_("Specular")).default_value({0.03f, 0.03f, 0.03f, 1.0f});
+ b.add_input<decl::Float>(N_("Roughness"))
+ .default_value(0.2f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Emissive Color")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Transparency"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Clear Coat"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Clear Coat Roughness"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Clear Coat Normal")).hide_value();
+ b.add_input<decl::Float>(N_("Ambient Occlusion")).hide_value();
+ b.add_output<decl::Shader>(N_("BSDF"));
+}
static int node_shader_gpu_eevee_specular(GPUMaterial *mat,
bNode *node,
@@ -81,21 +75,23 @@ static int node_shader_gpu_eevee_specular(GPUMaterial *mat,
GPU_link(mat, "set_value", GPU_constant(&one), &in[9].link);
}
- GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY);
+ GPU_material_flag_set(mat, static_cast<eGPUMatFlag>(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY));
return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_constant(&node->ssr_id));
}
+} // namespace blender::nodes::node_shader_eevee_specular_cc
+
/* node type definition */
-void register_node_type_sh_eevee_specular(void)
+void register_node_type_sh_eevee_specular()
{
+ namespace file_ns = blender::nodes::node_shader_eevee_specular_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_EEVEE_SPECULAR, "Specular BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_eevee_specular_in, sh_node_eevee_specular_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_eevee_specular);
+ sh_node_type_base(&ntype, SH_NODE_EEVEE_SPECULAR, "Specular BSDF", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_eevee_specular);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_emission.c b/source/blender/nodes/shader/nodes/node_shader_emission.cc
index 13f040fca48..ea36763578f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_emission.c
+++ b/source/blender/nodes/shader/nodes/node_shader_emission.cc
@@ -17,20 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_emission_cc {
-static bNodeSocketTemplate sh_node_emission_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000000.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_emission_out[] = {
- {SOCK_SHADER, N_("Emission")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Strength")).default_value(1.0f).min(0.0f).max(1000000.0f);
+ b.add_output<decl::Shader>(N_("Emission"));
+}
static int node_shader_gpu_emission(GPUMaterial *mat,
bNode *node,
@@ -41,16 +37,18 @@ static int node_shader_gpu_emission(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_emission", in, out, GPU_builtin(GPU_VIEW_NORMAL));
}
+} // namespace blender::nodes::node_shader_emission_cc
+
/* node type definition */
-void register_node_type_sh_emission(void)
+void register_node_type_sh_emission()
{
+ namespace file_ns = blender::nodes::node_shader_emission_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_emission_in, sh_node_emission_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_emission);
+ sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_emission);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc
index 0af4e4ff5fb..5dba42fcc30 100644
--- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc
@@ -17,19 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Fresnel ******************** */
-static bNodeSocketTemplate sh_node_fresnel_in[] = {
- {SOCK_FLOAT, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_fresnel_cc {
-static bNodeSocketTemplate sh_node_fresnel_out[] = {
- {SOCK_FLOAT, N_("Fac"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Float>(N_("Fac"));
+}
static int node_shader_gpu_fresnel(GPUMaterial *mat,
bNode *node,
@@ -48,26 +45,18 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION));
}
-static void node_shader_exec_fresnel(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **UNUSED(in),
- bNodeStack **UNUSED(out))
-{
-}
+} // namespace blender::nodes::node_shader_fresnel_cc
/* node type definition */
-void register_node_type_sh_fresnel(void)
+void register_node_type_sh_fresnel()
{
+ namespace file_ns = blender::nodes::node_shader_fresnel_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_fresnel_in, sh_node_fresnel_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_fresnel);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_fresnel);
+ sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_fresnel);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c
deleted file mode 100644
index b48838e5f56..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_gamma.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-#include "node_shader_util.h"
-
-/* **************** Gamma Tools ******************** */
-
-static bNodeSocketTemplate sh_node_gamma_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Gamma"), 1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 10.0f, PROP_UNSIGNED},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_gamma_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
-
-static void node_shader_exec_gamma(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float col[3];
- float gamma;
- nodestack_get_vec(col, SOCK_VECTOR, in[0]);
- nodestack_get_vec(&gamma, SOCK_FLOAT, in[1]);
-
- out[0]->vec[0] = col[0] > 0.0f ? powf(col[0], gamma) : col[0];
- out[0]->vec[1] = col[1] > 0.0f ? powf(col[1], gamma) : col[1];
- out[0]->vec[2] = col[2] > 0.0f ? powf(col[2], gamma) : col[2];
-}
-
-static int node_shader_gpu_gamma(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "node_gamma", in, out);
-}
-
-void register_node_type_sh_gamma(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_gamma_in, sh_node_gamma_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_gamma);
- node_type_gpu(&ntype, node_shader_gpu_gamma);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.cc b/source/blender/nodes/shader/nodes/node_shader_gamma.cc
new file mode 100644
index 00000000000..98a287b08da
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_gamma.cc
@@ -0,0 +1,57 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_gamma_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Gamma"))
+ .default_value(1.0f)
+ .min(0.001f)
+ .max(10.0f)
+ .subtype(PROP_UNSIGNED);
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static int node_shader_gpu_gamma(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "node_gamma", in, out);
+}
+
+} // namespace blender::nodes::node_shader_gamma_cc
+
+void register_node_type_sh_gamma()
+{
+ namespace file_ns = blender::nodes::node_shader_gamma_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_gamma);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.cc
index f66633e64c8..2a5868333a9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geometry.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geometry.cc
@@ -17,22 +17,22 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_geometry_cc {
-static bNodeSocketTemplate sh_node_geometry_out[] = {
- {SOCK_VECTOR, N_("Position"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Tangent"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("True Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Incoming"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Parametric"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Backfacing"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Pointiness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Random Per Island"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Position"));
+ b.add_output<decl::Vector>(N_("Normal"));
+ b.add_output<decl::Vector>(N_("Tangent"));
+ b.add_output<decl::Vector>(N_("True Normal"));
+ b.add_output<decl::Vector>(N_("Incoming"));
+ b.add_output<decl::Vector>(N_("Parametric"));
+ b.add_output<decl::Float>(N_("Backfacing"));
+ b.add_output<decl::Float>(N_("Pointiness"));
+ b.add_output<decl::Float>(N_("Random Per Island"));
+}
static int node_shader_gpu_geometry(GPUMaterial *mat,
bNode *node,
@@ -64,8 +64,8 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
bary_link);
- /* for each output */
- for (int i = 0; sh_node_geometry_out[i].type != -1; i++) {
+ int i;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) {
node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
/* Normalize some vectors after dFdx/dFdy offsets.
* This is the case for interpolated, non linear functions.
@@ -79,23 +79,25 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
out[i].link,
out[i].link,
&out[i].link,
- NULL);
+ nullptr);
}
}
return success;
}
+} // namespace blender::nodes::node_shader_geometry_cc
+
/* node type definition */
-void register_node_type_sh_geometry(void)
+void register_node_type_sh_geometry()
{
+ namespace file_ns = blender::nodes::node_shader_geometry_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_NEW_GEOMETRY, "Geometry", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_geometry_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_geometry);
+ sh_node_type_base(&ntype, SH_NODE_NEW_GEOMETRY, "Geometry", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_geometry);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_hair_info.c b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc
index c721fb9c77a..12c29c40b1d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hair_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc
@@ -17,18 +17,19 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
-
-static bNodeSocketTemplate outputs[] = {
- {SOCK_FLOAT, N_("Is Strand"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Intercept"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Thickness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Tangent Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- // { SOCK_FLOAT, 0, N_("Fade"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Random")},
- {-1, ""},
-};
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_hair_info_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Is Strand"));
+ b.add_output<decl::Float>(N_("Intercept"));
+ b.add_output<decl::Float>(N_("Length"));
+ b.add_output<decl::Float>(N_("Thickness"));
+ b.add_output<decl::Vector>(N_("Tangent Normal"));
+ b.add_output<decl::Float>(N_("Random"));
+}
static int node_shader_gpu_hair_info(GPUMaterial *mat,
bNode *node,
@@ -43,16 +44,18 @@ static int node_shader_gpu_hair_info(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_hair_info", in, out, length_link);
}
+} // namespace blender::nodes::node_shader_hair_info_cc
+
/* node type definition */
-void register_node_type_sh_hair_info(void)
+void register_node_type_sh_hair_info()
{
+ namespace file_ns = blender::nodes::node_shader_hair_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, outputs);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_hair_info);
+ sh_node_type_base(&ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_hair_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_holdout.c b/source/blender/nodes/shader/nodes/node_shader_holdout.cc
index b58f86c1fc0..4f6f8a639de 100644
--- a/source/blender/nodes/shader/nodes/node_shader_holdout.c
+++ b/source/blender/nodes/shader/nodes/node_shader_holdout.cc
@@ -17,18 +17,14 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_holdout_cc {
-static bNodeSocketTemplate sh_node_holdout_in[] = {
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_holdout_out[] = {
- {SOCK_SHADER, N_("Holdout")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Shader>(N_("Holdout"));
+}
static int gpu_shader_rgb(GPUMaterial *mat,
bNode *node,
@@ -39,16 +35,18 @@ static int gpu_shader_rgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_holdout", in, out);
}
+} // namespace blender::nodes::node_shader_holdout_cc
+
/* node type definition */
-void register_node_type_sh_holdout(void)
+void register_node_type_sh_holdout()
{
+ namespace file_ns = blender::nodes::node_shader_holdout_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_HOLDOUT, "Holdout", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_holdout_in, sh_node_holdout_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_rgb);
+ sh_node_type_base(&ntype, SH_NODE_HOLDOUT, "Holdout", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_rgb);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
deleted file mode 100644
index 50eb5bf32c9..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2006 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** Hue Saturation ******************** */
-static bNodeSocketTemplate sh_node_hue_sat_in[] = {
- {SOCK_FLOAT, N_("Hue"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Saturation"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Value"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate sh_node_hue_sat_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
-
-/* NOTE: it would be possible to use CMP version for both nodes. */
-static void do_hue_sat_fac(
- bNode *UNUSED(node), float *out, float hue, float sat, float val, const float in[4], float fac)
-{
- if (fac != 0.0f && (hue != 0.5f || sat != 1.0f || val != 1.0f)) {
- float col[3], hsv[3], mfac = 1.0f - fac;
-
- rgb_to_hsv(in[0], in[1], in[2], hsv, hsv + 1, hsv + 2);
- hsv[0] = fmodf(hsv[0] + hue + 0.5f, 1.0f);
- hsv[1] = clamp_f(hsv[1] * sat, 0.0f, 1.0f);
- hsv[2] *= val;
- hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col + 1, col + 2);
-
- out[0] = mfac * in[0] + fac * col[0];
- out[1] = mfac * in[1] + fac * col[1];
- out[2] = mfac * in[2] + fac * col[2];
- }
- else {
- copy_v4_v4(out, in);
- }
-}
-
-static void node_shader_exec_hue_sat(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float hue, sat, val, fac;
- float col[4];
- nodestack_get_vec(&hue, SOCK_FLOAT, in[0]);
- nodestack_get_vec(&sat, SOCK_FLOAT, in[1]);
- nodestack_get_vec(&val, SOCK_FLOAT, in[2]);
- nodestack_get_vec(&fac, SOCK_FLOAT, in[3]);
- nodestack_get_vec(col, SOCK_RGBA, in[4]);
- do_hue_sat_fac(node, out[0]->vec, hue, sat, val, col, fac);
-}
-
-static int gpu_shader_hue_sat(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "hue_sat", in, out);
-}
-
-void register_node_type_sh_hue_sat(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_hue_sat_in, sh_node_hue_sat_out);
- node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_hue_sat);
- node_type_gpu(&ntype, gpu_shader_hue_sat);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc
new file mode 100644
index 00000000000..94b9a61c602
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_hueSatVal_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Hue")).default_value(0.5f).min(0.0f).max(1.0f);
+ b.add_input<decl::Float>(N_("Saturation")).default_value(1.0f).min(0.0f).max(2.0f);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f).min(0.0f).max(2.0f);
+ 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_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static int gpu_shader_hue_sat(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "hue_sat", in, out);
+}
+
+} // namespace blender::nodes::node_shader_hueSatVal_cc
+
+void register_node_type_sh_hue_sat()
+{
+ namespace file_ns = blender::nodes::node_shader_hueSatVal_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
+ node_type_gpu(&ntype, file_ns::gpu_shader_hue_sat);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_ies_light.c b/source/blender/nodes/shader/nodes/node_shader_ies_light.c
deleted file mode 100644
index 9cc5fd46181..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_ies_light.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2018 Blender Foundation.
- * All rights reserved.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** IES Light ******************** */
-
-static bNodeSocketTemplate sh_node_tex_ies_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000000.0f, PROP_NONE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_tex_ies_out[] = {
- {SOCK_FLOAT, N_("Fac")},
- {-1, ""},
-};
-
-static void node_shader_init_tex_ies(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeShaderTexIES *tex = MEM_callocN(sizeof(NodeShaderTexIES), "NodeShaderIESLight");
- node->storage = tex;
-}
-
-/* node type definition */
-void register_node_type_sh_tex_ies(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_TEX_IES, "IES Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_ies_in, sh_node_tex_ies_out);
- node_type_init(&ntype, node_shader_init_tex_ies);
- node_type_storage(
- &ntype, "NodeShaderTexIES", node_free_standard_storage, node_copy_standard_storage);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_ies_light.cc b/source/blender/nodes/shader/nodes/node_shader_ies_light.cc
new file mode 100644
index 00000000000..82f0a3045c9
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_ies_light.cc
@@ -0,0 +1,74 @@
+/*
+ * 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) 2018 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_ies_light_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector")).hide_value();
+ b.add_input<decl::Float>(N_("Strength")).default_value(1.0f).min(0.0f).max(1000000.0f);
+ b.add_output<decl::Float>(N_("Fac"));
+}
+
+static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, true);
+
+ if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) {
+ uiItemR(row, ptr, "ies", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+ else {
+ uiItemR(row, ptr, "filepath", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+}
+
+static void node_shader_init_tex_ies(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeShaderTexIES *tex = MEM_cnew<NodeShaderTexIES>("NodeShaderIESLight");
+ node->storage = tex;
+}
+
+} // namespace blender::nodes::node_shader_ies_light_cc
+
+/* node type definition */
+void register_node_type_sh_tex_ies()
+{
+ namespace file_ns = blender::nodes::node_shader_ies_light_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_TEX_IES, "IES Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_ies;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_ies);
+ node_type_storage(
+ &ntype, "NodeShaderTexIES", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.c b/source/blender/nodes/shader/nodes/node_shader_invert.c
deleted file mode 100644
index 0d6709a1968..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_invert.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** INVERT ******************** */
-static bNodeSocketTemplate sh_node_invert_in[] = {
- {SOCK_FLOAT, N_("Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""}};
-
-static bNodeSocketTemplate sh_node_invert_out[] = {{SOCK_RGBA, N_("Color")}, {-1, ""}};
-
-static void node_shader_exec_invert(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float col[3], icol[3], fac;
-
- nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
- nodestack_get_vec(col, SOCK_VECTOR, in[1]);
-
- icol[0] = 1.0f - col[0];
- icol[1] = 1.0f - col[1];
- icol[2] = 1.0f - col[2];
-
- /* if fac, blend result against original input */
- if (fac < 1.0f) {
- interp_v3_v3v3(out[0]->vec, col, icol, fac);
- }
- else {
- copy_v3_v3(out[0]->vec, icol);
- }
-}
-
-static int gpu_shader_invert(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "invert", in, out);
-}
-
-void register_node_type_sh_invert(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_invert_in, sh_node_invert_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_invert);
- node_type_gpu(&ntype, gpu_shader_invert);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.cc b/source/blender/nodes/shader/nodes/node_shader_invert.cc
new file mode 100644
index 00000000000..3b5f4cb1d38
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_invert.cc
@@ -0,0 +1,57 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_invert_cc {
+
+static void node_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_("Color")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static int gpu_shader_invert(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "invert", in, out);
+}
+
+} // namespace blender::nodes::node_shader_invert_cc
+
+void register_node_type_sh_invert()
+{
+ namespace file_ns = blender::nodes::node_shader_invert_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_invert);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc
index c26b40b081c..b4210ce154c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
+++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc
@@ -17,21 +17,17 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Layer Weight ******************** */
+namespace blender::nodes::node_shader_layer_weight_cc {
-static bNodeSocketTemplate sh_node_layer_weight_in[] = {
- {SOCK_FLOAT, N_("Blend"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_layer_weight_out[] = {
- {SOCK_FLOAT, N_("Fresnel"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Facing"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Blend")).default_value(0.5f).min(0.0f).max(1.0f);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Float>(N_("Fresnel"));
+ b.add_output<decl::Float>(N_("Facing"));
+}
static int node_shader_gpu_layer_weight(GPUMaterial *mat,
bNode *node,
@@ -50,26 +46,18 @@ static int node_shader_gpu_layer_weight(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_layer_weight", in, out, GPU_builtin(GPU_VIEW_POSITION));
}
-static void node_shader_exec_layer_weight(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **UNUSED(in),
- bNodeStack **UNUSED(out))
-{
-}
+} // namespace blender::nodes::node_shader_layer_weight_cc
/* node type definition */
-void register_node_type_sh_layer_weight(void)
+void register_node_type_sh_layer_weight()
{
+ namespace file_ns = blender::nodes::node_shader_layer_weight_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_layer_weight_in, sh_node_layer_weight_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_layer_weight);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_layer_weight);
+ sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_layer_weight);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_falloff.c b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc
index 22172221f77..50eea2b3643 100644
--- a/source/blender/nodes/shader/nodes/node_shader_light_falloff.c
+++ b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc
@@ -17,24 +17,18 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** INPUT ********************* */
+namespace blender::nodes::node_shader_light_falloff_cc {
-static bNodeSocketTemplate sh_node_light_falloff_in[] = {
- {SOCK_FLOAT, N_("Strength"), 100.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000000.0f},
- {SOCK_FLOAT, N_("Smooth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {-1, ""},
-};
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_light_falloff_out[] = {
- {SOCK_FLOAT, N_("Quadratic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Linear"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Constant"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Strength")).default_value(100.0f).min(0.0f).max(1000000.0f);
+ b.add_input<decl::Float>(N_("Smooth")).default_value(0.0f).min(0.0f).max(1000.0f);
+ b.add_output<decl::Float>(N_("Quadratic"));
+ b.add_output<decl::Float>(N_("Linear"));
+ b.add_output<decl::Float>(N_("Constant"));
+}
static int node_shader_gpu_light_falloff(GPUMaterial *mat,
bNode *node,
@@ -45,17 +39,19 @@ static int node_shader_gpu_light_falloff(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_light_falloff", in, out);
}
+} // namespace blender::nodes::node_shader_light_falloff_cc
+
/* node type definition */
-void register_node_type_sh_light_falloff(void)
+void register_node_type_sh_light_falloff()
{
+ namespace file_ns = blender::nodes::node_shader_light_falloff_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_LIGHT_FALLOFF, "Light Falloff", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_light_falloff_in, sh_node_light_falloff_out);
+ sh_node_type_base(&ntype, SH_NODE_LIGHT_FALLOFF, "Light Falloff", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_light_falloff);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_light_falloff);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.c b/source/blender/nodes/shader/nodes/node_shader_light_path.c
deleted file mode 100644
index 45ad2133ee8..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_light_path.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_light_path_out[] = {
- {SOCK_FLOAT, N_("Is Camera Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Shadow Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Diffuse Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Glossy Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Singular Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Reflection Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Is Transmission Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Ray Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Ray Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Diffuse Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Glossy Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Transparent Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Transmission Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
-
-static int node_shader_gpu_light_path(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "node_light_path", in, out);
-}
-
-/* node type definition */
-void register_node_type_sh_light_path(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_light_path_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_light_path);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.cc b/source/blender/nodes/shader/nodes/node_shader_light_path.cc
new file mode 100644
index 00000000000..6fbd5751886
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_light_path.cc
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_light_path_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Is Camera Ray"));
+ b.add_output<decl::Float>(N_("Is Shadow Ray"));
+ b.add_output<decl::Float>(N_("Is Diffuse Ray"));
+ b.add_output<decl::Float>(N_("Is Glossy Ray"));
+ b.add_output<decl::Float>(N_("Is Singular Ray"));
+ b.add_output<decl::Float>(N_("Is Reflection Ray"));
+ b.add_output<decl::Float>(N_("Is Transmission Ray"));
+ b.add_output<decl::Float>(N_("Ray Length"));
+ b.add_output<decl::Float>(N_("Ray Depth"));
+ b.add_output<decl::Float>(N_("Diffuse Depth"));
+ b.add_output<decl::Float>(N_("Glossy Depth"));
+ b.add_output<decl::Float>(N_("Transparent Depth"));
+ b.add_output<decl::Float>(N_("Transmission Depth"));
+}
+
+static int node_shader_gpu_light_path(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "node_light_path", in, out);
+}
+
+} // namespace blender::nodes::node_shader_light_path_cc
+
+/* node type definition */
+void register_node_type_sh_light_path()
+{
+ namespace file_ns = blender::nodes::node_shader_light_path_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_light_path);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
index 615ae276eb4..bc7ca661a77 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -23,13 +23,18 @@
#include <algorithm>
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_math_base_safe.h"
-NODE_STORAGE_FUNCS(NodeMapRange)
+#include "NOD_socket_search_link.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_map_range_cc {
+
+NODE_STORAGE_FUNCS(NodeMapRange)
static void sh_node_map_range_declare(NodeDeclarationBuilder &b)
{
@@ -48,9 +53,18 @@ static void sh_node_map_range_declare(NodeDeclarationBuilder &b)
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_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ if (!ELEM(RNA_enum_get(ptr, "interpolation_type"),
+ NODE_MAP_RANGE_SMOOTHSTEP,
+ NODE_MAP_RANGE_SMOOTHERSTEP)) {
+ uiItemR(layout, ptr, "clamp", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
static void node_shader_update_map_range(bNodeTree *ntree, bNode *node)
{
@@ -80,7 +94,7 @@ static void node_shader_update_map_range(bNodeTree *ntree, bNode *node)
static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeMapRange *data = (NodeMapRange *)MEM_callocN(sizeof(NodeMapRange), __func__);
+ NodeMapRange *data = MEM_cnew<NodeMapRange>(__func__);
data->clamp = 1;
data->data_type = CD_PROP_FLOAT;
data->interpolation_type = NODE_MAP_RANGE_LINEAR;
@@ -89,6 +103,66 @@ static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ CustomDataType data_type;
+ int interpolation_type = NODE_MAP_RANGE_LINEAR;
+
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("ShaderNodeMapRange");
+ node_storage(node).data_type = data_type;
+ node_storage(node).interpolation_type = interpolation_type;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ return CD_PROP_FLOAT;
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ return CD_PROP_FLOAT3;
+ default:
+ return {};
+ }
+}
+
+static void node_map_range_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+
+ if (params.in_out() == SOCK_IN) {
+ if (*type == CD_PROP_FLOAT3) {
+ params.add_item(IFACE_("Vector"), SocketSearchOp{"Vector", *type}, 0);
+ }
+ else {
+ params.add_item(IFACE_("Value"), SocketSearchOp{"Value", *type}, 0);
+ }
+ params.add_item(IFACE_("From Min"), SocketSearchOp{"From Min", *type}, -1);
+ params.add_item(IFACE_("From Max"), SocketSearchOp{"From Max", *type}, -1);
+ params.add_item(IFACE_("To Min"), SocketSearchOp{"To Min", *type}, -2);
+ params.add_item(IFACE_("To Max"), SocketSearchOp{"To Max", *type}, -2);
+ params.add_item(IFACE_("Steps"), SocketSearchOp{"Steps", *type, NODE_MAP_RANGE_STEPPED}, -3);
+ }
+ else {
+ if (*type == CD_PROP_FLOAT3) {
+ params.add_item(IFACE_("Vector"), SocketSearchOp{"Vector", *type});
+ }
+ else {
+ params.add_item(IFACE_("Result"), SocketSearchOp{"Result", *type});
+ }
+ }
+}
+
static const char *gpu_shader_get_name(int mode, bool use_vector)
{
if (use_vector) {
@@ -143,8 +217,6 @@ static int gpu_shader_map_range(GPUMaterial *mat,
return ret;
}
-namespace blender::nodes {
-
static inline float clamp_range(const float value, const float min, const float max)
{
return (min > max) ? std::clamp(value, max, min) : std::clamp(value, min, max);
@@ -200,7 +272,7 @@ class MapRangeVectorFunction : public blender::fn::MultiFunction {
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]);
+ float3 factor = math::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];
}
@@ -243,8 +315,8 @@ class MapRangeSteppedVectorFunction : public blender::fn::MultiFunction {
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]);
+ float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
+ factor = math::safe_divide(math::floor(factor * (steps[i] + 1.0f)), steps[i]);
results[i] = factor * (to_max[i] - to_min[i]) + to_min[i];
}
@@ -283,7 +355,7 @@ class MapRangeSmoothstepVectorFunction : public blender::fn::MultiFunction {
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]);
+ float3 factor = math::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];
@@ -318,7 +390,7 @@ class MapRangeSmootherstepVectorFunction : public blender::fn::MultiFunction {
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]);
+ float3 factor = math::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];
@@ -582,20 +654,23 @@ static void sh_node_map_range_build_multi_function(
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_map_range_cc
void register_node_type_sh_map_range()
{
+ namespace file_ns = blender::nodes::node_shader_map_range_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_map_range_declare;
- node_type_init(&ntype, node_shader_init_map_range);
+ sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_map_range_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_map_range;
+ node_type_init(&ntype, file_ns::node_shader_init_map_range);
node_type_storage(
&ntype, "NodeMapRange", node_free_standard_storage, node_copy_standard_storage);
- node_type_update(&ntype, node_shader_update_map_range);
- node_type_gpu(&ntype, gpu_shader_map_range);
- ntype.build_multi_function = blender::nodes::sh_node_map_range_build_multi_function;
-
+ node_type_update(&ntype, file_ns::node_shader_update_map_range);
+ node_type_gpu(&ntype, file_ns::gpu_shader_map_range);
+ ntype.build_multi_function = file_ns::sh_node_map_range_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::node_map_range_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
deleted file mode 100644
index cabfecdb6ee..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** MAPPING ******************** */
-static bNodeSocketTemplate sh_node_mapping_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE},
- {SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
- {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
- {SOCK_VECTOR, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_mapping_out[] = {
- {SOCK_VECTOR, N_("Vector")},
- {-1, ""},
-};
-
-static int gpu_shader_mapping(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- static const char *names[] = {
- [NODE_MAPPING_TYPE_POINT] = "mapping_point",
- [NODE_MAPPING_TYPE_TEXTURE] = "mapping_texture",
- [NODE_MAPPING_TYPE_VECTOR] = "mapping_vector",
- [NODE_MAPPING_TYPE_NORMAL] = "mapping_normal",
- };
-
- if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
- return GPU_stack_link(mat, node, names[node->custom1], in, out);
- }
-
- return 0;
-}
-
-static void node_shader_update_mapping(bNodeTree *ntree, bNode *node)
-{
- bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location");
- nodeSetSocketAvailability(
- ntree, sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE));
-}
-
-void register_node_type_sh_mapping(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out);
- node_type_gpu(&ntype, gpu_shader_mapping);
- node_type_update(&ntype, node_shader_update_mapping);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.cc b/source/blender/nodes/shader/nodes/node_shader_mapping.cc
new file mode 100644
index 00000000000..19c3a26796e
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.cc
@@ -0,0 +1,110 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_mapping_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(-FLT_MAX)
+ .max(FLT_MAX);
+ b.add_input<decl::Vector>(N_("Location"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(-FLT_MAX)
+ .max(FLT_MAX)
+ .subtype(PROP_TRANSLATION);
+ b.add_input<decl::Vector>(N_("Rotation"))
+ .default_value({0.0f, 0.0f, 0.0f})
+ .min(-FLT_MAX)
+ .max(FLT_MAX)
+ .subtype(PROP_EULER);
+ b.add_input<decl::Vector>(N_("Scale"))
+ .default_value({1.0f, 1.0f, 1.0f})
+ .min(-FLT_MAX)
+ .max(FLT_MAX)
+ .subtype(PROP_XYZ);
+ b.add_output<decl::Vector>(N_("Vector"));
+}
+
+static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "vector_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_MAPPING_TYPE_POINT:
+ return "mapping_point";
+ case NODE_MAPPING_TYPE_TEXTURE:
+ return "mapping_texture";
+ case NODE_MAPPING_TYPE_VECTOR:
+ return "mapping_vector";
+ case NODE_MAPPING_TYPE_NORMAL:
+ return "mapping_normal";
+ }
+ return nullptr;
+}
+
+static int gpu_shader_mapping(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ if (gpu_shader_get_name(node->custom1)) {
+ return GPU_stack_link(mat, node, gpu_shader_get_name(node->custom1), in, out);
+ }
+
+ return 0;
+}
+
+static void node_shader_update_mapping(bNodeTree *ntree, bNode *node)
+{
+ bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location");
+ nodeSetSocketAvailability(
+ ntree, sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE));
+}
+
+} // namespace blender::nodes::node_shader_mapping_cc
+
+void register_node_type_sh_mapping()
+{
+ namespace file_ns = blender::nodes::node_shader_mapping_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_mapping;
+ node_type_gpu(&ntype, file_ns::gpu_shader_mapping);
+ node_type_update(&ntype, file_ns::node_shader_update_mapping);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
index a10124460ff..50585405cbf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -21,13 +21,16 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "NOD_math_functions.hh"
+#include "NOD_socket_search_link.hh"
+
+#include "RNA_enum_types.h"
/* **************** SCALAR MATH ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_shader_math_cc {
static void sh_node_math_declare(NodeDeclarationBuilder &b)
{
@@ -42,9 +45,43 @@ static void sh_node_math_declare(NodeDeclarationBuilder &b)
.min(-10000.0f)
.max(10000.0f);
b.add_output<decl::Float>(N_("Value"));
+}
+
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ NodeMathOperation mode = NODE_MATH_ADD;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("ShaderNodeMath");
+ node.custom1 = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
};
-} // namespace blender::nodes
+static void sh_node_math_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ if (!params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ return;
+ }
+
+ const bool is_geometry_node_tree = params.node_tree().type == NTREE_GEOMETRY;
+ const int weight = ELEM(params.other_socket().type, SOCK_FLOAT, SOCK_BOOLEAN, SOCK_INT) ? 0 : -1;
+
+ for (const EnumPropertyItem *item = rna_enum_node_math_items; item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ const int gn_weight =
+ (is_geometry_node_tree &&
+ ELEM(item->value, NODE_MATH_COMPARE, NODE_MATH_GREATER_THAN, NODE_MATH_LESS_THAN)) ?
+ -1 :
+ weight;
+ params.add_item(
+ IFACE_(item->name), SocketSearchOp{"Value", (NodeMathOperation)item->value}, gn_weight);
+ }
+ }
+}
static const char *gpu_shader_get_name(int mode)
{
@@ -161,16 +198,21 @@ static void sh_node_math_build_multi_function(blender::nodes::NodeMultiFunctionB
}
}
+} // namespace blender::nodes::node_shader_math_cc
+
void register_node_type_sh_math()
{
+ namespace file_ns = blender::nodes::node_shader_math_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_math_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_math_declare;
ntype.labelfunc = node_math_label;
- node_type_gpu(&ntype, gpu_shader_math);
+ node_type_gpu(&ntype, file_ns::gpu_shader_math);
node_type_update(&ntype, node_math_update);
- ntype.build_multi_function = sh_node_math_build_multi_function;
+ ntype.build_multi_function = file_ns::sh_node_math_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::sh_node_math_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
index b89e0527eed..9678e86d289 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
@@ -21,9 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_mix_rgb_cc {
static void sh_node_mix_rgb_declare(NodeDeclarationBuilder &b)
{
@@ -32,34 +32,6 @@ static void sh_node_mix_rgb_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Color>(N_("Color1")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
b.add_input<decl::Color>(N_("Color2")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
b.add_output<decl::Color>(N_("Color"));
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_mix_rgb(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- /* stack order in: fac, col1, col2 */
- /* stack order out: col */
- float col[3];
- float fac;
- float vec[3];
-
- nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
- CLAMP(fac, 0.0f, 1.0f);
-
- nodestack_get_vec(col, SOCK_VECTOR, in[1]);
- nodestack_get_vec(vec, SOCK_VECTOR, in[2]);
-
- ramp_blend(node->custom1, col, fac, vec);
- if (node->custom2 & SHD_MIXRGB_CLAMP) {
- CLAMP3(col, 0.0f, 1.0f);
- }
- copy_v3_v3(out[0]->vec, col);
}
static const char *gpu_shader_get_name(int mode)
@@ -183,16 +155,19 @@ static void sh_node_mix_rgb_build_multi_function(blender::nodes::NodeMultiFuncti
builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type);
}
+} // namespace blender::nodes::node_shader_mix_rgb_cc
+
void register_node_type_sh_mix_rgb()
{
+ namespace file_ns = blender::nodes::node_shader_mix_rgb_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::sh_node_mix_rgb_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::sh_node_mix_rgb_declare;
ntype.labelfunc = node_blend_label;
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_mix_rgb);
- node_type_gpu(&ntype, gpu_shader_mix_rgb);
- ntype.build_multi_function = sh_node_mix_rgb_build_multi_function;
+ node_type_gpu(&ntype, file_ns::gpu_shader_mix_rgb);
+ ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_shader.c b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc
index 33cbf34543c..d9aa906e451 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mix_shader.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc
@@ -17,21 +17,17 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_mix_shader_cc {
-static bNodeSocketTemplate sh_node_mix_shader_in[] = {
- {SOCK_FLOAT, N_("Fac"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_SHADER, N_("Shader")},
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_mix_shader_out[] = {
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_input<decl::Shader>(N_("Shader"));
+ b.add_input<decl::Shader>(N_("Shader"), "Shader_001");
+ b.add_output<decl::Shader>(N_("Shader"));
+}
static int node_shader_gpu_mix_shader(GPUMaterial *mat,
bNode *node,
@@ -42,16 +38,18 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_mix_shader", in, out);
}
+} // namespace blender::nodes::node_shader_mix_shader_cc
+
/* node type definition */
-void register_node_type_sh_mix_shader(void)
+void register_node_type_sh_mix_shader()
{
+ namespace file_ns = blender::nodes::node_shader_mix_shader_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_mix_shader_in, sh_node_mix_shader_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_mix_shader);
+ sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_mix_shader);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.c b/source/blender/nodes/shader/nodes/node_shader_normal.cc
index 83d5abcba67..e677f36e425 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal.cc
@@ -21,37 +21,23 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** NORMAL ******************** */
-static bNodeSocketTemplate sh_node_normal_in[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_DIRECTION},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_normal_cc {
-static bNodeSocketTemplate sh_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, ""},
-};
-
-/* generates normal, does dot product */
-static void node_shader_exec_normal(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
+static void node_declare(NodeDeclarationBuilder &b)
{
- float vec[3];
-
- /* stack order input: normal */
- /* stack order output: normal, value */
-
- nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
-
- /* render normals point inside... the widget points outside */
- out[1]->vec[0] = -dot_v3v3(vec, out[0]->vec);
+ b.add_input<decl::Vector>(N_("Normal"))
+ .default_value({0.0f, 0.0f, 1.0f})
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_DIRECTION);
+ b.add_output<decl::Vector>(N_("Normal"))
+ .default_value({0.0f, 0.0f, 1.0f})
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_DIRECTION);
+ b.add_output<decl::Float>(N_("Dot"));
}
static int gpu_shader_normal(GPUMaterial *mat,
@@ -64,14 +50,17 @@ static int gpu_shader_normal(GPUMaterial *mat,
return GPU_stack_link(mat, node, "normal_new_shading", in, out, vec);
}
-void register_node_type_sh_normal(void)
+} // namespace blender::nodes::node_shader_normal_cc
+
+void register_node_type_sh_normal()
{
+ namespace file_ns = blender::nodes::node_shader_normal_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_normal_in, sh_node_normal_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal);
- node_type_gpu(&ntype, gpu_shader_normal);
+ sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_normal);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc
index 493acb06963..338b4c62a3a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc
@@ -17,34 +17,43 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "BKE_context.h"
-static bNodeSocketTemplate sh_node_normal_map_in[] = {
- {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f},
- {SOCK_RGBA, N_("Color"), 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_normal_map_out[] = {
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_normal_map_cc {
-static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
+static void node_declare(NodeDeclarationBuilder &b)
{
- NodeShaderNormalMap *attr = MEM_callocN(sizeof(NodeShaderNormalMap), "NodeShaderNormalMap");
- node->storage = attr;
+ b.add_input<decl::Float>(N_("Strength")).default_value(1.0f).min(0.0f).max(10.0f);
+ b.add_input<decl::Color>(N_("Color")).default_value({0.5f, 0.5f, 1.0f, 1.0f});
+ b.add_output<decl::Vector>(N_("Normal"));
+}
+
+static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, "", 0);
+
+ if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) {
+ PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
+
+ if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+ PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
+ uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
+ }
+ else {
+ uiItemR(layout, ptr, "uv_map", UI_ITEM_R_SPLIT_EMPTY_NAME, "", 0);
+ }
+ }
}
-static void node_shader_exec_normal_map(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **UNUSED(in),
- bNodeStack **UNUSED(out))
+static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
{
+ NodeShaderNormalMap *attr = MEM_cnew<NodeShaderNormalMap>("NodeShaderNormalMap");
+ node->storage = attr;
}
static int gpu_shader_normal_map(GPUMaterial *mat,
@@ -53,15 +62,16 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderNormalMap *nm = node->storage;
+ NodeShaderNormalMap *nm = static_cast<NodeShaderNormalMap *>(node->storage);
GPUNodeLink *strength;
if (in[0].link) {
strength = in[0].link;
}
else if (node->original) {
- bNodeSocket *socket = BLI_findlink(&node->original->inputs, 0);
- bNodeSocketValueFloat *socket_data = socket->default_value;
+ bNodeSocket *socket = static_cast<bNodeSocket *>(BLI_findlink(&node->original->inputs, 0));
+ bNodeSocketValueFloat *socket_data = static_cast<bNodeSocketValueFloat *>(
+ socket->default_value);
strength = GPU_uniform(&socket_data->value);
}
else {
@@ -73,8 +83,8 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
newnormal = in[1].link;
}
else if (node->original) {
- bNodeSocket *socket = BLI_findlink(&node->original->inputs, 1);
- bNodeSocketValueRGBA *socket_data = socket->default_value;
+ bNodeSocket *socket = static_cast<bNodeSocket *>(BLI_findlink(&node->original->inputs, 1));
+ bNodeSocketValueRGBA *socket_data = static_cast<bNodeSocketValueRGBA *>(socket->default_value);
newnormal = GPU_uniform(socket_data->value);
}
else {
@@ -114,19 +124,23 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_normal_map_cc
+
/* node type definition */
-void register_node_type_sh_normal_map(void)
+void register_node_type_sh_normal_map()
{
+ namespace file_ns = blender::nodes::node_shader_normal_map_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_normal_map_in, sh_node_normal_map_out);
+ sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_normal_map;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_normal_map);
+ node_type_init(&ntype, file_ns::node_shader_init_normal_map);
node_type_storage(
&ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, gpu_shader_normal_map);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal_map);
+ node_type_gpu(&ntype, file_ns::gpu_shader_normal_map);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.cc
index 47040954c9e..7bc7039d11e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_object_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_object_info.cc
@@ -17,18 +17,18 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_object_info_cc {
-static bNodeSocketTemplate sh_node_object_info_out[] = {
- {SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Object Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Material Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Random"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Location"));
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Object Index"));
+ b.add_output<decl::Float>(N_("Material Index"));
+ b.add_output<decl::Float>(N_("Random"));
+}
static int node_shader_gpu_object_info(GPUMaterial *mat,
bNode *node,
@@ -49,13 +49,17 @@ static int node_shader_gpu_object_info(GPUMaterial *mat,
GPU_constant(&index));
}
-void register_node_type_sh_object_info(void)
+} // namespace blender::nodes::node_shader_object_info_cc
+
+void register_node_type_sh_object_info()
{
+ namespace file_ns = blender::nodes::node_shader_object_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_object_info_out);
- node_type_gpu(&ntype, node_shader_gpu_object_info);
+ sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_object_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.c b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc
index 32765b459ca..6ffd763b0d1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_aov.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc
@@ -17,21 +17,29 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_hash.h"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_output_aov_in[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_output_aov_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Value")).default_value(0.0f).min(0.0f).max(1.0f);
+}
+
+static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "name", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
static void node_shader_init_output_aov(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderOutputAOV *aov = MEM_callocN(sizeof(NodeShaderOutputAOV), "NodeShaderOutputAOV");
+ NodeShaderOutputAOV *aov = MEM_cnew<NodeShaderOutputAOV>("NodeShaderOutputAOV");
node->storage = aov;
}
@@ -52,17 +60,22 @@ static int node_shader_gpu_output_aov(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_output_aov_cc
+
/* node type definition */
-void register_node_type_sh_output_aov(void)
+void register_node_type_sh_output_aov()
{
+ namespace file_ns = blender::nodes::node_shader_output_aov_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_AOV, "AOV Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_aov_in, NULL);
- node_type_init(&ntype, node_shader_init_output_aov);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_AOV, "AOV Output", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_output_aov;
+ node_type_init(&ntype, file_ns::node_shader_init_output_aov);
node_type_storage(
&ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_output_aov);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_output_aov);
ntype.no_muting = true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_light.c b/source/blender/nodes/shader/nodes/node_shader_output_light.cc
index 6c4837f3c6f..0c8288f801b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_light.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_light.cc
@@ -17,25 +17,26 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_output_light_cc {
-static bNodeSocketTemplate sh_node_output_light_in[] = {
- {SOCK_SHADER, N_("Surface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Shader>(N_("Surface"));
+}
+
+} // namespace blender::nodes::node_shader_output_light_cc
/* node type definition */
-void register_node_type_sh_output_light(void)
+void register_node_type_sh_output_light()
{
- static bNodeType ntype;
+ namespace file_ns = blender::nodes::node_shader_output_light_cc;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_light_in, NULL);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
+ static bNodeType ntype;
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::node_declare;
ntype.no_muting = true;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c
deleted file mode 100644
index 07e253383e2..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_output_linestyle_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 0.0f, 1.0f, 1.0f},
- {SOCK_FLOAT, N_("Color Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Alpha Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
-
-/* node type definition */
-void register_node_type_sh_output_linestyle(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_linestyle_in, NULL);
- node_type_init(&ntype, NULL);
-
- ntype.no_muting = true;
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc
new file mode 100644
index 00000000000..9b6c3292e75
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc
@@ -0,0 +1,72 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_output_linestyle_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 0.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Color Fac"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Alpha"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Alpha Fac"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+}
+
+static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row, *col;
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRow(col, true);
+ uiItemR(row, ptr, "blend_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
+
+} // namespace blender::nodes::node_shader_output_linestyle_cc
+
+/* node type definition */
+void register_node_type_sh_output_linestyle()
+{
+ namespace file_ns = blender::nodes::node_shader_output_linestyle_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_buts_output_linestyle;
+ ntype.no_muting = true;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.cc
index 41932cca6a3..5fc95b92e3f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc
@@ -17,27 +17,18 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BKE_scene.h"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_output_material_cc {
-static bNodeSocketTemplate sh_node_output_material_in[] = {
- {SOCK_SHADER, N_("Surface")},
- {SOCK_SHADER, N_("Volume")},
- {SOCK_VECTOR,
- N_("Displacement"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_HIDE_VALUE},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Shader>(N_("Surface"));
+ b.add_input<decl::Shader>(N_("Volume"));
+ b.add_input<decl::Vector>(N_("Displacement")).hide_value();
+}
static int node_shader_gpu_output_material(GPUMaterial *mat,
bNode *node,
@@ -73,16 +64,18 @@ static int node_shader_gpu_output_material(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_output_material_cc
+
/* node type definition */
-void register_node_type_sh_output_material(void)
+void register_node_type_sh_output_material()
{
+ namespace file_ns = blender::nodes::node_shader_output_material_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_MATERIAL, "Material Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_material_in, NULL);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_output_material);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_MATERIAL, "Material Output", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_output_material);
ntype.no_muting = true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.cc
index 09eca7f712e..501dc088cbe 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_world.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_world.cc
@@ -17,15 +17,15 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_output_world_cc {
-static bNodeSocketTemplate sh_node_output_world_in[] = {
- {SOCK_SHADER, N_("Surface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_SHADER, N_("Volume"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Shader>(N_("Surface"));
+ b.add_input<decl::Shader>(N_("Volume"));
+}
static int node_shader_gpu_output_world(GPUMaterial *mat,
bNode *node,
@@ -41,16 +41,18 @@ static int node_shader_gpu_output_world(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_output_world_cc
+
/* node type definition */
-void register_node_type_sh_output_world(void)
+void register_node_type_sh_output_world()
{
+ namespace file_ns = blender::nodes::node_shader_output_world_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_WORLD, "World Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_world_in, NULL);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_output_world);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_WORLD, "World Output", NODE_CLASS_OUTPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_output_world);
ntype.no_muting = true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.c b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc
index c6eabc3b2cb..d68d0fe0d72 100644
--- a/source/blender/nodes/shader/nodes/node_shader_particle_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc
@@ -17,30 +17,25 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
#include "RE_texture.h"
-static bNodeSocketTemplate outputs[] = {
- {SOCK_FLOAT, "Index"},
- {SOCK_FLOAT, "Random"},
- {SOCK_FLOAT, "Age"},
- {SOCK_FLOAT, "Lifetime"},
- {SOCK_VECTOR, "Location"},
+namespace blender::nodes::node_shader_particle_info_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Index"));
+ b.add_output<decl::Float>(N_("Random"));
+ b.add_output<decl::Float>(N_("Age"));
+ b.add_output<decl::Float>(N_("Lifetime"));
+ b.add_output<decl::Vector>(N_("Location"));
#if 0 /* quaternion sockets not yet supported */
- {SOCK_QUATERNION, "Rotation"},
+ b.add_output<decl::Quaternion>(N_("Rotation"));
#endif
- {SOCK_FLOAT, "Size"},
- {SOCK_VECTOR, "Velocity"},
- {SOCK_VECTOR, "Angular Velocity"},
- {-1, ""},
-};
-static void node_shader_exec_particle_info(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **UNUSED(in),
- bNodeStack **UNUSED(out))
-{
+ b.add_output<decl::Float>(N_("Size"));
+ b.add_output<decl::Vector>(N_("Velocity"));
+ b.add_output<decl::Vector>(N_("Angular Velocity"));
}
static int gpu_shader_particle_info(GPUMaterial *mat,
@@ -61,15 +56,18 @@ static int gpu_shader_particle_info(GPUMaterial *mat,
GPU_builtin(GPU_PARTICLE_ANG_VELOCITY));
}
+} // namespace blender::nodes::node_shader_particle_info_cc
+
/* node type definition */
-void register_node_type_sh_particle_info(void)
+void register_node_type_sh_particle_info()
{
+ namespace file_ns = blender::nodes::node_shader_particle_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, outputs);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_particle_info);
- node_type_gpu(&ntype, gpu_shader_particle_info);
+ sh_node_type_base(&ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_particle_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_point_info.cc b/source/blender/nodes/shader/nodes/node_shader_point_info.cc
new file mode 100644
index 00000000000..adc58ca065a
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_point_info.cc
@@ -0,0 +1,54 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_point_info_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Position"));
+ b.add_output<decl::Float>(N_("Radius"));
+ b.add_output<decl::Float>(N_("Random"));
+}
+
+static int node_shader_gpu_point_info(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "node_point_info", in, out);
+}
+
+} // namespace blender::nodes::node_shader_point_info_cc
+
+/* node type definition */
+void register_node_type_sh_point_info()
+{
+ namespace file_ns = blender::nodes::node_shader_point_info_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_POINT_INFO, "Point Info", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_point_info);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb.c b/source/blender/nodes/shader/nodes/node_shader_rgb.cc
index 0bdef9a2a17..f3b83b72232 100644
--- a/source/blender/nodes/shader/nodes/node_shader_rgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_rgb.cc
@@ -21,13 +21,14 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** RGB ******************** */
-static bNodeSocketTemplate sh_node_rgb_out[] = {
- {SOCK_RGBA, N_("Color"), 0.5f, 0.5f, 0.5f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_rgb_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Color")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
+}
static int gpu_shader_rgb(GPUMaterial *mat,
bNode *node,
@@ -39,13 +40,17 @@ static int gpu_shader_rgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "set_rgba", in, out, link);
}
-void register_node_type_sh_rgb(void)
+} // namespace blender::nodes::node_shader_rgb_cc
+
+void register_node_type_sh_rgb()
{
+ namespace file_ns = blender::nodes::node_shader_rgb_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_RGB, "RGB", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_rgb_out);
- node_type_gpu(&ntype, gpu_shader_rgb);
+ sh_node_type_base(&ntype, SH_NODE_RGB, "RGB", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_rgb);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
index e3808985c0e..13ba056d9ee 100644
--- a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
@@ -23,194 +23,14 @@
#include "IMB_colormanagement.h"
-#include "DNA_texture_types.h"
+#include "node_shader_util.hh"
-#include "BLI_color.hh"
-
-#include "node_shader_util.h"
-
-namespace blender::nodes {
-
-static void sh_node_valtorgb_declare(NodeDeclarationBuilder &b)
-{
- b.is_function_node();
- b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_output<decl::Color>(N_("Color"));
- b.add_output<decl::Float>(N_("Alpha"));
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_valtorgb(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- /* stack order in: fac */
- /* stack order out: col, alpha */
-
- if (node->storage) {
- float fac;
- nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
-
- BKE_colorband_evaluate((ColorBand *)node->storage, fac, out[0]->vec);
- out[1]->vec[0] = out[0]->vec[3];
- }
-}
-
-static void node_shader_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->storage = BKE_colorband_add(true);
-}
-
-static int gpu_shader_valtorgb(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- struct ColorBand *coba = (ColorBand *)node->storage;
- float *array, layer;
- int size;
-
- /* Common / easy case optimization. */
- if ((coba->tot <= 2) && (coba->color_mode == COLBAND_BLEND_RGB)) {
- float mul_bias[2];
- switch (coba->ipotype) {
- case COLBAND_INTERP_LINEAR:
- mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos);
- mul_bias[1] = -mul_bias[0] * coba->data[0].pos;
- return GPU_stack_link(mat,
- node,
- "valtorgb_opti_linear",
- in,
- out,
- GPU_uniform(mul_bias),
- GPU_uniform(&coba->data[0].r),
- GPU_uniform(&coba->data[1].r));
- case COLBAND_INTERP_CONSTANT:
- mul_bias[1] = max_ff(coba->data[0].pos, coba->data[1].pos);
- return GPU_stack_link(mat,
- node,
- "valtorgb_opti_constant",
- in,
- out,
- GPU_uniform(&mul_bias[1]),
- GPU_uniform(&coba->data[0].r),
- GPU_uniform(&coba->data[1].r));
- case COLBAND_INTERP_EASE:
- mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos);
- mul_bias[1] = -mul_bias[0] * coba->data[0].pos;
- return GPU_stack_link(mat,
- node,
- "valtorgb_opti_ease",
- in,
- out,
- GPU_uniform(mul_bias),
- GPU_uniform(&coba->data[0].r),
- GPU_uniform(&coba->data[1].r));
- default:
- break;
- }
- }
-
- BKE_colorband_evaluate_table_rgba(coba, &array, &size);
- GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
-
- if (coba->ipotype == COLBAND_INTERP_CONSTANT) {
- return GPU_stack_link(mat, node, "valtorgb_nearest", in, out, tex, GPU_constant(&layer));
- }
-
- return GPU_stack_link(mat, node, "valtorgb", in, out, tex, GPU_constant(&layer));
-}
-
-class ColorBandFunction : public blender::fn::MultiFunction {
- private:
- const ColorBand &color_band_;
-
- public:
- ColorBandFunction(const ColorBand &color_band) : color_band_(color_band)
- {
- static blender::fn::MFSignature signature = create_signature();
- this->set_signature(&signature);
- }
-
- static blender::fn::MFSignature create_signature()
- {
- blender::fn::MFSignatureBuilder signature{"Color Band"};
- signature.single_input<float>("Value");
- signature.single_output<blender::ColorGeometry4f>("Color");
- signature.single_output<float>("Alpha");
- return signature.build();
- }
-
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
- {
- const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
- blender::MutableSpan<blender::ColorGeometry4f> colors =
- params.uninitialized_single_output<blender::ColorGeometry4f>(1, "Color");
- blender::MutableSpan<float> alphas = params.uninitialized_single_output<float>(2, "Alpha");
-
- for (int64_t i : mask) {
- blender::ColorGeometry4f color;
- BKE_colorband_evaluate(&color_band_, values[i], color);
- colors[i] = color;
- alphas[i] = color.a;
- }
- }
-};
-
-static void sh_node_valtorgb_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
-{
- bNode &bnode = builder.node();
- const ColorBand *color_band = (const ColorBand *)bnode.storage;
- builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
-}
-
-void register_node_type_sh_valtorgb()
-{
- static bNodeType ntype;
-
- sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_valtorgb_declare;
- node_type_init(&ntype, node_shader_init_valtorgb);
- node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_valtorgb);
- node_type_gpu(&ntype, gpu_shader_valtorgb);
- ntype.build_multi_function = sh_node_valtorgb_build_multi_function;
-
- nodeRegisterType(&ntype);
-}
-
-namespace blender::nodes {
+namespace blender::nodes::node_shader_rgb_to_bw_cc {
static void sh_node_rgbtobw_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Color")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
b.add_output<decl::Float>(N_("Val"));
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_rgbtobw(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- /* Stack order out: BW. */
- /* Stack order in: COL. */
- float col[3];
- nodestack_get_vec(col, SOCK_VECTOR, in[0]);
-
- out[0]->vec[0] = IMB_colormanagement_get_luminance(col);
}
static int gpu_shader_rgbtobw(GPUMaterial *mat,
@@ -222,14 +42,17 @@ static int gpu_shader_rgbtobw(GPUMaterial *mat,
return GPU_stack_link(mat, node, "rgbtobw", in, out);
}
+} // namespace blender::nodes::node_shader_rgb_to_bw_cc
+
void register_node_type_sh_rgbtobw()
{
+ namespace file_ns = blender::nodes::node_shader_rgb_to_bw_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_rgbtobw_declare;
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_rgbtobw);
- node_type_gpu(&ntype, gpu_shader_rgbtobw);
+ sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_rgbtobw_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_rgbtobw);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_script.c b/source/blender/nodes/shader/nodes/node_shader_script.c
deleted file mode 100644
index 42ab272de0e..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_script.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** Script ******************** */
-
-static void init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeShaderScript *nss = MEM_callocN(sizeof(NodeShaderScript), "shader script node");
- node->storage = nss;
-}
-
-static void node_free_script(bNode *node)
-{
- NodeShaderScript *nss = node->storage;
-
- if (nss) {
- if (nss->bytecode) {
- MEM_freeN(nss->bytecode);
- }
-
- MEM_freeN(nss);
- }
-}
-
-static void node_copy_script(bNodeTree *UNUSED(dest_ntree),
- bNode *dest_node,
- const bNode *src_node)
-{
- NodeShaderScript *src_nss = src_node->storage;
- NodeShaderScript *dest_nss = MEM_dupallocN(src_nss);
-
- if (src_nss->bytecode) {
- dest_nss->bytecode = MEM_dupallocN(src_nss->bytecode);
- }
-
- dest_node->storage = dest_nss;
-}
-
-void register_node_type_sh_script(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_SCRIPT, "Script", NODE_CLASS_SCRIPT, 0);
- node_type_init(&ntype, init);
- node_type_storage(&ntype, "NodeShaderScript", node_free_script, node_copy_script);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_script.cc b/source/blender/nodes/shader/nodes/node_shader_script.cc
new file mode 100644
index 00000000000..e6af90fa588
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_script.cc
@@ -0,0 +1,112 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_script_cc {
+
+static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+
+ row = uiLayoutRow(layout, true);
+
+ if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL) {
+ uiItemR(row, ptr, "script", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+ else {
+ uiItemR(row, ptr, "filepath", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+
+ uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update");
+}
+
+static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiItemS(layout);
+
+ node_shader_buts_script(layout, C, ptr);
+
+#if 0 /* not implemented yet */
+ if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL) {
+ uiItemR(layout, ptr, "use_auto_update", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+#endif
+}
+
+static void init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeShaderScript *nss = MEM_cnew<NodeShaderScript>("shader script node");
+ node->storage = nss;
+}
+
+static void node_free_script(bNode *node)
+{
+ NodeShaderScript *nss = static_cast<NodeShaderScript *>(node->storage);
+
+ if (nss) {
+ if (nss->bytecode) {
+ MEM_freeN(nss->bytecode);
+ }
+
+ MEM_freeN(nss);
+ }
+}
+
+static void node_copy_script(bNodeTree *UNUSED(dest_ntree),
+ bNode *dest_node,
+ const bNode *src_node)
+{
+ NodeShaderScript *src_nss = static_cast<NodeShaderScript *>(src_node->storage);
+ NodeShaderScript *dest_nss = static_cast<NodeShaderScript *>(MEM_dupallocN(src_nss));
+
+ if (src_nss->bytecode) {
+ dest_nss->bytecode = static_cast<char *>(MEM_dupallocN(src_nss->bytecode));
+ }
+
+ dest_node->storage = dest_nss;
+}
+
+} // namespace blender::nodes::node_shader_script_cc
+
+void register_node_type_sh_script()
+{
+ namespace file_ns = blender::nodes::node_shader_script_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_SCRIPT, "Script", NODE_CLASS_SCRIPT);
+ ntype.draw_buttons = file_ns::node_shader_buts_script;
+ ntype.draw_buttons_ex = file_ns::node_shader_buts_script_ex;
+ node_type_init(&ntype, file_ns::init);
+ node_type_storage(
+ &ntype, "NodeShaderScript", file_ns::node_free_script, file_ns::node_copy_script);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c
deleted file mode 100644
index dfecb830b35..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c
+++ /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.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** SEPARATE HSV ******************** */
-static bNodeSocketTemplate sh_node_sephsv_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f},
- {-1, ""},
-};
-static bNodeSocketTemplate sh_node_sephsv_out[] = {
- {SOCK_FLOAT, N_("H")},
- {SOCK_FLOAT, N_("S")},
- {SOCK_FLOAT, N_("V")},
- {-1, ""},
-};
-
-static void node_shader_exec_sephsv(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float col[3];
- nodestack_get_vec(col, SOCK_VECTOR, in[0]);
-
- rgb_to_hsv(col[0], col[1], col[2], &out[0]->vec[0], &out[1]->vec[0], &out[2]->vec[0]);
-}
-
-static int gpu_shader_sephsv(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "separate_hsv", in, out);
-}
-
-void register_node_type_sh_sephsv(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_sephsv_in, sh_node_sephsv_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_sephsv);
- node_type_gpu(&ntype, gpu_shader_sephsv);
-
- nodeRegisterType(&ntype);
-}
-
-/* **************** COMBINE HSV ******************** */
-static bNodeSocketTemplate sh_node_combhsv_in[] = {
- {SOCK_FLOAT, N_("H"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, N_("S"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
- {SOCK_FLOAT, N_("V"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
- {-1, ""},
-};
-static bNodeSocketTemplate sh_node_combhsv_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
-
-static void node_shader_exec_combhsv(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float h, s, v;
- nodestack_get_vec(&h, SOCK_FLOAT, in[0]);
- nodestack_get_vec(&s, SOCK_FLOAT, in[1]);
- nodestack_get_vec(&v, SOCK_FLOAT, in[2]);
-
- hsv_to_rgb(h, s, v, &out[0]->vec[0], &out[0]->vec[1], &out[0]->vec[2]);
-}
-
-static int gpu_shader_combhsv(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "combine_hsv", in, out);
-}
-
-void register_node_type_sh_combhsv(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_combhsv_in, sh_node_combhsv_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_combhsv);
- node_type_gpu(&ntype, gpu_shader_combhsv);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
new file mode 100644
index 00000000000..700e4ce3667
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.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.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_sepcomb_hsv_cc {
+
+/* **************** SEPARATE HSV ******************** */
+
+static void node_declare_sephsv(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0});
+ b.add_output<decl::Float>(N_("H"));
+ b.add_output<decl::Float>(N_("S"));
+ b.add_output<decl::Float>(N_("V"));
+}
+
+static int gpu_shader_sephsv(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "separate_hsv", in, out);
+}
+
+} // namespace blender::nodes::node_shader_sepcomb_hsv_cc
+
+void register_node_type_sh_sephsv()
+{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_hsv_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare_sephsv;
+ node_type_gpu(&ntype, file_ns::gpu_shader_sephsv);
+
+ nodeRegisterType(&ntype);
+}
+
+namespace blender::nodes::node_shader_sepcomb_hsv_cc {
+
+/* **************** COMBINE HSV ******************** */
+
+static void node_declare_combhsv(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("H")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_UNSIGNED);
+ b.add_input<decl::Float>(N_("S")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_UNSIGNED);
+ b.add_input<decl::Float>(N_("V")).default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_UNSIGNED);
+ b.add_output<decl::Color>(N_("Color"));
+}
+
+static int gpu_shader_combhsv(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "combine_hsv", in, out);
+}
+
+} // namespace blender::nodes::node_shader_sepcomb_hsv_cc
+
+void register_node_type_sh_combhsv()
+{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_hsv_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare_combhsv;
+ node_type_gpu(&ntype, file_ns::gpu_shader_combhsv);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
index 4984a530d8b..d4be0bd14dc 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
@@ -21,9 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_rgb_cc {
static void sh_node_seprgb_declare(NodeDeclarationBuilder &b)
{
@@ -32,23 +32,6 @@ static void sh_node_seprgb_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("R"));
b.add_output<decl::Float>(N_("G"));
b.add_output<decl::Float>(N_("B"));
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_seprgb(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float col[3];
- nodestack_get_vec(col, SOCK_VECTOR, in[0]);
-
- out[0]->vec[0] = col[0];
- out[1]->vec[0] = col[1];
- out[2]->vec[0] = col[2];
}
static int gpu_shader_seprgb(GPUMaterial *mat,
@@ -103,20 +86,23 @@ static void sh_node_seprgb_build_multi_function(blender::nodes::NodeMultiFunctio
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_shader_sepcomb_rgb_cc
+
void register_node_type_sh_seprgb()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_rgb_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_seprgb_declare;
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_seprgb);
- node_type_gpu(&ntype, gpu_shader_seprgb);
- ntype.build_multi_function = sh_node_seprgb_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_seprgb_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_seprgb);
+ ntype.build_multi_function = file_ns::sh_node_seprgb_build_multi_function;
nodeRegisterType(&ntype);
}
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_rgb_cc {
static void sh_node_combrgb_declare(NodeDeclarationBuilder &b)
{
@@ -125,25 +111,6 @@ static void sh_node_combrgb_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("G")).min(0.0f).max(1.0f);
b.add_input<decl::Float>(N_("B")).min(0.0f).max(1.0f);
b.add_output<decl::Color>(N_("Image"));
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_combrgb(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float r, g, b;
- nodestack_get_vec(&r, SOCK_FLOAT, in[0]);
- nodestack_get_vec(&g, SOCK_FLOAT, in[1]);
- nodestack_get_vec(&b, SOCK_FLOAT, in[2]);
-
- out[0]->vec[0] = r;
- out[0]->vec[1] = g;
- out[0]->vec[2] = b;
}
static int gpu_shader_combrgb(GPUMaterial *mat,
@@ -163,15 +130,18 @@ static void sh_node_combrgb_build_multi_function(blender::nodes::NodeMultiFuncti
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_shader_sepcomb_rgb_cc
+
void register_node_type_sh_combrgb()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_rgb_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_combrgb_declare;
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_combrgb);
- node_type_gpu(&ntype, gpu_shader_combrgb);
- ntype.build_multi_function = sh_node_combrgb_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_combrgb_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_combrgb);
+ ntype.build_multi_function = file_ns::sh_node_combrgb_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
index a414630829e..f8064eb192a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
@@ -21,9 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_xyz_cc {
static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b)
{
@@ -32,9 +32,7 @@ static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("X"));
b.add_output<decl::Float>(N_("Y"));
b.add_output<decl::Float>(N_("Z"));
-};
-
-} // namespace blender::nodes
+}
static int gpu_shader_sepxyz(GPUMaterial *mat,
bNode *node,
@@ -88,19 +86,23 @@ static void sh_node_sepxyz_build_multi_function(blender::nodes::NodeMultiFunctio
builder.set_matching_fn(separate_fn);
}
+} // namespace blender::nodes::node_shader_sepcomb_xyz_cc
+
void register_node_type_sh_sepxyz()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_sepxyz_declare;
- node_type_gpu(&ntype, gpu_shader_sepxyz);
- ntype.build_multi_function = sh_node_sepxyz_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_sepxyz_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_sepxyz);
+ ntype.build_multi_function = file_ns::sh_node_sepxyz_build_multi_function;
nodeRegisterType(&ntype);
}
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_xyz_cc {
static void sh_node_combxyz_declare(NodeDeclarationBuilder &b)
{
@@ -109,9 +111,7 @@ static void sh_node_combxyz_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Y")).min(-10000.0f).max(10000.0f);
b.add_input<decl::Float>(N_("Z")).min(-10000.0f).max(10000.0f);
b.add_output<decl::Vector>(N_("Vector"));
-};
-
-} // namespace blender::nodes
+}
static int gpu_shader_combxyz(GPUMaterial *mat,
bNode *node,
@@ -129,14 +129,18 @@ static void sh_node_combxyz_build_multi_function(blender::nodes::NodeMultiFuncti
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_shader_sepcomb_xyz_cc
+
void register_node_type_sh_combxyz()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_combxyz_declare;
- node_type_gpu(&ntype, gpu_shader_combxyz);
- ntype.build_multi_function = sh_node_combxyz_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_combxyz_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_combxyz);
+ ntype.build_multi_function = file_ns::sh_node_combxyz_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc
index 25c30aa4081..153b1abfbca 100644
--- a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc
@@ -17,20 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_shader_to_rgb_cc {
-static bNodeSocketTemplate sh_node_shadertorgb_in[] = {
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_shadertorgb_out[] = {
- {SOCK_RGBA, N_("Color")},
- {SOCK_FLOAT, N_("Alpha")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Shader>(N_("Shader"));
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Alpha"));
+}
static int node_shader_gpu_shadertorgb(GPUMaterial *mat,
bNode *node,
@@ -45,16 +41,18 @@ static int node_shader_gpu_shadertorgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_shader_to_rgba", in, out);
}
+} // namespace blender::nodes::node_shader_shader_to_rgb_cc
+
/* node type definition */
-void register_node_type_sh_shadertorgb(void)
+void register_node_type_sh_shadertorgb()
{
+ namespace file_ns = blender::nodes::node_shader_shader_to_rgb_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_shadertorgb_in, sh_node_shadertorgb_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_shadertorgb);
+ sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_shadertorgb);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_squeeze.c b/source/blender/nodes/shader/nodes/node_shader_squeeze.c
deleted file mode 100644
index ca7bdf41df9..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_squeeze.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** VALUE SQUEEZE ******************** */
-static bNodeSocketTemplate sh_node_squeeze_in[] = {
- {SOCK_FLOAT, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Width"), 1.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {SOCK_FLOAT, N_("Center"), 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f, PROP_NONE},
- {-1, ""}};
-
-static bNodeSocketTemplate sh_node_squeeze_out[] = {{SOCK_FLOAT, N_("Value")}, {-1, ""}};
-
-static void node_shader_exec_squeeze(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float vec[3];
-
- nodestack_get_vec(vec, SOCK_FLOAT, in[0]);
- nodestack_get_vec(vec + 1, SOCK_FLOAT, in[1]);
- nodestack_get_vec(vec + 2, SOCK_FLOAT, in[2]);
-
- out[0]->vec[0] = 1.0f / (1.0f + powf(M_E, -((vec[0] - vec[2]) * vec[1])));
-}
-
-static int gpu_shader_squeeze(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- return GPU_stack_link(mat, node, "squeeze", in, out);
-}
-
-void register_node_type_sh_squeeze(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_squeeze_in, sh_node_squeeze_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_squeeze);
- node_type_gpu(&ntype, gpu_shader_squeeze);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_squeeze.cc b/source/blender/nodes/shader/nodes/node_shader_squeeze.cc
new file mode 100644
index 00000000000..83965160019
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_squeeze.cc
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_squeeze_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Value")).default_value(0.0f).min(-100.0f).max(100.0f);
+ b.add_input<decl::Float>(N_("Width")).default_value(1.0f).min(-100.0f).max(100.0f);
+ b.add_input<decl::Float>(N_("Center")).default_value(0.0f).min(-100.0f).max(100.0f);
+ b.add_output<decl::Float>(N_("Value"));
+}
+
+static int gpu_shader_squeeze(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, node, "squeeze", in, out);
+}
+
+} // namespace blender::nodes::node_shader_squeeze_cc
+
+void register_node_type_sh_squeeze()
+{
+ namespace file_ns = blender::nodes::node_shader_squeeze_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_squeeze);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc
index 85a4a6aa425..f60db81b4a9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc
@@ -17,24 +17,37 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_subsurface_scattering_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Scale"), 1.0, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Radius"), 1.0f, 0.2f, 0.1f, 0.0f, 0.0f, 100.0f, PROP_NONE, SOCK_COMPACT},
- {SOCK_FLOAT, N_("IOR"), 1.4f, 0.0f, 0.0f, 0.0f, 1.01f, 3.8f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Anisotropy"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_subsurface_scattering_cc {
-static bNodeSocketTemplate sh_node_subsurface_scattering_out[] = {
- {SOCK_SHADER, N_("BSSRDF")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Radius"))
+ .default_value({1.0f, 0.2f, 0.1f})
+ .min(0.0f)
+ .max(100.0f)
+ .compact();
+ b.add_input<decl::Float>(N_("IOR")).default_value(1.4f).min(1.01f).max(3.8f).subtype(
+ PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Anisotropy"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Vector>(N_("Normal")).hide_value();
+ b.add_output<decl::Shader>(N_("BSSRDF"));
+}
+
+static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_subsurface_scattering(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -53,14 +66,14 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
}
if (node->sss_id > 0) {
- bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
- bNodeSocketValueRGBA *socket_data = socket->default_value;
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2);
+ bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value;
/* For some reason it seems that the socket value is in ARGB format. */
GPU_material_sss_profile_create(mat, &socket_data->value[1]);
/* sss_id is 0 only the node is not connected to any output.
* In this case flagging the material would trigger a bug (see T68736). */
- GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
+ GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS));
}
return GPU_stack_link(
@@ -71,27 +84,30 @@ static void node_shader_update_subsurface_scattering(bNodeTree *ntree, bNode *no
{
const int sss_method = node->custom1;
- for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (STR_ELEM(sock->name, "IOR", "Anisotropy")) {
nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY);
}
}
}
+} // namespace blender::nodes::node_shader_subsurface_scattering_cc
+
/* node type definition */
-void register_node_type_sh_subsurface_scattering(void)
+void register_node_type_sh_subsurface_scattering()
{
+ namespace file_ns = blender::nodes::node_shader_subsurface_scattering_cc;
+
static bNodeType ntype;
sh_node_type_base(
- &ntype, SH_NODE_SUBSURFACE_SCATTERING, "Subsurface Scattering", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(
- &ntype, sh_node_subsurface_scattering_in, sh_node_subsurface_scattering_out);
+ &ntype, SH_NODE_SUBSURFACE_SCATTERING, "Subsurface Scattering", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_subsurface;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_subsurface_scattering);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_subsurface_scattering);
- node_type_update(&ntype, node_shader_update_subsurface_scattering);
+ node_type_init(&ntype, file_ns::node_shader_init_subsurface_scattering);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_subsurface_scattering);
+ node_type_update(&ntype, file_ns::node_shader_update_subsurface_scattering);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.c b/source/blender/nodes/shader/nodes/node_shader_tangent.cc
index 2c12bf9bc01..c4e5660b9f8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tangent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tangent.cc
@@ -17,18 +17,49 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "BKE_context.h"
-static bNodeSocketTemplate sh_node_tangent_out[] = {
- {SOCK_VECTOR, N_("Tangent"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tangent_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Tangent"));
+}
+
+static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiLayout *split, *row;
+
+ split = uiLayoutSplit(layout, 0.0f, false);
+
+ uiItemR(split, ptr, "direction_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", 0);
+
+ row = uiLayoutRow(split, false);
+
+ if (RNA_enum_get(ptr, "direction_type") == SHD_TANGENT_UVMAP) {
+ PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
+
+ if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+ PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
+ uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
+ }
+ else {
+ uiItemR(row, ptr, "uv_map", UI_ITEM_R_SPLIT_EMPTY_NAME, "", 0);
+ }
+ }
+ else {
+ uiItemR(row, ptr, "axis", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND, nullptr, 0);
+ }
+}
static void node_shader_init_tangent(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderTangent *attr = MEM_callocN(sizeof(NodeShaderTangent), "NodeShaderTangent");
+ NodeShaderTangent *attr = MEM_cnew<NodeShaderTangent>("NodeShaderTangent");
attr->axis = SHD_TANGENT_AXIS_Z;
node->storage = attr;
}
@@ -39,7 +70,7 @@ static int node_shader_gpu_tangent(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderTangent *attr = node->storage;
+ NodeShaderTangent *attr = static_cast<NodeShaderTangent *>(node->storage);
if (attr->direction_type == SHD_TANGENT_UVMAP) {
return GPU_stack_link(
@@ -68,16 +99,21 @@ static int node_shader_gpu_tangent(GPUMaterial *mat,
GPU_builtin(GPU_OBJECT_MATRIX));
}
+} // namespace blender::nodes::node_shader_tangent_cc
+
/* node type definition */
-void register_node_type_sh_tangent(void)
+void register_node_type_sh_tangent()
{
+ namespace file_ns = blender::nodes::node_shader_tangent_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TANGENT, "Tangent", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_tangent_out);
+ sh_node_type_base(&ntype, SH_NODE_TANGENT, "Tangent", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tangent;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tangent);
- node_type_gpu(&ntype, node_shader_gpu_tangent);
+ node_type_init(&ntype, file_ns::node_shader_init_tangent);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tangent);
node_type_storage(
&ntype, "NodeShaderTangent", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
index 7925c96db3d..81a69ef18da 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
@@ -17,12 +17,14 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-#include "BLI_float2.hh"
-#include "BLI_float4.hh"
+#include "BLI_math_vec_types.hh"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_brick_cc {
static void sh_node_tex_brick_declare(NodeDeclarationBuilder &b)
{
@@ -55,13 +57,31 @@ static void sh_node_tex_brick_declare(NodeDeclarationBuilder &b)
.no_muted_links();
b.add_output<decl::Color>(N_("Color"));
b.add_output<decl::Float>(N_("Fac"));
-};
+}
-} // namespace blender::nodes
+static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *col;
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col,
+ ptr,
+ "offset",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER,
+ IFACE_("Offset"),
+ ICON_NONE);
+ uiItemR(
+ col, ptr, "offset_frequency", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Frequency"), ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "squash", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Squash"), ICON_NONE);
+ uiItemR(
+ col, ptr, "squash_frequency", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Frequency"), ICON_NONE);
+}
static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexBrick *tex = (NodeTexBrick *)MEM_callocN(sizeof(NodeTexBrick), "NodeTexBrick");
+ NodeTexBrick *tex = MEM_cnew<NodeTexBrick>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
@@ -101,8 +121,6 @@ static int node_shader_gpu_tex_brick(GPUMaterial *mat,
GPU_constant(&squash_freq));
}
-namespace blender::nodes {
-
class BrickFunction : public fn::MultiFunction {
private:
const float offset_;
@@ -266,20 +284,23 @@ static void sh_node_brick_build_multi_function(blender::nodes::NodeMultiFunction
tex->offset, tex->offset_freq, tex->squash, tex->squash_freq);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_brick_cc
void register_node_type_sh_tex_brick()
{
+ namespace file_ns = blender::nodes::node_shader_tex_brick_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_brick_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_brick_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_brick;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_brick);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_brick);
node_type_storage(
&ntype, "NodeTexBrick", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_brick);
- ntype.build_multi_function = blender::nodes::sh_node_brick_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_brick);
+ ntype.build_multi_function = file_ns::sh_node_brick_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
index 6d2d199aec8..6022f13821a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
@@ -17,9 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_tex_checker_cc {
static void sh_node_tex_checker_declare(NodeDeclarationBuilder &b)
{
@@ -34,13 +34,11 @@ static void sh_node_tex_checker_declare(NodeDeclarationBuilder &b)
.no_muted_links();
b.add_output<decl::Color>(N_("Color"));
b.add_output<decl::Float>(N_("Fac"));
-};
-
-} // namespace blender::nodes
+}
static void node_shader_init_tex_checker(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexChecker *tex = (NodeTexChecker *)MEM_callocN(sizeof(NodeTexChecker), "NodeTexChecker");
+ NodeTexChecker *tex = MEM_cnew<NodeTexChecker>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
@@ -59,8 +57,6 @@ static int node_shader_gpu_tex_checker(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_tex_checker", in, out);
}
-namespace blender::nodes {
-
class NodeTexChecker : public fn::MultiFunction {
public:
NodeTexChecker()
@@ -121,19 +117,21 @@ static void sh_node_tex_checker_build_multi_function(
builder.set_matching_fn(fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_checker_cc
void register_node_type_sh_tex_checker()
{
+ namespace file_ns = blender::nodes::node_shader_tex_checker_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_CHECKER, "Checker Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_checker_declare;
- node_type_init(&ntype, node_shader_init_tex_checker);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_CHECKER, "Checker Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_checker_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_checker);
node_type_storage(
&ntype, "NodeTexChecker", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_checker);
- ntype.build_multi_function = blender::nodes::sh_node_tex_checker_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_checker);
+ ntype.build_multi_function = file_ns::sh_node_tex_checker_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc
index 4ce19bdc45e..1bbaed88ea5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc
@@ -17,22 +17,31 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "DNA_customdata_types.h"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_tex_coord_out[] = {
- {SOCK_VECTOR, N_("Generated"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("UV"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Object"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Camera"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Window"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Reflection"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_tex_coord_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Generated"));
+ b.add_output<decl::Vector>(N_("Normal"));
+ b.add_output<decl::Vector>(N_("UV"));
+ b.add_output<decl::Vector>(N_("Object"));
+ b.add_output<decl::Vector>(N_("Camera"));
+ b.add_output<decl::Vector>(N_("Window"));
+ b.add_output<decl::Vector>(N_("Reflection"));
+}
+
+static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "object", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+ uiItemR(layout, ptr, "from_instancer", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+}
static int node_shader_gpu_tex_coord(GPUMaterial *mat,
bNode *node,
@@ -42,11 +51,12 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
{
Object *ob = (Object *)node->id;
- GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) :
- GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
+ GPUNodeLink *inv_obmat = (ob != nullptr) ? GPU_uniform(&ob->imat[0][0]) :
+ GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
/* Opti: don't request orco if not needed. */
- GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant((float[4]){0.0f, 0.0f, 0.0f, 0.0f}) :
+ const float default_coords[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant(default_coords) :
GPU_attribute(mat, CD_ORCO, "");
GPUNodeLink *mtface = GPU_attribute(mat, CD_MTFACE, "");
GPUNodeLink *viewpos = GPU_builtin(GPU_VIEW_POSITION);
@@ -60,8 +70,8 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
GPU_stack_link(
mat, node, "node_tex_coord", in, out, viewpos, worldnor, inv_obmat, texcofacs, orco, mtface);
- /* for each output. */
- for (int i = 0; sh_node_tex_coord_out[i].type != -1; i++) {
+ int i;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, i) {
node_shader_gpu_bump_tex_coord(mat, node, &out[i].link);
/* Normalize some vectors after dFdx/dFdy offsets.
* This is the case for interpolated, non linear functions.
@@ -75,23 +85,26 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
out[i].link,
out[i].link,
&out[i].link,
- NULL);
+ nullptr);
}
}
return 1;
}
+} // namespace blender::nodes::node_shader_tex_coord_cc
+
/* node type definition */
-void register_node_type_sh_tex_coord(void)
+void register_node_type_sh_tex_coord()
{
+ namespace file_ns = blender::nodes::node_shader_tex_coord_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_COORD, "Texture Coordinate", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_tex_coord_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_tex_coord);
+ sh_node_type_base(&ntype, SH_NODE_TEX_COORD, "Texture Coordinate", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_coord;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_coord);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
index ff08961b3e9..7b947392084 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
@@ -17,23 +17,19 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_tex_environment_cc {
-static bNodeSocketTemplate sh_node_tex_environment_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_tex_environment_out[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector")).hide_value();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+}
static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment");
+ NodeTexEnvironment *tex = MEM_cnew<NodeTexEnvironment>("NodeTexEnvironment");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->projection = SHD_PROJ_EQUIRECTANGULAR;
@@ -49,12 +45,12 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
GPUNodeStack *out)
{
Image *ima = (Image *)node->id;
- NodeTexEnvironment *tex = node->storage;
+ NodeTexEnvironment *tex = (NodeTexEnvironment *)node->storage;
/* We get the image user from the original node, since GPU image keeps
* a pointer to it and the dependency refreshes the original. */
bNode *node_original = node->original ? node->original : node;
- NodeTexImage *tex_original = node_original->storage;
+ NodeTexImage *tex_original = (NodeTexImage *)node_original->storage;
ImageUser *iuser = &tex_original->iuser;
eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
/* TODO(fclem): For now assume mipmap is always enabled. */
@@ -132,17 +128,21 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_tex_environment_cc
+
/* node type definition */
-void register_node_type_sh_tex_environment(void)
+void register_node_type_sh_tex_environment()
{
+ namespace file_ns = blender::nodes::node_shader_tex_environment_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_ENVIRONMENT, "Environment Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_environment_in, sh_node_tex_environment_out);
- node_type_init(&ntype, node_shader_init_tex_environment);
+ sh_node_type_base(&ntype, SH_NODE_TEX_ENVIRONMENT, "Environment Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_environment);
node_type_storage(
&ntype, "NodeTexEnvironment", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_environment);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_environment);
ntype.labelfunc = node_image_label;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
index 48199968547..53be5bc09d9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
@@ -17,9 +17,12 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_gradient_cc {
static void sh_node_tex_gradient_declare(NodeDeclarationBuilder &b)
{
@@ -27,14 +30,16 @@ static void sh_node_tex_gradient_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Vector>(N_("Vector")).hide_value().implicit_field();
b.add_output<decl::Color>(N_("Color")).no_muted_links();
b.add_output<decl::Float>(N_("Fac")).no_muted_links();
-};
+}
-} // namespace blender::nodes
+static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "gradient_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_tex_gradient(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexGradient *tex = (NodeTexGradient *)MEM_callocN(sizeof(NodeTexGradient),
- "NodeTexGradient");
+ NodeTexGradient *tex = MEM_cnew<NodeTexGradient>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->gradient_type = SHD_BLEND_LINEAR;
@@ -56,8 +61,6 @@ static int node_shader_gpu_tex_gradient(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_tex_gradient", in, out, GPU_constant(&gradient_type));
}
-namespace blender::nodes {
-
class GradientFunction : public fn::MultiFunction {
private:
int gradient_type_;
@@ -127,7 +130,7 @@ class GradientFunction : public fn::MultiFunction {
/* Bias a little bit for the case where input is a unit length vector,
* to get exactly zero instead of a small random value depending
* on float precision. */
- const float r = std::max(0.999999f - vector[i].length(), 0.0f);
+ const float r = std::max(0.999999f - math::length(vector[i]), 0.0f);
fac[i] = r * r;
}
break;
@@ -137,7 +140,7 @@ class GradientFunction : public fn::MultiFunction {
/* Bias a little bit for the case where input is a unit length vector,
* to get exactly zero instead of a small random value depending
* on float precision. */
- fac[i] = std::max(0.999999f - vector[i].length(), 0.0f);
+ fac[i] = std::max(0.999999f - math::length(vector[i]), 0.0f);
}
break;
}
@@ -158,19 +161,22 @@ static void sh_node_gradient_tex_build_multi_function(
builder.construct_and_set_matching_fn<GradientFunction>(tex->gradient_type);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_gradient_cc
void register_node_type_sh_tex_gradient()
{
+ namespace file_ns = blender::nodes::node_shader_tex_gradient_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_GRADIENT, "Gradient Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_gradient_declare;
- node_type_init(&ntype, node_shader_init_tex_gradient);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_GRADIENT, "Gradient Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_gradient_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_gradient;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_gradient);
node_type_storage(
&ntype, "NodeTexGradient", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_gradient);
- ntype.build_multi_function = blender::nodes::sh_node_gradient_tex_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_gradient);
+ ntype.build_multi_function = file_ns::sh_node_gradient_tex_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
index d139707c6d7..d5479f46a35 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
@@ -17,9 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_tex_image_cc {
static void sh_node_tex_image_declare(NodeDeclarationBuilder &b)
{
@@ -27,13 +27,11 @@ static void sh_node_tex_image_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Vector>(N_("Vector")).implicit_field();
b.add_output<decl::Color>(N_("Color")).no_muted_links();
b.add_output<decl::Float>(N_("Alpha")).no_muted_links();
-};
-
-}; // namespace blender::nodes
+}
static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexImage *tex = (NodeTexImage *)MEM_callocN(sizeof(NodeTexImage), "NodeTexImage");
+ NodeTexImage *tex = MEM_cnew<NodeTexImage>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
BKE_imageuser_default(&tex->iuser);
@@ -173,17 +171,20 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
return true;
}
-/* node type definition */
+} // namespace blender::nodes::node_shader_tex_image_cc
+
void register_node_type_sh_tex_image()
{
+ namespace file_ns = blender::nodes::node_shader_tex_image_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_IMAGE, "Image Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_image_declare;
- node_type_init(&ntype, node_shader_init_tex_image);
+ sh_node_type_base(&ntype, SH_NODE_TEX_IMAGE, "Image Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_image_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_image);
node_type_storage(
&ntype, "NodeTexImage", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_image);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_image);
ntype.labelfunc = node_image_label;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
index 9bd5c335cee..e40914783b6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
@@ -17,9 +17,12 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_magic_cc {
static void sh_node_tex_magic_declare(NodeDeclarationBuilder &b)
{
@@ -29,13 +32,16 @@ static void sh_node_tex_magic_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Distortion")).min(-1000.0f).max(1000.0f).default_value(1.0f);
b.add_output<decl::Color>(N_("Color")).no_muted_links();
b.add_output<decl::Float>(N_("Fac")).no_muted_links();
-};
+}
-} // namespace blender::nodes
+static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "turbulence_depth", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+}
static void node_shader_init_tex_magic(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexMagic *tex = (NodeTexMagic *)MEM_callocN(sizeof(NodeTexMagic), "NodeTexMagic");
+ NodeTexMagic *tex = MEM_cnew<NodeTexMagic>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->depth = 2;
@@ -58,8 +64,6 @@ static int node_shader_gpu_tex_magic(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_tex_magic", in, out, GPU_constant(&depth));
}
-namespace blender::nodes {
-
class MagicFunction : public fn::MultiFunction {
private:
int depth_;
@@ -179,19 +183,22 @@ static void sh_node_magic_tex_build_multi_function(
builder.construct_and_set_matching_fn<MagicFunction>(tex->depth);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_magic_cc
void register_node_type_sh_tex_magic()
{
+ namespace file_ns = blender::nodes::node_shader_tex_magic_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_MAGIC, "Magic Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_magic_declare;
- node_type_init(&ntype, node_shader_init_tex_magic);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_MAGIC, "Magic Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_magic_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_magic;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_magic);
node_type_storage(
&ntype, "NodeTexMagic", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_magic);
- ntype.build_multi_function = blender::nodes::sh_node_magic_tex_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_magic);
+ ntype.build_multi_function = file_ns::sh_node_magic_tex_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
index 9504b0dc9f0..45c2a83c178 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
@@ -17,19 +17,25 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_noise.hh"
-NODE_STORAGE_FUNCS(NodeTexMusgrave)
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_musgrave_cc {
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeTexMusgrave)
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);
@@ -37,14 +43,17 @@ static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Offset")).min(-1000.0f).max(1000.0f);
b.add_input<decl::Float>(N_("Gain")).min(0.0f).max(1000.0f).default_value(1.0f);
b.add_output<decl::Float>(N_("Fac")).no_muted_links();
-};
+}
-} // namespace blender::nodes
+static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "musgrave_dimensions", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "musgrave_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexMusgrave *tex = (NodeTexMusgrave *)MEM_callocN(sizeof(NodeTexMusgrave),
- "NodeTexMusgrave");
+ NodeTexMusgrave *tex = MEM_cnew<NodeTexMusgrave>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->musgrave_type = SHD_MUSGRAVE_FBM;
@@ -130,8 +139,6 @@ static void node_shader_update_tex_musgrave(bNodeTree *ntree, bNode *node)
node_sock_label(outFacSock, "Height");
}
-namespace blender::nodes {
-
class MusgraveFunction : public fn::MultiFunction {
private:
const int dimensions_;
@@ -521,7 +528,7 @@ class MusgraveFunction : public fn::MultiFunction {
}
}
}
-}; // namespace blender::nodes
+};
static void sh_node_musgrave_build_multi_function(
blender::nodes::NodeMultiFunctionBuilder &builder)
@@ -531,21 +538,24 @@ static void sh_node_musgrave_build_multi_function(
builder.construct_and_set_matching_fn<MusgraveFunction>(tex->dimensions, tex->musgrave_type);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_musgrave_cc
void register_node_type_sh_tex_musgrave()
{
+ namespace file_ns = blender::nodes::node_shader_tex_musgrave_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_musgrave_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_musgrave_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_musgrave;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_musgrave);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_musgrave);
node_type_storage(
&ntype, "NodeTexMusgrave", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_musgrave);
- node_type_update(&ntype, node_shader_update_tex_musgrave);
- ntype.build_multi_function = blender::nodes::sh_node_musgrave_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_musgrave);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_musgrave);
+ ntype.build_multi_function = file_ns::sh_node_musgrave_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
index e3764120663..1c703313edf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
@@ -17,19 +17,25 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_noise.hh"
-NODE_STORAGE_FUNCS(NodeTexNoise)
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_noise_cc {
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeTexNoise)
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"))
@@ -40,13 +46,16 @@ static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Distortion")).min(-1000.0f).max(1000.0f).default_value(0.0f);
b.add_output<decl::Float>(N_("Fac")).no_muted_links();
b.add_output<decl::Color>(N_("Color")).no_muted_links();
-};
+}
-} // namespace blender::nodes
+static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "noise_dimensions", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexNoise *tex = (NodeTexNoise *)MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise");
+ NodeTexNoise *tex = MEM_cnew<NodeTexNoise>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->dimensions = 3;
@@ -88,8 +97,6 @@ static void node_shader_update_tex_noise(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sockW, storage.dimensions == 1 || storage.dimensions == 4);
}
-namespace blender::nodes {
-
class NoiseFunction : public fn::MultiFunction {
private:
int dimensions_;
@@ -169,14 +176,14 @@ class NoiseFunction : public fn::MultiFunction {
const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
if (compute_factor) {
for (int64_t i : mask) {
- const float2 position = vector[i] * scale[i];
+ const float2 position = float2(vector[i] * scale[i]);
r_factor[i] = noise::perlin_fractal_distorted(
position, detail[i], roughness[i], distortion[i]);
}
}
if (compute_color) {
for (int64_t i : mask) {
- const float2 position = vector[i] * scale[i];
+ const float2 position = float2(vector[i] * scale[i]);
const float3 c = noise::perlin_float3_fractal_distorted(
position, detail[i], roughness[i], distortion[i]);
r_color[i] = ColorGeometry4f(c[0], c[1], c[2], 1.0f);
@@ -247,21 +254,23 @@ static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunction
builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_noise_cc
-/* node type definition */
void register_node_type_sh_tex_noise()
{
+ namespace file_ns = blender::nodes::node_shader_tex_noise_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_noise_declare;
- node_type_init(&ntype, node_shader_init_tex_noise);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_noise_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_noise;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_noise);
node_type_storage(
&ntype, "NodeTexNoise", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_noise);
- node_type_update(&ntype, node_shader_update_tex_noise);
- ntype.build_multi_function = blender::nodes::sh_node_noise_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_noise);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_noise);
+ ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
deleted file mode 100644
index 14cd1fd4c0c..00000000000
--- a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2015 Blender Foundation.
- * All rights reserved.
- */
-
-#include "../node_shader_util.h"
-
-#include "RE_texture.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_tex_pointdensity_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_tex_pointdensity_out[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Density"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
- {-1, ""},
-};
-
-static void node_shader_init_tex_pointdensity(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeShaderTexPointDensity *point_density = MEM_callocN(sizeof(NodeShaderTexPointDensity),
- "new pd node");
- point_density->resolution = 100;
- point_density->radius = 0.3f;
- point_density->space = SHD_POINTDENSITY_SPACE_OBJECT;
- point_density->color_source = SHD_POINTDENSITY_COLOR_PARTAGE;
- node->storage = point_density;
-}
-
-static void node_shader_free_tex_pointdensity(bNode *node)
-{
- NodeShaderTexPointDensity *point_density = node->storage;
- PointDensity *pd = &point_density->pd;
- RE_point_density_free(pd);
- BKE_texture_pointdensity_free_data(pd);
- memset(pd, 0, sizeof(*pd));
- MEM_freeN(point_density);
-}
-
-static void node_shader_copy_tex_pointdensity(bNodeTree *UNUSED(dest_ntree),
- bNode *dest_node,
- const bNode *src_node)
-{
- dest_node->storage = MEM_dupallocN(src_node->storage);
- NodeShaderTexPointDensity *point_density = dest_node->storage;
- PointDensity *pd = &point_density->pd;
- memset(pd, 0, sizeof(*pd));
-}
-
-/* node type definition */
-void register_node_type_sh_tex_pointdensity(void)
-{
- static bNodeType ntype;
-
- sh_node_type_base(&ntype, SH_NODE_TEX_POINTDENSITY, "Point Density", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_pointdensity_in, sh_node_tex_pointdensity_out);
- node_type_init(&ntype, node_shader_init_tex_pointdensity);
- node_type_storage(&ntype,
- "NodeShaderTexPointDensity",
- node_shader_free_tex_pointdensity,
- node_shader_copy_tex_pointdensity);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc
new file mode 100644
index 00000000000..1a4cf70565f
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc
@@ -0,0 +1,131 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "node_shader_util.hh"
+
+#include "RE_texture.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_pointdensity_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector")).hide_value();
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Density"));
+}
+
+static void node_shader_buts_tex_pointdensity(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeShaderTexPointDensity *shader_point_density = (NodeShaderTexPointDensity *)node->storage;
+ Object *ob = (Object *)node->id;
+
+ PointerRNA ob_ptr, obdata_ptr;
+ RNA_id_pointer_create((ID *)ob, &ob_ptr);
+ RNA_id_pointer_create(ob ? (ID *)ob->data : nullptr, &obdata_ptr);
+
+ uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "object", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
+ PointerRNA dataptr;
+ RNA_id_pointer_create((ID *)node->id, &dataptr);
+ uiItemPointerR(
+ layout, ptr, "particle_system", &dataptr, "particle_systems", nullptr, ICON_NONE);
+ }
+
+ uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "radius", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "resolution", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
+ uiItemR(layout, ptr, "particle_color_source", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ else {
+ uiItemR(layout, ptr, "vertex_color_source", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) {
+ if (ob_ptr.data) {
+ uiItemPointerR(
+ layout, ptr, "vertex_attribute_name", &ob_ptr, "vertex_groups", "", ICON_NONE);
+ }
+ }
+ if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTCOL) {
+ if (obdata_ptr.data) {
+ uiItemPointerR(
+ layout, ptr, "vertex_attribute_name", &obdata_ptr, "vertex_colors", "", ICON_NONE);
+ }
+ }
+ }
+}
+
+static void node_shader_init_tex_pointdensity(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeShaderTexPointDensity *point_density = MEM_cnew<NodeShaderTexPointDensity>("new pd node");
+ point_density->resolution = 100;
+ point_density->radius = 0.3f;
+ point_density->space = SHD_POINTDENSITY_SPACE_OBJECT;
+ point_density->color_source = SHD_POINTDENSITY_COLOR_PARTAGE;
+ node->storage = point_density;
+}
+
+static void node_shader_free_tex_pointdensity(bNode *node)
+{
+ NodeShaderTexPointDensity *point_density = (NodeShaderTexPointDensity *)node->storage;
+ PointDensity *pd = &point_density->pd;
+ RE_point_density_free(pd);
+ BKE_texture_pointdensity_free_data(pd);
+ memset(pd, 0, sizeof(*pd));
+ MEM_freeN(point_density);
+}
+
+static void node_shader_copy_tex_pointdensity(bNodeTree *UNUSED(dest_ntree),
+ bNode *dest_node,
+ const bNode *src_node)
+{
+ dest_node->storage = MEM_dupallocN(src_node->storage);
+ NodeShaderTexPointDensity *point_density = (NodeShaderTexPointDensity *)dest_node->storage;
+ PointDensity *pd = &point_density->pd;
+ memset(pd, 0, sizeof(*pd));
+}
+
+} // namespace blender::nodes::node_shader_tex_pointdensity_cc
+
+/* node type definition */
+void register_node_type_sh_tex_pointdensity()
+{
+ namespace file_ns = blender::nodes::node_shader_tex_pointdensity_cc;
+
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_TEX_POINTDENSITY, "Point Density", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_pointdensity;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_pointdensity);
+ node_type_storage(&ntype,
+ "NodeShaderTexPointDensity",
+ file_ns::node_shader_free_tex_pointdensity,
+ file_ns::node_shader_copy_tex_pointdensity);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
index 5c581528c14..b8728d69bba 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
@@ -17,24 +17,66 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "sky_model.h"
-/* **************** OUTPUT ******************** */
+#include "BKE_context.h"
+#include "BKE_scene.h"
-static bNodeSocketTemplate sh_node_tex_sky_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_tex_sky_out[] = {
- {SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_tex_sky_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector")).hide_value();
+ b.add_output<decl::Color>(N_("Color")).no_muted_links();
+}
+
+static void node_shader_buts_tex_sky(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "sky_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+
+ if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_PREETHAM) {
+ uiItemR(layout, ptr, "sun_direction", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "turbidity", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_HOSEK) {
+ uiItemR(layout, ptr, "sun_direction", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "turbidity", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "ground_albedo", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+ if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NISHITA) {
+ Scene *scene = CTX_data_scene(C);
+ if (BKE_scene_uses_blender_eevee(scene)) {
+ uiItemL(layout, TIP_("Nishita not available in Eevee"), ICON_ERROR);
+ }
+ uiItemR(layout, ptr, "sun_disc", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+
+ uiLayout *col;
+ if (RNA_boolean_get(ptr, "sun_disc")) {
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "sun_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "sun_intensity", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "sun_elevation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "sun_rotation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ uiItemR(layout, ptr, "altitude", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "air_density", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "dust_density", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(col, ptr, "ozone_density", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ }
+}
static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexSky *tex = MEM_callocN(sizeof(NodeTexSky), "NodeTexSky");
+ NodeTexSky *tex = MEM_cnew<NodeTexSky>("NodeTexSky");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->sun_direction[0] = 0.0f;
@@ -55,10 +97,10 @@ static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = tex;
}
-typedef struct SkyModelPreetham {
+struct SkyModelPreetham {
float config_Y[5], config_x[5], config_y[5]; /* named after xyY color space */
float radiance[3];
-} SkyModelPreetham;
+};
static float sky_perez_function(const float *lam, float theta, float gamma)
{
@@ -203,19 +245,24 @@ static void node_shader_update_sky(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1));
}
+} // namespace blender::nodes::node_shader_tex_sky_cc
+
/* node type definition */
-void register_node_type_sh_tex_sky(void)
+void register_node_type_sh_tex_sky()
{
+ namespace file_ns = blender::nodes::node_shader_tex_sky_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_SKY, "Sky Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_sky_in, sh_node_tex_sky_out);
+ sh_node_type_base(&ntype, SH_NODE_TEX_SKY, "Sky Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_sky;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_sky);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_sky);
node_type_storage(&ntype, "NodeTexSky", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_sky);
- /* remove Vector input for Nishita */
- node_type_update(&ntype, node_shader_update_sky);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_sky);
+ /* Remove vector input for Nishita sky model. */
+ node_type_update(&ntype, file_ns::node_shader_update_sky);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
index 6968a7483b6..209f96449cd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
@@ -17,26 +17,37 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_noise.hh"
-NODE_STORAGE_FUNCS(NodeTexVoronoi)
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_voronoi_cc {
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeTexVoronoi)
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)
@@ -45,15 +56,29 @@ 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
+static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "voronoi_dimensions", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "feature", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ int feature = RNA_enum_get(ptr, "feature");
+ if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) &&
+ RNA_enum_get(ptr, "voronoi_dimensions") != 1) {
+ uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+}
static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexVoronoi *tex = (NodeTexVoronoi *)MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi");
+ NodeTexVoronoi *tex = MEM_cnew<NodeTexVoronoi>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->dimensions = 3;
@@ -168,8 +193,6 @@ static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, outRadiusSock, storage.feature == SHD_VORONOI_N_SPHERE_RADIUS);
}
-namespace blender::nodes {
-
static MultiFunction::ExecutionHints voronoi_execution_hints{50, false};
class VoronoiMinowskiFunction : public fn::MultiFunction {
@@ -290,7 +313,7 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- pos = float2::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
r_position[i] = float3(pos.x, pos.y, 0.0f);
}
}
@@ -322,7 +345,7 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- pos = float2::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
r_position[i] = float3(pos.x, pos.y, 0.0f);
}
}
@@ -357,7 +380,7 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- pos = float2::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
r_position[i] = float3(pos.x, pos.y, 0.0f);
}
}
@@ -393,7 +416,7 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
}
}
break;
@@ -423,7 +446,7 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
}
}
break;
@@ -456,7 +479,7 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
}
}
break;
@@ -496,7 +519,7 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position || calc_w) {
- pos = float4::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
if (calc_position) {
r_position[i] = float3(pos.x, pos.y, pos.z);
}
@@ -537,7 +560,7 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position || calc_w) {
- pos = float4::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
if (calc_position) {
r_position[i] = float3(pos.x, pos.y, pos.z);
}
@@ -581,7 +604,7 @@ class VoronoiMinowskiFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position || calc_w) {
- pos = float4::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
if (calc_position) {
r_position[i] = float3(pos.x, pos.y, pos.z);
}
@@ -814,7 +837,7 @@ class VoronoiMetricFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- pos = float2::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
r_position[i] = float3(pos.x, pos.y, 0.0f);
}
}
@@ -845,7 +868,7 @@ class VoronoiMetricFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- pos = float2::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
r_position[i] = float3(pos.x, pos.y, 0.0f);
}
}
@@ -879,7 +902,7 @@ class VoronoiMetricFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- pos = float2::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
r_position[i] = float3(pos.x, pos.y, 0.0f);
}
}
@@ -914,7 +937,7 @@ class VoronoiMetricFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
}
}
break;
@@ -943,7 +966,7 @@ class VoronoiMetricFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
}
}
break;
@@ -976,7 +999,7 @@ class VoronoiMetricFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position) {
- r_position[i] = float3::safe_divide(r_position[i], scale[i]);
+ r_position[i] = math::safe_divide(r_position[i], scale[i]);
}
}
}
@@ -1017,7 +1040,7 @@ class VoronoiMetricFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position || calc_w) {
- pos = float4::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
if (calc_position) {
r_position[i] = float3(pos.x, pos.y, pos.z);
}
@@ -1057,7 +1080,7 @@ class VoronoiMetricFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position || calc_w) {
- pos = float4::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
if (calc_position) {
r_position[i] = float3(pos.x, pos.y, pos.z);
}
@@ -1100,7 +1123,7 @@ class VoronoiMetricFunction : public fn::MultiFunction {
r_color[i] = ColorGeometry4f(col[0], col[1], col[2], 1.0f);
}
if (calc_position || calc_w) {
- pos = float4::safe_divide(pos, scale[i]);
+ pos = math::safe_divide(pos, scale[i]);
if (calc_position) {
r_position[i] = float3(pos.x, pos.y, pos.z);
}
@@ -1327,20 +1350,23 @@ static void sh_node_voronoi_build_multi_function(blender::nodes::NodeMultiFuncti
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_voronoi_cc
void register_node_type_sh_tex_voronoi()
{
+ namespace file_ns = blender::nodes::node_shader_tex_voronoi_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_voronoi_declare;
- node_type_init(&ntype, node_shader_init_tex_voronoi);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_voronoi_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_voronoi;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_voronoi);
node_type_storage(
&ntype, "NodeTexVoronoi", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_voronoi);
- node_type_update(&ntype, node_shader_update_tex_voronoi);
- ntype.build_multi_function = blender::nodes::sh_node_voronoi_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_voronoi);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_voronoi);
+ ntype.build_multi_function = file_ns::sh_node_voronoi_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
index d3e25b533e5..fc6c66061ff 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
@@ -17,11 +17,14 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_noise.hh"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_wave_cc {
static void sh_node_tex_wave_declare(NodeDeclarationBuilder &b)
{
@@ -39,13 +42,25 @@ static void sh_node_tex_wave_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Phase Offset")).min(-1000.0f).max(1000.0f).default_value(0.0f);
b.add_output<decl::Color>(N_("Color")).no_muted_links();
b.add_output<decl::Float>(N_("Fac")).no_muted_links();
-};
+}
+
+static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "wave_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ int type = RNA_enum_get(ptr, "wave_type");
+ if (type == SHD_WAVE_BANDS) {
+ uiItemR(layout, ptr, "bands_direction", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
+ else { /* SHD_WAVE_RINGS */
+ uiItemR(layout, ptr, "rings_direction", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ }
-} // namespace blender::nodes
+ uiItemR(layout, ptr, "wave_profile", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_tex_wave(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexWave *tex = (NodeTexWave *)MEM_callocN(sizeof(NodeTexWave), "NodeTexWave");
+ NodeTexWave *tex = MEM_cnew<NodeTexWave>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->wave_type = SHD_WAVE_BANDS;
@@ -81,8 +96,6 @@ static int node_shader_gpu_tex_wave(GPUMaterial *mat,
GPU_constant(&wave_profile));
}
-namespace blender::nodes {
-
class WaveFunction : public fn::MultiFunction {
private:
int wave_type_;
@@ -216,19 +229,22 @@ static void sh_node_wave_tex_build_multi_function(
tex->wave_type, tex->bands_direction, tex->rings_direction, tex->wave_profile);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_wave_cc
void register_node_type_sh_tex_wave()
{
+ namespace file_ns = blender::nodes::node_shader_tex_wave_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_WAVE, "Wave Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_wave_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_WAVE, "Wave Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_wave_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_tex_wave;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_wave);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_wave);
node_type_storage(&ntype, "NodeTexWave", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_wave);
- ntype.build_multi_function = blender::nodes::sh_node_wave_tex_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_wave);
+ ntype.build_multi_function = file_ns::sh_node_wave_tex_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
index f2dfd2e6968..3a5bc98896c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
@@ -17,22 +17,31 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_noise.hh"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_tex_white_noise_cc {
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"));
-};
+}
-} // namespace blender::nodes
+static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "noise_dimensions", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_tex_white_noise(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -67,8 +76,6 @@ static void node_shader_update_tex_white_noise(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sockW, node->custom1 == 1 || node->custom1 == 4);
}
-namespace blender::nodes {
-
class WhiteNoiseFunction : public fn::MultiFunction {
private:
int dimensions_;
@@ -189,19 +196,21 @@ static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunction
builder.construct_and_set_matching_fn<WhiteNoiseFunction>((int)node.custom1);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_white_noise_cc
void register_node_type_sh_tex_white_noise()
{
+ namespace file_ns = blender::nodes::node_shader_tex_white_noise_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(
- &ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_white_noise_declare;
- node_type_init(&ntype, node_shader_init_tex_white_noise);
- node_type_gpu(&ntype, gpu_shader_tex_white_noise);
- node_type_update(&ntype, node_shader_update_tex_white_noise);
- ntype.build_multi_function = blender::nodes::sh_node_noise_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_white_noise_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_white_noise;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_white_noise);
+ node_type_gpu(&ntype, file_ns::gpu_shader_tex_white_noise);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_white_noise);
+ ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc
index 05c3248af65..382a0f16ecd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc
@@ -17,23 +17,35 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_uvalongstroke_out[] = {
- {SOCK_VECTOR, N_("UV"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_uv_along_stroke_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("UV"));
+}
+
+static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_tips", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+}
+
+} // namespace blender::nodes::node_shader_uv_along_stroke_cc
/* node type definition */
-void register_node_type_sh_uvalongstroke(void)
+void register_node_type_sh_uvalongstroke()
{
+ namespace file_ns = blender::nodes::node_shader_uv_along_stroke_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_uvalongstroke_out);
- node_type_init(&ntype, NULL);
+ sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_uvalongstroke;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
index 775b8ffbc06..b004be75188 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
@@ -17,20 +17,39 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+#include "BKE_context.h"
#include "DNA_customdata_types.h"
-/* **************** OUTPUT ******************** */
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_uvmap_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("UV"));
+}
-static bNodeSocketTemplate sh_node_uvmap_out[] = {
- {SOCK_VECTOR, N_("UV"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "from_instancer", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+
+ if (!RNA_boolean_get(ptr, "from_instancer")) {
+ PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
+
+ if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+ PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
+ uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
+ }
+ }
+}
static void node_shader_init_uvmap(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderUVMap *attr = MEM_callocN(sizeof(NodeShaderUVMap), "NodeShaderUVMap");
+ NodeShaderUVMap *attr = MEM_cnew<NodeShaderUVMap>("NodeShaderUVMap");
node->storage = attr;
}
@@ -40,7 +59,7 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderUVMap *attr = node->storage;
+ NodeShaderUVMap *attr = static_cast<NodeShaderUVMap *>(node->storage);
GPUNodeLink *mtface = GPU_attribute(mat, CD_MTFACE, attr->uv_map);
GPU_stack_link(mat, node, "node_uvmap", in, out, mtface);
@@ -50,18 +69,23 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
return 1;
}
+} // namespace blender::nodes::node_shader_uvmap_cc
+
/* node type definition */
-void register_node_type_sh_uvmap(void)
+void register_node_type_sh_uvmap()
{
+ namespace file_ns = blender::nodes::node_shader_uvmap_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_UVMAP, "UV Map", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_uvmap_out);
+ sh_node_type_base(&ntype, SH_NODE_UVMAP, "UV Map", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_uvmap;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_uvmap);
+ node_type_init(&ntype, file_ns::node_shader_init_uvmap);
node_type_storage(
&ntype, "NodeShaderUVMap", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_uvmap);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_uvmap);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc
index f0eb3ea9bee..265f03e6e88 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_value.cc
@@ -21,16 +21,14 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_value_cc {
static void sh_node_value_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Value"));
-};
-
-} // namespace blender::nodes
+}
static int gpu_shader_value(GPUMaterial *mat,
bNode *node,
@@ -49,14 +47,18 @@ static void sh_node_value_build_multi_function(blender::nodes::NodeMultiFunction
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value);
}
+} // namespace blender::nodes::node_shader_value_cc
+
void register_node_type_sh_value()
{
+ namespace file_ns = blender::nodes::node_shader_value_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::sh_node_value_declare;
- node_type_gpu(&ntype, gpu_shader_value);
- ntype.build_multi_function = sh_node_value_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::sh_node_value_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_value);
+ ntype.build_multi_function = file_ns::sh_node_value_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc
index 0e82f346529..3486eda1635 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc
@@ -17,21 +17,17 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_vector_displacement_cc {
-static bNodeSocketTemplate sh_node_vector_displacement_in[] = {
- {SOCK_RGBA, N_("Vector"), 0.00f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Midlevel"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Scale"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_vector_displacement_out[] = {
- {SOCK_VECTOR, N_("Displacement"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Vector")).hide_value();
+ b.add_input<decl::Float>(N_("Midlevel")).default_value(0.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_output<decl::Vector>(N_("Displacement"));
+}
static void node_shader_init_vector_displacement(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -63,18 +59,20 @@ static int gpu_shader_vector_displacement(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_vector_displacement_world", in, out);
}
+} // namespace blender::nodes::node_shader_vector_displacement_cc
+
/* node type definition */
-void register_node_type_sh_vector_displacement(void)
+void register_node_type_sh_vector_displacement()
{
+ namespace file_ns = blender::nodes::node_shader_vector_displacement_cc;
+
static bNodeType ntype;
sh_node_type_base(
- &ntype, SH_NODE_VECTOR_DISPLACEMENT, "Vector Displacement", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(
- &ntype, sh_node_vector_displacement_in, sh_node_vector_displacement_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_init(&ntype, node_shader_init_vector_displacement);
- node_type_gpu(&ntype, gpu_shader_vector_displacement);
+ &ntype, SH_NODE_VECTOR_DISPLACEMENT, "Vector Displacement", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_vector_displacement);
+ node_type_gpu(&ntype, file_ns::gpu_shader_vector_displacement);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
index 7f87332ba1b..591734c7dd6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
@@ -21,11 +21,17 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "NOD_math_functions.hh"
+#include "NOD_socket_search_link.hh"
-namespace blender::nodes {
+#include "RNA_enum_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_vector_math_cc {
static void sh_node_vector_math_declare(NodeDeclarationBuilder &b)
{
@@ -36,9 +42,53 @@ static void sh_node_vector_math_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Scale")).default_value(1.0f).min(-10000.0f).max(10000.0f);
b.add_output<decl::Vector>(N_("Vector"));
b.add_output<decl::Float>(N_("Value"));
+}
+
+static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "operation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
+
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ NodeVectorMathOperation mode = NODE_VECTOR_MATH_ADD;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("ShaderNodeVectorMath");
+ node.custom1 = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
};
-} // namespace blender::nodes
+static void sh_node_vector_math_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ if (!params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_VECTOR)) {
+ return;
+ }
+
+ const int weight = ELEM(params.other_socket().type, SOCK_VECTOR, SOCK_RGBA) ? 0 : -1;
+
+ for (const EnumPropertyItem *item = rna_enum_node_vec_math_items; item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ if ((params.in_out() == SOCK_OUT) && ELEM(item->value,
+ NODE_VECTOR_MATH_LENGTH,
+ NODE_VECTOR_MATH_DISTANCE,
+ NODE_VECTOR_MATH_DOT_PRODUCT)) {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{"Value", (NodeVectorMathOperation)item->value},
+ weight);
+ }
+ else {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{"Vector", (NodeVectorMathOperation)item->value},
+ weight);
+ }
+ }
+ }
+}
static const char *gpu_shader_get_name(int mode)
{
@@ -279,16 +329,22 @@ static void sh_node_vector_math_build_multi_function(
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_shader_vector_math_cc
+
void register_node_type_sh_vect_math()
{
+ namespace file_ns = blender::nodes::node_shader_vector_math_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::sh_node_vector_math_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::sh_node_vector_math_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_vect_math;
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;
+ node_type_gpu(&ntype, file_ns::gpu_shader_vector_math);
+ node_type_update(&ntype, file_ns::node_shader_update_vector_math);
+ ntype.build_multi_function = file_ns::sh_node_vector_math_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::sh_node_vector_math_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
index a3cb82f3245..d8dcd028c56 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -21,9 +21,12 @@
* \ingroup shdnodes
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_vector_rotate_cc {
static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b)
{
@@ -34,9 +37,13 @@ static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE);
b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
b.add_output<decl::Vector>(N_("Vector"));
-};
+}
-} // namespace blender::nodes
+static void node_shader_buts_vector_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "rotation_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "invert", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+}
static const char *gpu_shader_get_name(int mode)
{
@@ -205,15 +212,20 @@ static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node)
ntree, sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
}
+} // namespace blender::nodes::node_shader_vector_rotate_cc
+
void register_node_type_sh_vector_rotate()
{
+ namespace file_ns = blender::nodes::node_shader_vector_rotate_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::sh_node_vector_rotate_declare;
- node_type_gpu(&ntype, gpu_shader_vector_rotate);
- node_type_update(&ntype, node_shader_update_vector_rotate);
- ntype.build_multi_function = sh_node_vector_rotate_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::sh_node_vector_rotate_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_vector_rotate;
+ node_type_gpu(&ntype, file_ns::gpu_shader_vector_rotate);
+ node_type_update(&ntype, file_ns::node_shader_update_vector_rotate);
+ ntype.build_multi_function = file_ns::sh_node_vector_rotate_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_transform.c b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc
index 7b08178f874..a8a6902e30c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_transform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc
@@ -21,21 +21,37 @@
* \ingroup shdnodes
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Vector Transform ******************** */
-static bNodeSocketTemplate sh_node_vect_transform_in[] = {
- {SOCK_VECTOR, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, {-1, ""}};
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_vect_transform_out[] = {
- {SOCK_VECTOR, N_("Vector")},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_vector_transform_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("Vector"))
+ .default_value({0.5f, 0.5f, 0.5f})
+ .min(-10000.0f)
+ .max(10000.0f);
+ b.add_output<decl::Vector>(N_("Vector"));
+}
+
+static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout,
+ ptr,
+ "vector_type",
+ UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_EXPAND,
+ nullptr,
+ ICON_NONE);
+ uiItemR(layout, ptr, "convert_from", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+ uiItemR(layout, ptr, "convert_to", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
+}
static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderVectTransform *vect = MEM_callocN(sizeof(NodeShaderVectTransform),
- "NodeShaderVectTransform");
+ NodeShaderVectTransform *vect = MEM_cnew<NodeShaderVectTransform>("NodeShaderVectTransform");
/* Convert World into Object Space per default */
vect->convert_to = 1;
@@ -43,22 +59,13 @@ static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = vect;
}
-static void node_shader_exec_vect_transform(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **UNUSED(in),
- bNodeStack **UNUSED(out))
-{
-}
-
static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
{
switch (from) {
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
switch (to) {
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
- return NULL;
+ return nullptr;
case SHD_VECT_TRANSFORM_SPACE_WORLD:
return GPU_builtin(GPU_OBJECT_MATRIX);
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
@@ -68,7 +75,7 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
case SHD_VECT_TRANSFORM_SPACE_WORLD:
switch (to) {
case SHD_VECT_TRANSFORM_SPACE_WORLD:
- return NULL;
+ return nullptr;
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
return GPU_builtin(GPU_VIEW_MATRIX);
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
@@ -78,7 +85,7 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
switch (to) {
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
- return NULL;
+ return nullptr;
case SHD_VECT_TRANSFORM_SPACE_WORLD:
return GPU_builtin(GPU_INVERSE_VIEW_MATRIX);
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
@@ -86,7 +93,7 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
}
break;
}
- return NULL;
+ return nullptr;
}
static int gpu_shader_vect_transform(GPUMaterial *mat,
bNode *node,
@@ -99,7 +106,7 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
const char *vtransform = "direction_transform_m4v3";
const char *ptransform = "point_transform_m4v3";
- const char *func_name = 0;
+ const char *func_name = nullptr;
NodeShaderVectTransform *nodeprop = (NodeShaderVectTransform *)node->storage;
@@ -137,17 +144,21 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
return true;
}
-void register_node_type_sh_vect_transform(void)
+} // namespace blender::nodes::node_shader_vector_transform_cc
+
+void register_node_type_sh_vect_transform()
{
+ namespace file_ns = blender::nodes::node_shader_vector_transform_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_OP_VECTOR, 0);
- node_type_init(&ntype, node_shader_init_vect_transform);
- node_type_socket_templates(&ntype, sh_node_vect_transform_in, sh_node_vect_transform_out);
+ sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_vect_transform;
+ node_type_init(&ntype, file_ns::node_shader_init_vect_transform);
node_type_storage(
&ntype, "NodeShaderVectTransform", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_vect_transform);
- node_type_gpu(&ntype, gpu_shader_vect_transform);
+ node_type_gpu(&ntype, file_ns::gpu_shader_vect_transform);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
index 40576b68dd5..6501527ef5d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
@@ -17,18 +17,44 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-static bNodeSocketTemplate sh_node_vertex_color_out[] = {
- {SOCK_RGBA, N_("Color")},
- {SOCK_FLOAT, N_("Alpha")},
- {-1, ""},
-};
+#include "BKE_context.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_shader_vertex_color_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Alpha"));
+}
+
+static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
+ if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+ PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
+
+ if (U.experimental.use_sculpt_vertex_colors &&
+ RNA_collection_length(&dataptr, "sculpt_vertex_colors")) {
+ uiItemPointerR(
+ layout, ptr, "layer_name", &dataptr, "sculpt_vertex_colors", "", ICON_GROUP_VCOL);
+ }
+ else {
+ uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL);
+ }
+ }
+ else {
+ uiItemL(layout, TIP_("No mesh in active object"), ICON_ERROR);
+ }
+}
static void node_shader_init_vertex_color(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderVertexColor *vertexColor = MEM_callocN(sizeof(NodeShaderVertexColor),
- "NodeShaderVertexColor");
+ NodeShaderVertexColor *vertexColor = MEM_cnew<NodeShaderVertexColor>("NodeShaderVertexColor");
node->storage = vertexColor;
}
@@ -47,16 +73,21 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
}
-void register_node_type_sh_vertex_color(void)
+} // namespace blender::nodes::node_shader_vertex_color_cc
+
+void register_node_type_sh_vertex_color()
{
+ namespace file_ns = blender::nodes::node_shader_vertex_color_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_vertex_color_out);
- node_type_init(&ntype, node_shader_init_vertex_color);
+ sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_vertex_color;
+ node_type_init(&ntype, file_ns::node_shader_init_vertex_color);
node_type_storage(
&ntype, "NodeShaderVertexColor", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_vertex_color);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_vertex_color);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc
index abf2e63e6d5..a31bfdb6543 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc
@@ -17,20 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_volume_absorption_cc {
-static bNodeSocketTemplate sh_node_volume_absorption_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_volume_absorption_out[] = {
- {SOCK_SHADER, N_("Volume")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_output<decl::Shader>(N_("Volume"));
+}
static int node_shader_gpu_volume_absorption(GPUMaterial *mat,
bNode *node,
@@ -41,16 +37,18 @@ static int node_shader_gpu_volume_absorption(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_volume_absorption", in, out);
}
+} // namespace blender::nodes::node_shader_volume_absorption_cc
+
/* node type definition */
-void register_node_type_sh_volume_absorption(void)
+void register_node_type_sh_volume_absorption()
{
+ namespace file_ns = blender::nodes::node_shader_volume_absorption_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_ABSORPTION, "Volume Absorption", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_volume_absorption_in, sh_node_volume_absorption_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_volume_absorption);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_ABSORPTION, "Volume Absorption", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_absorption);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_info.c b/source/blender/nodes/shader/nodes/node_shader_volume_info.cc
index 6cafc991e13..6a973cdbad7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_info.cc
@@ -17,15 +17,17 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-static bNodeSocketTemplate sh_node_volume_info_out[] = {
- {SOCK_RGBA, N_("Color")},
- {SOCK_FLOAT, N_("Density")},
- {SOCK_FLOAT, N_("Flame")},
- {SOCK_FLOAT, N_("Temperature")},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_volume_info_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Density"));
+ b.add_output<decl::Float>(N_("Flame"));
+ b.add_output<decl::Float>(N_("Temperature"));
+}
static int node_shader_gpu_volume_info(GPUMaterial *mat,
bNode *UNUSED(node),
@@ -49,13 +51,17 @@ static int node_shader_gpu_volume_info(GPUMaterial *mat,
return true;
}
-void register_node_type_sh_volume_info(void)
+} // namespace blender::nodes::node_shader_volume_info_cc
+
+void register_node_type_sh_volume_info()
{
+ namespace file_ns = blender::nodes::node_shader_volume_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_INFO, "Volume Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_volume_info_out);
- node_type_gpu(&ntype, node_shader_gpu_volume_info);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_INFO, "Volume Info", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
index 1a25aec5cb8..54e92eafcf6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
@@ -17,30 +17,34 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
-
-/* **************** OUTPUT ******************** */
-
-static bNodeSocketTemplate sh_node_volume_principled_in[] = {
- {SOCK_RGBA, N_("Color"), 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
- {SOCK_STRING, N_("Color Attribute"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_STRING, N_("Density Attribute"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Anisotropy"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Absorption Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Emission Strength"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1000.0f},
- {SOCK_RGBA, N_("Emission Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Blackbody Intensity"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_RGBA, N_("Blackbody Tint"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Temperature"), 1000.0f, 0.0f, 0.0f, 0.0f, 0.0f, 6500.0f},
- {SOCK_STRING, N_("Temperature Attribute"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_volume_principled_out[] = {
- {SOCK_SHADER, N_("Volume")},
- {-1, ""},
-};
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_volume_principled_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
+ b.add_input<decl::String>(N_("Color Attribute"));
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::String>(N_("Density Attribute"));
+ b.add_input<decl::Float>(N_("Anisotropy"))
+ .default_value(0.0f)
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Absorption Color")).default_value({0.0f, 0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Emission Strength")).default_value(0.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Color>(N_("Emission Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Blackbody Intensity"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Color>(N_("Blackbody Tint")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Temperature")).default_value(1000.0f).min(0.0f).max(6500.0f);
+ b.add_input<decl::String>(N_("Temperature Attribute"));
+ b.add_output<decl::Shader>(N_("Volume"));
+}
static void node_shader_init_volume_principled(bNodeTree *UNUSED(ntree), bNode *node)
{
@@ -64,14 +68,14 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
bool use_blackbody = (in[8].link || in[8].vec[0] != 0.0f);
/* Get volume attributes. */
- GPUNodeLink *density = NULL, *color = NULL, *temperature = NULL;
+ GPUNodeLink *density = nullptr, *color = nullptr, *temperature = nullptr;
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (sock->typeinfo->type != SOCK_STRING) {
continue;
}
- bNodeSocketValueString *value = sock->default_value;
+ bNodeSocketValueString *value = (bNodeSocketValueString *)sock->default_value;
const char *attribute_name = value->value;
if (attribute_name[0] == '\0') {
continue;
@@ -106,11 +110,11 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
const int size = CM_TABLE + 1;
float *data, layer;
if (use_blackbody) {
- data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
+ data = (float *)MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
}
else {
- data = MEM_callocN(sizeof(float) * size * 4, "blackbody black");
+ data = (float *)MEM_callocN(sizeof(float) * size * 4, "blackbody black");
}
GPUNodeLink *spectrummap = GPU_color_band(mat, size, data, &layer);
@@ -126,17 +130,20 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
GPU_constant(&layer));
}
+} // namespace blender::nodes::node_shader_volume_principled_cc
+
/* node type definition */
-void register_node_type_sh_volume_principled(void)
+void register_node_type_sh_volume_principled()
{
+ namespace file_ns = blender::nodes::node_shader_volume_principled_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_PRINCIPLED, "Principled Volume", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_volume_principled_in, sh_node_volume_principled_out);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_PRINCIPLED, "Principled Volume", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, node_shader_init_volume_principled);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_volume_principled);
+ node_type_init(&ntype, file_ns::node_shader_init_volume_principled);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_principled);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc
index f4cfe7729ca..abd10cfcbcf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc
@@ -17,21 +17,21 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_volume_scatter_cc {
-static bNodeSocketTemplate sh_node_volume_scatter_in[] = {
- {SOCK_RGBA, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Anisotropy"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_volume_scatter_out[] = {
- {SOCK_SHADER, N_("Volume")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Anisotropy"))
+ .default_value(0.0f)
+ .min(-1.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_output<decl::Shader>(N_("Volume"));
+}
static int node_shader_gpu_volume_scatter(GPUMaterial *mat,
bNode *node,
@@ -42,16 +42,18 @@ static int node_shader_gpu_volume_scatter(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_volume_scatter", in, out);
}
+} // namespace blender::nodes::node_shader_volume_scatter_cc
+
/* node type definition */
-void register_node_type_sh_volume_scatter(void)
+void register_node_type_sh_volume_scatter()
{
+ namespace file_ns = blender::nodes::node_shader_volume_scatter_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_SCATTER, "Volume Scatter", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_volume_scatter_in, sh_node_volume_scatter_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_volume_scatter);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_SCATTER, "Volume Scatter", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_scatter);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_wavelength.c b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
index f978537ee85..a67c7830edd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wavelength.c
+++ b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
@@ -17,18 +17,15 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Wavelength ******************** */
-static bNodeSocketTemplate sh_node_wavelength_in[] = {
- {SOCK_FLOAT, N_("Wavelength"), 500.0f, 0.0f, 0.0f, 0.0f, 380.0f, 780.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_wavelength_cc {
-static bNodeSocketTemplate sh_node_wavelength_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Wavelength")).default_value(500.0f).min(380.0f).max(780.0f);
+ b.add_output<decl::Color>(N_("Color"));
+}
static int node_shader_gpu_wavelength(GPUMaterial *mat,
bNode *node,
@@ -37,7 +34,7 @@ static int node_shader_gpu_wavelength(GPUMaterial *mat,
GPUNodeStack *out)
{
const int size = CM_TABLE + 1;
- float *data = MEM_mallocN(sizeof(float) * size * 4, "cie_xyz texture");
+ float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "cie_xyz texture"));
wavelength_to_xyz_table(data, size);
@@ -57,17 +54,19 @@ static int node_shader_gpu_wavelength(GPUMaterial *mat,
GPU_uniform(xyz_to_rgb.b));
}
+} // namespace blender::nodes::node_shader_wavelength_cc
+
/* node type definition */
-void register_node_type_sh_wavelength(void)
+void register_node_type_sh_wavelength()
{
+ namespace file_ns = blender::nodes::node_shader_wavelength_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_WAVELENGTH, "Wavelength", NODE_CLASS_CONVERTER, 0);
+ sh_node_type_base(&ntype, SH_NODE_WAVELENGTH, "Wavelength", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_socket_templates(&ntype, sh_node_wavelength_in, sh_node_wavelength_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_wavelength);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_wavelength);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_wireframe.c b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc
index 37e60ddb205..1ba2391a09d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wireframe.c
+++ b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc
@@ -17,18 +17,23 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Wireframe ******************** */
-static bNodeSocketTemplate sh_node_wireframe_in[] = {
- {SOCK_FLOAT, N_("Size"), 0.01f, 0.0f, 0.0f, 0.0f, 0.0f, 100.0f},
- {-1, ""},
-};
+#include "UI_interface.h"
+#include "UI_resources.h"
-static bNodeSocketTemplate sh_node_wireframe_out[] = {
- {SOCK_FLOAT, N_("Fac"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_wireframe_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Size")).default_value(0.01f).min(0.0f).max(100.0f);
+ b.add_output<decl::Float>(N_("Fac"));
+}
+
+static void node_shader_buts_wireframe(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_pixel_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, 0);
+}
static int node_shader_gpu_wireframe(GPUMaterial *mat,
bNode *node,
@@ -52,16 +57,19 @@ static int node_shader_gpu_wireframe(GPUMaterial *mat,
GPU_builtin(GPU_BARYCENTRIC_DIST));
}
+} // namespace blender::nodes::node_shader_wireframe_cc
+
/* node type definition */
-void register_node_type_sh_wireframe(void)
+void register_node_type_sh_wireframe()
{
+ namespace file_ns = blender::nodes::node_shader_wireframe_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_WIREFRAME, "Wireframe", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_wireframe_in, sh_node_wireframe_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_wireframe);
+ sh_node_type_base(&ntype, SH_NODE_WIREFRAME, "Wireframe", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.draw_buttons = file_ns::node_shader_buts_wireframe;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_wireframe);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/CMakeLists.txt b/source/blender/nodes/texture/CMakeLists.txt
new file mode 100644
index 00000000000..053b17e4e57
--- /dev/null
+++ b/source/blender/nodes/texture/CMakeLists.txt
@@ -0,0 +1,89 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../
+ ../intern
+ ../../editors/include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../depsgraph
+ ../../imbuf
+ ../../makesdna
+ ../../makesrna
+ ../../render
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+
+set(SRC
+ nodes/node_texture_at.c
+ nodes/node_texture_bricks.c
+ nodes/node_texture_checker.c
+ nodes/node_texture_common.c
+ nodes/node_texture_compose.c
+ nodes/node_texture_coord.c
+ nodes/node_texture_curves.c
+ nodes/node_texture_decompose.c
+ nodes/node_texture_distance.c
+ nodes/node_texture_hueSatVal.c
+ nodes/node_texture_image.c
+ nodes/node_texture_invert.c
+ nodes/node_texture_math.c
+ nodes/node_texture_mixRgb.c
+ nodes/node_texture_output.c
+ nodes/node_texture_proc.c
+ nodes/node_texture_rotate.c
+ nodes/node_texture_scale.c
+ nodes/node_texture_texture.c
+ nodes/node_texture_translate.c
+ nodes/node_texture_valToNor.c
+ nodes/node_texture_valToRgb.c
+ nodes/node_texture_viewer.c
+ node_texture_tree.c
+ node_texture_util.c
+
+ node_texture_util.h
+)
+
+set(LIB
+ bf_nodes
+)
+
+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()
+
+blender_add_lib(bf_nodes_texture "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 14597050524..82ed43be779 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -50,6 +50,8 @@
#include "RE_texture.h"
+#include "UI_resources.h"
+
static void texture_get_from_context(const bContext *C,
bNodeTreeType *UNUSED(treetype),
bNodeTree **r_ntree,
@@ -132,24 +134,9 @@ static void localize(bNodeTree *UNUSED(localtree), bNodeTree *UNUSED(ntree))
}
#endif
-static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_sync_tree(ntree, localtree);
-}
-
-static void local_merge(Main *UNUSED(bmain), bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_merge_tree(ntree, localtree, true);
-}
-
static void update(bNodeTree *ntree)
{
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
static bool texture_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
@@ -169,14 +156,12 @@ void register_node_tree_type_tex(void)
tt->type = NTREE_TEXTURE;
strcpy(tt->idname, "TextureNodeTree");
strcpy(tt->ui_name, N_("Texture Node Editor"));
- tt->ui_icon = 0; /* Defined in `drawnode.c`. */
+ tt->ui_icon = ICON_NODE_TEXTURE; /* Defined in `drawnode.c`. */
strcpy(tt->ui_description, N_("Texture nodes"));
tt->foreach_nodeclass = foreach_nodeclass;
tt->update = update;
tt->localize = localize;
- tt->local_sync = local_sync;
- tt->local_merge = local_merge;
tt->get_from_context = texture_get_from_context;
tt->valid_socket_type = texture_node_tree_socket_type_valid;
@@ -185,6 +170,63 @@ void register_node_tree_type_tex(void)
ntreeTypeAdd(tt);
}
+/**** Material/Texture trees ****/
+
+bNodeThreadStack *ntreeGetThreadStack(bNodeTreeExec *exec, int thread)
+{
+ ListBase *lb = &exec->threadstack[thread];
+ bNodeThreadStack *nts;
+
+ for (nts = (bNodeThreadStack *)lb->first; nts; nts = nts->next) {
+ if (!nts->used) {
+ nts->used = true;
+ break;
+ }
+ }
+
+ if (!nts) {
+ nts = MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack");
+ nts->stack = (bNodeStack *)MEM_dupallocN(exec->stack);
+ nts->used = true;
+ BLI_addtail(lb, nts);
+ }
+
+ return nts;
+}
+
+void ntreeReleaseThreadStack(bNodeThreadStack *nts)
+{
+ nts->used = false;
+}
+
+bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *callerdata, int thread)
+{
+ bNodeStack *nsin[MAX_SOCKET] = {NULL}; /* arbitrary... watch this */
+ bNodeStack *nsout[MAX_SOCKET] = {NULL}; /* arbitrary... watch this */
+ bNodeExec *nodeexec;
+ bNode *node;
+ int n;
+
+ /* nodes are presorted, so exec is in order of list */
+
+ for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) {
+ node = nodeexec->node;
+ if (node->need_exec) {
+ node_get_stack(node, nts->stack, nsin, nsout);
+ /* Handle muted nodes...
+ * If the mute func is not set, assume the node should never be muted,
+ * and hence execute it!
+ */
+ if (node->typeinfo->exec_fn && !(node->flag & NODE_MUTED)) {
+ node->typeinfo->exec_fn(callerdata, thread, node, &nodeexec->data, nsin, nsout);
+ }
+ }
+ }
+
+ /* signal to that all went OK, for render */
+ return true;
+}
+
bNodeTreeExec *ntreeTexBeginExecTree_internal(bNodeExecContext *context,
bNodeTree *ntree,
bNodeInstanceKey parent_key)
diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c
index fe8e68bfc42..dc5e2bfcd6b 100644
--- a/source/blender/nodes/texture/node_texture_util.c
+++ b/source/blender/nodes/texture/node_texture_util.c
@@ -50,10 +50,9 @@ bool tex_node_poll_default(bNodeType *UNUSED(ntype),
return true;
}
-void tex_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = tex_node_poll_default;
ntype->insert_link = node_insert_link_default;
@@ -63,10 +62,6 @@ static void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, sh
{
if (dg->node->need_exec) {
dg->fn(out, params, dg->node, dg->in, thread);
-
- if (dg->cdata->do_preview) {
- tex_do_preview(dg->preview, params->previewco, out, dg->cdata->do_manage);
- }
}
}
@@ -123,19 +118,6 @@ void params_from_cdata(TexParams *out, TexCallData *in)
out->mtex = in->mtex;
}
-void tex_do_preview(bNodePreview *preview,
- const float coord[2],
- const float col[4],
- bool do_manage)
-{
- if (preview) {
- int xs = ((coord[0] + 1.0f) * 0.5f) * preview->xsize;
- int ys = ((coord[1] + 1.0f) * 0.5f) * preview->ysize;
-
- BKE_node_preview_set_pixel(preview, col, xs, ys, do_manage);
- }
-}
-
void tex_output(bNode *node,
bNodeExecData *execdata,
bNodeStack **in,
diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h
index 84d2c5c903a..7c8e39925bc 100644
--- a/source/blender/nodes/texture/node_texture_util.h
+++ b/source/blender/nodes/texture/node_texture_util.h
@@ -108,8 +108,7 @@ typedef struct TexDelegate {
bool tex_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
-void tex_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
void tex_input_rgba(float *out, bNodeStack *in, TexParams *params, short thread);
void tex_input_vec(float *out, bNodeStack *in, TexParams *params, short thread);
@@ -121,13 +120,21 @@ void tex_output(bNode *node,
bNodeStack *out,
TexFn texfn,
TexCallData *data);
-void tex_do_preview(bNodePreview *preview,
- const float coord[2],
- const float col[4],
- bool do_manage);
void params_from_cdata(TexParams *out, TexCallData *in);
+struct bNodeThreadStack *ntreeGetThreadStack(struct bNodeTreeExec *exec, int thread);
+void ntreeReleaseThreadStack(struct bNodeThreadStack *nts);
+bool ntreeExecThreadNodes(struct bNodeTreeExec *exec,
+ struct bNodeThreadStack *nts,
+ void *callerdata,
+ int thread);
+
+struct bNodeTreeExec *ntreeTexBeginExecTree_internal(struct bNodeExecContext *context,
+ struct bNodeTree *ntree,
+ bNodeInstanceKey parent_key);
+void ntreeTexEndExecTree_internal(struct bNodeTreeExec *exec);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/nodes/texture/nodes/node_texture_at.c b/source/blender/nodes/texture/nodes/node_texture_at.c
index a6f8d28db75..41dea303ea2 100644
--- a/source/blender/nodes/texture/nodes/node_texture_at.c
+++ b/source/blender/nodes/texture/nodes/node_texture_at.c
@@ -58,7 +58,7 @@ void register_node_type_tex_at(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_AT, "At", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_AT, "At", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size(&ntype, 140, 100, 320);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_bricks.c b/source/blender/nodes/texture/nodes/node_texture_bricks.c
index 72690d6ccfe..0dc92dc33d0 100644
--- a/source/blender/nodes/texture/nodes/node_texture_bricks.c
+++ b/source/blender/nodes/texture/nodes/node_texture_bricks.c
@@ -119,11 +119,12 @@ void register_node_type_tex_bricks(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_BRICKS, "Bricks", NODE_CLASS_PATTERN, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_BRICKS, "Bricks", NODE_CLASS_PATTERN);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, init);
node_type_exec(&ntype, NULL, NULL, exec);
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_checker.c b/source/blender/nodes/texture/nodes/node_texture_checker.c
index e3c4d44e7f5..62657cd7def 100644
--- a/source/blender/nodes/texture/nodes/node_texture_checker.c
+++ b/source/blender/nodes/texture/nodes/node_texture_checker.c
@@ -70,9 +70,10 @@ void register_node_type_tex_checker(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_CHECKER, "Checker", NODE_CLASS_PATTERN, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_CHECKER, "Checker", NODE_CLASS_PATTERN);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c
index f873ed5e457..d68cfe78b44 100644
--- a/source/blender/nodes/texture/nodes/node_texture_common.c
+++ b/source/blender/nodes/texture/nodes/node_texture_common.c
@@ -161,7 +161,7 @@ void register_node_type_tex_group(void)
/* NOTE: Cannot use #sh_node_type_base for node group, because it would map the node type
* to the shared #NODE_GROUP integer type id. */
- node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, 0);
+ node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP);
ntype.type = NODE_GROUP;
ntype.poll = tex_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
@@ -170,7 +170,6 @@ void register_node_type_tex_group(void)
BLI_assert(ntype.rna_ext.srna != NULL);
RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
- node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
diff --git a/source/blender/nodes/texture/nodes/node_texture_compose.c b/source/blender/nodes/texture/nodes/node_texture_compose.c
index ffa0e9ae43e..cd918ca8314 100644
--- a/source/blender/nodes/texture/nodes/node_texture_compose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_compose.c
@@ -58,7 +58,7 @@ void register_node_type_tex_compose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_coord.c b/source/blender/nodes/texture/nodes/node_texture_coord.c
index 5a0cf5eb497..e31fdcafbf2 100644
--- a/source/blender/nodes/texture/nodes/node_texture_coord.c
+++ b/source/blender/nodes/texture/nodes/node_texture_coord.c
@@ -49,9 +49,8 @@ void register_node_type_tex_coord(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_COORD, "Coordinates", NODE_CLASS_INPUT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_COORD, "Coordinates", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, NULL, outputs);
- node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/texture/nodes/node_texture_curves.c b/source/blender/nodes/texture/nodes/node_texture_curves.c
index f61e3f36db5..7fed45c5558 100644
--- a/source/blender/nodes/texture/nodes/node_texture_curves.c
+++ b/source/blender/nodes/texture/nodes/node_texture_curves.c
@@ -65,7 +65,7 @@ void register_node_type_tex_curve_time(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_CURVE_TIME, "Time", NODE_CLASS_INPUT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_CURVE_TIME, "Time", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, NULL, time_outputs);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, time_init);
@@ -114,7 +114,7 @@ void register_node_type_tex_curve_rgb(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, rgb_inputs, rgb_outputs);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, rgb_init);
diff --git a/source/blender/nodes/texture/nodes/node_texture_decompose.c b/source/blender/nodes/texture/nodes/node_texture_decompose.c
index 83922ea03ab..9c3cb6911e1 100644
--- a/source/blender/nodes/texture/nodes/node_texture_decompose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_decompose.c
@@ -78,7 +78,7 @@ void register_node_type_tex_decompose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_distance.c b/source/blender/nodes/texture/nodes/node_texture_distance.c
index c2241858737..2f8b28722bd 100644
--- a/source/blender/nodes/texture/nodes/node_texture_distance.c
+++ b/source/blender/nodes/texture/nodes/node_texture_distance.c
@@ -60,9 +60,8 @@ void register_node_type_tex_distance(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, inputs, outputs);
- node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
index 759fb3d43d5..f405c3b0bec 100644
--- a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
+++ b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
@@ -107,7 +107,7 @@ void register_node_type_tex_hue_sat(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c
index 9c61405ea23..18ae3609407 100644
--- a/source/blender/nodes/texture/nodes/node_texture_image.c
+++ b/source/blender/nodes/texture/nodes/node_texture_image.c
@@ -108,12 +108,13 @@ void register_node_type_tex_image(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_IMAGE, "Image", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, NULL, outputs);
node_type_init(&ntype, init);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
node_type_exec(&ntype, NULL, NULL, exec);
ntype.labelfunc = node_image_label;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_invert.c b/source/blender/nodes/texture/nodes/node_texture_invert.c
index 5d3f86c5c9c..7854ac4b5b8 100644
--- a/source/blender/nodes/texture/nodes/node_texture_invert.c
+++ b/source/blender/nodes/texture/nodes/node_texture_invert.c
@@ -63,7 +63,7 @@ void register_node_type_tex_invert(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c
index 9e37f4ee643..2f50f6aaae0 100644
--- a/source/blender/nodes/texture/nodes/node_texture_math.c
+++ b/source/blender/nodes/texture/nodes/node_texture_math.c
@@ -335,10 +335,9 @@ void register_node_type_tex_math(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, inputs, outputs);
ntype.labelfunc = node_math_label;
- node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
node_type_update(&ntype, node_math_update);
diff --git a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
index 044875cce90..5599807d8b1 100644
--- a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
@@ -69,7 +69,7 @@ void register_node_type_tex_mix_rgb(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
ntype.labelfunc = node_blend_label;
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c
index 19e24c9f82a..4911ab7ba9e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_output.c
+++ b/source/blender/nodes/texture/nodes/node_texture_output.c
@@ -37,7 +37,7 @@ static bNodeSocketTemplate inputs[] = {
static void exec(void *data,
int UNUSED(thread),
bNode *node,
- bNodeExecData *execdata,
+ bNodeExecData *UNUSED(execdata),
bNodeStack **in,
bNodeStack **UNUSED(out))
{
@@ -54,7 +54,6 @@ static void exec(void *data,
else {
tex_input_rgba(&target->tr, in[0], &params, cdata->thread);
}
- tex_do_preview(execdata->preview, params.co, &target->tr, cdata->do_manage);
}
else {
/* 0 means don't care, so just use first */
@@ -167,13 +166,14 @@ void register_node_type_tex_output(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT);
node_type_socket_templates(&ntype, inputs, NULL);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, init);
node_type_storage(&ntype, "TexNodeOutput", node_free_standard_storage, copy);
node_type_exec(&ntype, NULL, NULL, exec);
+ ntype.flag |= NODE_PREVIEW;
ntype.no_muting = true;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c
index a8a82153e58..8c294b5954d 100644
--- a/source/blender/nodes/texture/nodes/node_texture_proc.c
+++ b/source/blender/nodes/texture/nodes/node_texture_proc.c
@@ -294,12 +294,13 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
{ \
static bNodeType ntype; \
\
- tex_node_type_base(&ntype, TEX_NODE_PROC + TEXTYPE, Name, NODE_CLASS_TEXTURE, NODE_PREVIEW); \
+ tex_node_type_base(&ntype, TEX_NODE_PROC + TEXTYPE, Name, NODE_CLASS_TEXTURE); \
node_type_socket_templates(&ntype, name##_inputs, outputs); \
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); \
node_type_init(&ntype, init); \
node_type_storage(&ntype, "Tex", node_free_standard_storage, node_copy_standard_storage); \
node_type_exec(&ntype, NULL, NULL, name##_exec); \
+ ntype.flag |= NODE_PREVIEW; \
\
nodeRegisterType(&ntype); \
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_rotate.c b/source/blender/nodes/texture/nodes/node_texture_rotate.c
index 9985499772e..18024a4d41d 100644
--- a/source/blender/nodes/texture/nodes/node_texture_rotate.c
+++ b/source/blender/nodes/texture/nodes/node_texture_rotate.c
@@ -95,7 +95,7 @@ void register_node_type_tex_rotate(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_scale.c b/source/blender/nodes/texture/nodes/node_texture_scale.c
index d23b1b4d037..d570c73a67b 100644
--- a/source/blender/nodes/texture/nodes/node_texture_scale.c
+++ b/source/blender/nodes/texture/nodes/node_texture_scale.c
@@ -68,7 +68,7 @@ void register_node_type_tex_scale(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_SCALE, "Scale", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_texture.c b/source/blender/nodes/texture/nodes/node_texture_texture.c
index 59e2e9be581..083ae67ccb6 100644
--- a/source/blender/nodes/texture/nodes/node_texture_texture.c
+++ b/source/blender/nodes/texture/nodes/node_texture_texture.c
@@ -94,9 +94,10 @@ void register_node_type_tex_texture(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_translate.c b/source/blender/nodes/texture/nodes/node_texture_translate.c
index 2eef3132a18..732cd0a89a1 100644
--- a/source/blender/nodes/texture/nodes/node_texture_translate.c
+++ b/source/blender/nodes/texture/nodes/node_texture_translate.c
@@ -64,7 +64,7 @@ void register_node_type_tex_translate(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_valToNor.c b/source/blender/nodes/texture/nodes/node_texture_valToNor.c
index 5ccd44b8bf0..3f0d4fb668e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_valToNor.c
+++ b/source/blender/nodes/texture/nodes/node_texture_valToNor.c
@@ -80,7 +80,7 @@ void register_node_type_tex_valtonor(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
index 2446ef05e0c..844a4188663 100644
--- a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
@@ -63,7 +63,7 @@ void register_node_type_tex_valtorgb(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, valtorgb_in, valtorgb_out);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, valtorgb_init);
@@ -105,7 +105,7 @@ void register_node_type_tex_rgbtobw(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, rgbtobw_in, rgbtobw_out);
node_type_exec(&ntype, NULL, NULL, rgbtobw_exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_viewer.c b/source/blender/nodes/texture/nodes/node_texture_viewer.c
index 18b11b86d6f..ea69de9a1d6 100644
--- a/source/blender/nodes/texture/nodes/node_texture_viewer.c
+++ b/source/blender/nodes/texture/nodes/node_texture_viewer.c
@@ -29,14 +29,11 @@ static bNodeSocketTemplate inputs[] = {
{SOCK_RGBA, N_("Color"), 1.0f, 0.0f, 0.0f, 1.0f},
{-1, ""},
};
-static bNodeSocketTemplate outputs[] = {
- {-1, ""},
-};
static void exec(void *data,
int UNUSED(thread),
bNode *UNUSED(node),
- bNodeExecData *execdata,
+ bNodeExecData *UNUSED(execdata),
bNodeStack **in,
bNodeStack **UNUSED(out))
{
@@ -48,7 +45,6 @@ static void exec(void *data,
params_from_cdata(&params, cdata);
tex_input_rgba(col, in[0], &params, cdata->thread);
- tex_do_preview(execdata->preview, params.previewco, col, cdata->do_manage);
}
}
@@ -56,11 +52,12 @@ void register_node_type_tex_viewer(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
- node_type_socket_templates(&ntype, inputs, outputs);
+ tex_node_type_base(&ntype, TEX_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT);
+ node_type_socket_templates(&ntype, inputs, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
ntype.no_muting = true;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index e233a078ea9..b6604846bb8 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -81,7 +81,7 @@ void BPY_text_free_code(struct Text *text);
void BPY_modules_update(void);
void BPY_modules_load_user(struct bContext *C);
-void BPY_app_handlers_reset(const short do_all);
+void BPY_app_handlers_reset(short do_all);
/**
* Update function, it gets rid of py-drivers global dictionary, forcing
diff --git a/source/blender/python/BPY_extern_run.h b/source/blender/python/BPY_extern_run.h
index 30740d7fb60..9088a4b89c0 100644
--- a/source/blender/python/BPY_extern_run.h
+++ b/source/blender/python/BPY_extern_run.h
@@ -88,10 +88,8 @@ bool BPY_run_filepath(struct bContext *C, const char *filepath, struct ReportLis
* 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) ATTR_NONNULL(1, 2);
+bool BPY_run_text(struct bContext *C, struct Text *text, struct ReportList *reports, bool do_jump)
+ ATTR_NONNULL(1, 2);
/** \} */
diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h
index 42d1fee31c3..3786a0552d2 100644
--- a/source/blender/python/bmesh/bmesh_py_types.h
+++ b/source/blender/python/bmesh/bmesh_py_types.h
@@ -141,7 +141,7 @@ PyObject *BPy_BMVert_CreatePyObject(BMesh *bm, BMVert *v);
PyObject *BPy_BMEdge_CreatePyObject(BMesh *bm, BMEdge *e);
PyObject *BPy_BMFace_CreatePyObject(BMesh *bm, BMFace *f);
PyObject *BPy_BMLoop_CreatePyObject(BMesh *bm, BMLoop *l);
-PyObject *BPy_BMElemSeq_CreatePyObject(BMesh *bm, BPy_BMElem *py_ele, const char itype);
+PyObject *BPy_BMElemSeq_CreatePyObject(BMesh *bm, BPy_BMElem *py_ele, char itype);
PyObject *BPy_BMVertSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMEdgeSeq_CreatePyObject(BMesh *bm);
PyObject *BPy_BMFaceSeq_CreatePyObject(BMesh *bm);
@@ -162,18 +162,18 @@ void *BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm,
Py_ssize_t min,
Py_ssize_t max,
Py_ssize_t *r_size,
- const char htype,
- const bool do_unique_check,
- const bool do_bm_check,
+ char htype,
+ bool do_unique_check,
+ bool do_bm_check,
const char *error_prefix);
void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm,
PyObject *seq,
Py_ssize_t min,
Py_ssize_t max,
Py_ssize_t *r_size,
- const char htype,
- const bool do_unique_check,
- const bool do_bm_check,
+ char htype,
+ bool do_unique_check,
+ bool do_bm_check,
const char *error_prefix);
PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len);
@@ -182,14 +182,14 @@ PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_le
PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_len);
PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop **elem, Py_ssize_t elem_len);
-int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype);
+int BPy_BMElem_CheckHType(PyTypeObject *type, 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);
+char *BPy_BMElem_StringFromHType_ex(char htype, char ret[32]);
+char *BPy_BMElem_StringFromHType(char htype);
// void bpy_bm_generic_invalidate(BPy_BMGeneric *self);
int bpy_bm_generic_valid_check(BPy_BMGeneric *self);
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.h b/source/blender/python/bmesh/bmesh_py_types_customdata.h
index a5555a14ad7..d81e149cac1 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.h
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.h
@@ -61,9 +61,9 @@ typedef struct BPy_BMLayerItem {
int index; /* index of this layer type */
} BPy_BMLayerItem;
-PyObject *BPy_BMLayerAccess_CreatePyObject(BMesh *bm, const char htype);
-PyObject *BPy_BMLayerCollection_CreatePyObject(BMesh *bm, const char htype, int type);
-PyObject *BPy_BMLayerItem_CreatePyObject(BMesh *bm, const char htype, int type, int index);
+PyObject *BPy_BMLayerAccess_CreatePyObject(BMesh *bm, char htype);
+PyObject *BPy_BMLayerCollection_CreatePyObject(BMesh *bm, char htype, int type);
+PyObject *BPy_BMLayerItem_CreatePyObject(BMesh *bm, char htype, int type, int index);
void BPy_BM_init_types_customdata(void);
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index f6d8d7298af..f08665d75e7 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -57,31 +57,31 @@ void PyC_Err_PrintWithFunc(PyObject *py_func);
void PyC_FileAndNum(const char **r_filename, int *r_lineno);
void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno); /* checks python is running */
int PyC_AsArray_FAST(void *array,
- const size_t array_item_size,
+ size_t array_item_size,
PyObject *value_fast,
- const Py_ssize_t length,
+ Py_ssize_t length,
const PyTypeObject *type,
const char *error_prefix);
int PyC_AsArray(void *array,
- const size_t array_item_size,
+ size_t array_item_size,
PyObject *value,
- const Py_ssize_t length,
+ Py_ssize_t length,
const PyTypeObject *type,
const char *error_prefix);
int PyC_AsArray_Multi_FAST(void *array,
- const size_t array_item_size,
+ size_t array_item_size,
PyObject *value_fast,
const int *dims,
- const int dims_len,
+ int dims_len,
const PyTypeObject *type,
const char *error_prefix);
int PyC_AsArray_Multi(void *array,
- const size_t array_item_size,
+ size_t array_item_size,
PyObject *value,
const int *dims,
- const int dims_len,
+ int dims_len,
const PyTypeObject *type,
const char *error_prefix);
@@ -102,10 +102,10 @@ PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len);
#define PyC_Tuple_Pack_Bool(...) \
PyC_Tuple_PackArray_Bool(((const bool[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
-PyObject *PyC_Tuple_PackArray_Multi_F32(const float *array, const int dims[], const int dims_len);
-PyObject *PyC_Tuple_PackArray_Multi_F64(const double *array, const int dims[], const int dims_len);
-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);
+PyObject *PyC_Tuple_PackArray_Multi_F32(const float *array, const int dims[], int dims_len);
+PyObject *PyC_Tuple_PackArray_Multi_F64(const double *array, const int dims[], int dims_len);
+PyObject *PyC_Tuple_PackArray_Multi_I32(const int *array, const int dims[], int dims_len);
+PyObject *PyC_Tuple_PackArray_Multi_Bool(const bool *array, const int dims[], int dims_len);
/**
* Caller needs to ensure tuple is uninitialized.
@@ -219,8 +219,7 @@ struct PyC_StringEnum {
* 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);
+const char *PyC_StringEnum_FindIDFromValue(const struct PyC_StringEnumItems *items, int value);
int PyC_CheckArgs_DeepCopy(PyObject *args);
diff --git a/source/blender/python/gpu/gpu_py_buffer.h b/source/blender/python/gpu/gpu_py_buffer.h
index cbc46339628..3dcf335230d 100644
--- a/source/blender/python/gpu/gpu_py_buffer.h
+++ b/source/blender/python/gpu/gpu_py_buffer.h
@@ -55,7 +55,7 @@ size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer);
* \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,
+BPyGPUBuffer *BPyGPU_Buffer_CreatePyObject(int format,
const Py_ssize_t *shape,
- const int shape_len,
+ int shape_len,
void *buffer);
diff --git a/source/blender/python/gpu/gpu_py_framebuffer.c b/source/blender/python/gpu/gpu_py_framebuffer.c
index a9347b71723..412fcac02ca 100644
--- a/source/blender/python/gpu/gpu_py_framebuffer.c
+++ b/source/blender/python/gpu/gpu_py_framebuffer.c
@@ -530,6 +530,7 @@ static PyObject *pygpu_framebuffer_read_color(BPyGPUFrameBuffer *self,
PyErr_SetString(PyExc_BufferError, "the buffer size is smaller than expected");
return NULL;
}
+ Py_INCREF(py_buffer);
}
else {
py_buffer = BPyGPU_Buffer_CreatePyObject(
@@ -590,6 +591,7 @@ static PyObject *pygpu_framebuffer_read_depth(BPyGPUFrameBuffer *self,
PyErr_SetString(PyExc_BufferError, "the buffer size is smaller than expected");
return NULL;
}
+ Py_INCREF(py_buffer);
}
else {
py_buffer = BPyGPU_Buffer_CreatePyObject(GPU_DATA_FLOAT, (Py_ssize_t[]){h, w}, 2, NULL);
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index 48fbe09f0ce..19013dc9ca3 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -65,6 +65,14 @@
/** \name GPUOffScreen Common Utilities
* \{ */
+static const struct PyC_StringEnumItems pygpu_framebuffer_color_texture_formats[] = {
+ {GPU_RGBA8, "RGBA8"},
+ {GPU_RGBA16, "RGBA16"},
+ {GPU_RGBA16F, "RGBA16F"},
+ {GPU_RGBA32F, "RGBA32F"},
+ {0, NULL},
+};
+
static int pygpu_offscreen_valid_check(BPyGPUOffScreen *py_ofs)
{
if (UNLIKELY(py_ofs->ofs == NULL)) {
@@ -219,16 +227,18 @@ static PyObject *pygpu_offscreen__tp_new(PyTypeObject *UNUSED(self),
GPUOffScreen *ofs = NULL;
int width, height;
+ struct PyC_StringEnum pygpu_textureformat = {pygpu_framebuffer_color_texture_formats, GPU_RGBA8};
char err_out[256];
- static const char *_keywords[] = {"width", "height", NULL};
- static _PyArg_Parser _parser = {"ii:GPUOffScreen.__new__", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &width, &height)) {
+ static const char *_keywords[] = {"width", "height", "format", NULL};
+ static _PyArg_Parser _parser = {"ii|$O&:GPUOffScreen.__new__", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser, &width, &height, PyC_ParseStringEnum, &pygpu_textureformat)) {
return NULL;
}
if (GPU_context_active_get()) {
- ofs = GPU_offscreen_create(width, height, true, GPU_RGBA8, err_out);
+ ofs = GPU_offscreen_create(width, height, true, pygpu_textureformat.value_found, err_out);
}
else {
STRNCPY(err_out, "No active GPU context found");
@@ -456,14 +466,21 @@ static struct PyMethodDef pygpu_offscreen__tp_methods[] = {
};
PyDoc_STRVAR(pygpu_offscreen__tp_doc,
- ".. class:: GPUOffScreen(width, height)\n"
+ ".. class:: GPUOffScreen(width, height, *, format='RGBA8')\n"
"\n"
" This object gives access to off screen buffers.\n"
"\n"
" :arg width: Horizontal dimension of the buffer.\n"
" :type width: int\n"
" :arg height: Vertical dimension of the buffer.\n"
- " :type height: int\n");
+ " :type height: int\n"
+ " :arg format: Internal data format inside GPU memory for color attachment "
+ "texture. Possible values are:\n"
+ " `RGBA8`,\n"
+ " `RGBA16`,\n"
+ " `RGBA16F`,\n"
+ " `RGBA32F`,\n"
+ " :type format: str\n");
PyTypeObject BPyGPUOffScreen_Type = {
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUOffScreen",
.tp_basicsize = sizeof(BPyGPUOffScreen),
diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c
index 949086378a8..bb762f9fe33 100644
--- a/source/blender/python/gpu/gpu_py_vertex_buffer.c
+++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c
@@ -99,7 +99,7 @@ static void pygpu_fill_format_sequence(void *data_dst_void,
PyObject **value_fast_items = PySequence_Fast_ITEMS(py_seq_fast);
/**
- * Args are constants, so range checks will be optimized out if they're nop's.
+ * Args are constants, so range checks will be optimized out if they're no-op's.
*/
#define PY_AS_NATIVE(ty_dst, py_as_native) \
ty_dst *data_dst = data_dst_void; \
diff --git a/source/blender/python/intern/bpy_capi_utils.h b/source/blender/python/intern/bpy_capi_utils.h
index 0e4a28fb657..0889dec36c8 100644
--- a/source/blender/python/intern/bpy_capi_utils.h
+++ b/source/blender/python/intern/bpy_capi_utils.h
@@ -32,15 +32,15 @@ struct EnumPropertyItem;
struct ReportList;
/* error reporting */
-short BPy_reports_to_error(struct ReportList *reports, PyObject *exception, const bool clear);
+short BPy_reports_to_error(struct ReportList *reports, PyObject *exception, 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,
- const bool use_full,
- const bool use_location);
+ bool use_full,
+ bool use_location);
bool BPy_errors_to_report_brief_with_prefix(struct ReportList *reports, const char *error_prefix);
bool BPy_errors_to_report(struct ReportList *reports);
diff --git a/source/blender/python/intern/bpy_interface_run.c b/source/blender/python/intern/bpy_interface_run.c
index bc21c91074f..79744090cc3 100644
--- a/source/blender/python/intern/bpy_interface_run.c
+++ b/source/blender/python/intern/bpy_interface_run.c
@@ -180,7 +180,7 @@ static bool python_script_exec(
if (!py_result) {
if (text) {
if (do_jump) {
- /* ensure text is valid before use, the script may have freed its self */
+ /* ensure text is valid before use, the script may have freed itself */
Main *bmain_new = CTX_data_main(C);
if ((bmain_old == bmain_new) && (BLI_findindex(&bmain_new->texts, text) != -1)) {
python_script_error_jump_text(text);
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index ae42af7cd85..a86c2e3a35e 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -401,7 +401,7 @@ static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args)
return NULL;
}
- /* WM_operator_properties_create(&ptr, opname); */
+ // WM_operator_properties_create(&ptr, opname);
/* Save another lookup */
RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index ed9547ee13f..fe7183441d1 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -2609,7 +2609,9 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
" :type step: int\n"
#define BPY_PROPDEF_FLOAT_PREC_DOC \
- " :arg precision: Maximum number of decimal digits to display, in [0, 6].\n" \
+ " :arg precision: Maximum number of decimal digits to display, in [0, 6]. Fraction is " \
+ "automatically hidden for exact integer values of fields with unit 'NONE' or 'TIME' (frame " \
+ "count) and step divisible by 100.\n" \
" :type precision: int\n"
#define BPY_PROPDEF_UPDATE_DOC \
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index f6a05a86311..b131aed6d23 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -178,7 +178,7 @@ typedef struct {
} BPy_FunctionRNA;
StructRNA *srna_from_self(PyObject *self, const char *error_prefix);
-StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *error_prefix);
+StructRNA *pyrna_struct_as_srna(PyObject *self, bool parent, const char *error_prefix);
void BPY_rna_init(void);
void BPY_rna_exit(void);
@@ -196,10 +196,7 @@ bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id);
bool pyrna_id_CheckPyObject(PyObject *obj);
/* operators also need this to set args */
-int pyrna_pydict_to_props(PointerRNA *ptr,
- PyObject *kw,
- const bool all_args,
- const char *error_prefix);
+int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, bool all_args, const char *error_prefix);
PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop);
int pyrna_deferred_register_class(struct StructRNA *srna, PyTypeObject *py_class);
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 270c9ad431c..f3b1e357ebc 100644
--- a/source/blender/python/intern/bpy_rna_array.c
+++ b/source/blender/python/intern/bpy_rna_array.c
@@ -126,7 +126,7 @@ static int validate_array_type(PyObject *seq,
ok = 0;
}
else if ((item_seq_size = PySequence_Size(item)) == -1) {
- /* BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str); */
+ // BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str);
PyErr_Format(PyExc_TypeError,
"%s expected a sequence of %s, not %s",
error_prefix,
diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c
index c19d9ba47b1..16ea4bf3e5e 100644
--- a/source/blender/python/intern/bpy_rna_callback.c
+++ b/source/blender/python/intern/bpy_rna_callback.c
@@ -255,6 +255,9 @@ static eSpace_Type rna_Space_refine_reverse(StructRNA *srna)
if (srna == &RNA_SpaceClipEditor) {
return SPACE_CLIP;
}
+ if (srna == &RNA_SpaceSpreadsheet) {
+ return SPACE_SPREADSHEET;
+ }
return SPACE_EMPTY;
}
@@ -380,6 +383,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
void *handle;
StructRNA *srna;
bool capsule_clear = false;
+ bool handle_removed = false;
if (PyTuple_GET_SIZE(args) < 2) {
PyErr_SetString(PyExc_ValueError, "callback_remove(handler): expected at least 2 args");
@@ -403,7 +407,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
args, "OO!:WindowManager.draw_cursor_remove", &cls, &PyCapsule_Type, &py_handle)) {
return NULL;
}
- WM_paint_cursor_end(handle);
+ handle_removed = WM_paint_cursor_end(handle);
capsule_clear = true;
}
else if (RNA_struct_is_a(srna, &RNA_Space)) {
@@ -442,7 +446,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
params.region_type_enum.value_orig);
return NULL;
}
- ED_region_draw_cb_exit(art, handle);
+ handle_removed = ED_region_draw_cb_exit(art, handle);
capsule_clear = true;
}
else {
@@ -450,9 +454,14 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
return NULL;
}
- /* The handle has been removed, so decrement its customdata. */
- PyObject *handle_args = PyCapsule_GetContext(py_handle);
- Py_DECREF(handle_args);
+ /* When `handle_removed == false`: Blender has already freed the data
+ * (freeing screen data when loading a new file for example).
+ * This will have already decremented the user, so don't decrement twice. */
+ if (handle_removed == true) {
+ /* The handle has been removed, so decrement its custom-data. */
+ PyObject *handle_args = PyCapsule_GetContext(py_handle);
+ Py_DECREF(handle_args);
+ }
/* don't allow reuse */
if (capsule_clear) {
diff --git a/source/blender/python/intern/bpy_rna_gizmo.c b/source/blender/python/intern/bpy_rna_gizmo.c
index e4fb5b33e97..e769fe7f4c2 100644
--- a/source/blender/python/intern/bpy_rna_gizmo.c
+++ b/source/blender/python/intern/bpy_rna_gizmo.c
@@ -201,7 +201,7 @@ fail:
PyErr_Print();
PyErr_Clear();
- Py_DECREF(ret);
+ Py_XDECREF(ret);
PyGILState_Release(gilstate);
}
diff --git a/source/blender/python/intern/bpy_rna_operator.c b/source/blender/python/intern/bpy_rna_operator.c
index d3ec54fc12d..d24e2a77a75 100644
--- a/source/blender/python/intern/bpy_rna_operator.c
+++ b/source/blender/python/intern/bpy_rna_operator.c
@@ -103,7 +103,7 @@ PyDoc_STRVAR(BPY_rna_operator_poll_message_set_doc,
static PyObject *BPY_rna_operator_poll_message_set(PyObject *UNUSED(self), PyObject *args)
{
- const ssize_t args_len = PyTuple_GET_SIZE(args);
+ const Py_ssize_t args_len = PyTuple_GET_SIZE(args);
if (args_len == 0) {
PyErr_SetString(PyExc_ValueError,
"poll_message_set(message, ...): requires a message argument");
diff --git a/source/blender/python/mathutils/mathutils_Euler.h b/source/blender/python/mathutils/mathutils_Euler.h
index 0deef3cfdf3..453a3b3736e 100644
--- a/source/blender/python/mathutils/mathutils_Euler.h
+++ b/source/blender/python/mathutils/mathutils_Euler.h
@@ -37,14 +37,14 @@ typedef struct {
/* prototypes */
PyObject *Euler_CreatePyObject(const float eul[3],
- const short order,
+ short order,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
PyObject *Euler_CreatePyObject_wrap(float eul[3],
- const short order,
+ short order,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
PyObject *Euler_CreatePyObject_cb(PyObject *cb_user,
- const short order,
+ short order,
unsigned char cb_type,
unsigned char cb_subtype) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index 56bb4d39d01..3067c5417b9 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -61,17 +61,17 @@ typedef struct {
/* prototypes */
PyObject *Matrix_CreatePyObject(const float *mat,
- const ushort num_col,
- const ushort num_row,
+ ushort num_col,
+ ushort num_row,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
PyObject *Matrix_CreatePyObject_wrap(float *mat,
- const ushort num_col,
- const ushort num_row,
+ ushort num_col,
+ ushort num_row,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
PyObject *Matrix_CreatePyObject_cb(PyObject *user,
- const unsigned short num_col,
- const unsigned short num_row,
+ unsigned short num_col,
+ unsigned short num_row,
unsigned char cb_type,
unsigned char cb_subtype) ATTR_WARN_UNUSED_RESULT;
@@ -79,8 +79,8 @@ PyObject *Matrix_CreatePyObject_cb(PyObject *user,
* \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,
+ ushort num_col,
+ ushort num_row,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
/* PyArg_ParseTuple's "O&" formatting helpers. */
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 525b2da7d06..8c333413d74 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -320,7 +320,7 @@ static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject
QUAT_SIZE,
QUAT_SIZE,
value,
- "Quaternion.difference(other), invalid 'other' arg") == -1) {
+ "Quaternion.rotation_difference(other), invalid 'other' arg") == -1) {
return NULL;
}
diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h
index fb420b32df4..50609e51b0a 100644
--- a/source/blender/python/mathutils/mathutils_Vector.h
+++ b/source/blender/python/mathutils/mathutils_Vector.h
@@ -33,7 +33,7 @@ typedef struct {
/*prototypes*/
PyObject *Vector_CreatePyObject(const float *vec,
- const int size,
+ int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT;
/**
* Create a vector that wraps existing memory.
@@ -41,7 +41,7 @@ PyObject *Vector_CreatePyObject(const float *vec,
* \param vec: Use this vector in-place.
*/
PyObject *Vector_CreatePyObject_wrap(float *vec,
- const int size,
+ int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
/**
@@ -56,6 +56,6 @@ PyObject *Vector_CreatePyObject_cb(PyObject *user,
* \param vec: Initialized vector value to use in-place, allocated with #PyMem_Malloc
*/
PyObject *Vector_CreatePyObject_alloc(float *vec,
- const int size,
+ int size,
PyTypeObject *base_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index d47b59d0c76..b8244efbee2 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -1236,7 +1236,7 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject
polyLine = PySequence_GetItem(polyLineSeq, i);
if (!PySequence_Check(polyLine)) {
BKE_displist_free(&dispbase);
- Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/
+ Py_XDECREF(polyLine); /* May be null so use #Py_XDECREF. */
PyErr_SetString(PyExc_TypeError,
"One or more of the polylines is not a sequence of mathutils.Vector's");
return NULL;
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index 494415a4077..a7c1b12982c 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -49,6 +49,7 @@ set(SRC
intern/pipeline.c
intern/render_result.c
intern/texture_image.c
+ intern/texture_margin.cc
intern/texture_pointdensity.c
intern/texture_procedural.c
intern/zbuf.c
@@ -58,6 +59,7 @@ set(SRC
RE_multires_bake.h
RE_pipeline.h
RE_texture.h
+ RE_texture_margin.h
intern/pipeline.h
intern/render_result.h
diff --git a/source/blender/render/RE_bake.h b/source/blender/render/RE_bake.h
index b2c44e051d1..d3025bf4198 100644
--- a/source/blender/render/RE_bake.h
+++ b/source/blender/render/RE_bake.h
@@ -25,6 +25,7 @@
struct Depsgraph;
struct ImBuf;
+struct MLoopUV;
struct Mesh;
struct Render;
@@ -81,42 +82,47 @@ bool RE_bake_has_engine(const struct Render *re);
bool RE_bake_engine(struct Render *re,
struct Depsgraph *depsgraph,
struct Object *object,
- const int object_id,
+ int object_id,
const BakePixel pixel_array[],
const BakeTargets *targets,
- const eScenePassType pass_type,
- const int pass_filter,
+ eScenePassType pass_type,
+ int pass_filter,
float result[]);
/* bake.c */
-int RE_pass_depth(const eScenePassType pass_type);
+int RE_pass_depth(eScenePassType pass_type);
bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low,
BakePixel pixel_array_from[],
BakePixel pixel_array_to[],
BakeHighPolyData highpoly[],
- const int tot_highpoly,
- const size_t num_pixels,
- const bool is_custom_cage,
- const float cage_extrusion,
- const float max_ray_distance,
+ int tot_highpoly,
+ size_t num_pixels,
+ bool is_custom_cage,
+ float cage_extrusion,
+ float max_ray_distance,
float mat_low[4][4],
float mat_cage[4][4],
struct Mesh *me_cage);
void RE_bake_pixels_populate(struct Mesh *me,
struct BakePixel *pixel_array,
- const size_t num_pixels,
+ size_t num_pixels,
const struct BakeTargets *targets,
const char *uv_layer);
-void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask);
+void RE_bake_mask_fill(const BakePixel pixel_array[], size_t num_pixels, char *mask);
-void RE_bake_margin(struct ImBuf *ibuf, char *mask, const int margin);
+void RE_bake_margin(struct ImBuf *ibuf,
+ char *mask,
+ int margin,
+ char margin_type,
+ struct Mesh const *me,
+ char const *uv_layer);
void RE_bake_normal_world_to_object(const BakePixel pixel_array[],
- const size_t num_pixels,
- const int depth,
+ size_t num_pixels,
+ int depth,
float result[],
struct Object *ob,
const eBakeNormalSwizzle normal_swizzle[3]);
@@ -125,19 +131,19 @@ void RE_bake_normal_world_to_object(const BakePixel pixel_array[],
* 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,
+ size_t num_pixels,
+ int depth,
float result[],
struct Mesh *me,
const eBakeNormalSwizzle normal_swizzle[3],
float mat[4][4]);
void RE_bake_normal_world_to_world(const BakePixel pixel_array[],
- const size_t num_pixels,
- const int depth,
+ size_t num_pixels,
+ int depth,
float result[],
const eBakeNormalSwizzle normal_swizzle[3]);
-void RE_bake_ibuf_clear(struct Image *image, const bool is_tangent);
+void RE_bake_ibuf_clear(struct Image *image, bool is_tangent);
#ifdef __cplusplus
}
diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h
index b22d263490c..c0bd8c0fe4e 100644
--- a/source/blender/render/RE_engine.h
+++ b/source/blender/render/RE_engine.h
@@ -106,10 +106,10 @@ typedef struct RenderEngineType {
void (*bake)(struct RenderEngine *engine,
struct Depsgraph *depsgraph,
struct Object *object,
- const int pass_type,
- const int pass_filter,
- const int width,
- const int height);
+ int pass_type,
+ int pass_filter,
+ int width,
+ int height);
void (*view_update)(struct RenderEngine *engine,
const struct bContext *context,
diff --git a/source/blender/render/RE_multires_bake.h b/source/blender/render/RE_multires_bake.h
index 42ee2c57fbb..6df80c27c40 100644
--- a/source/blender/render/RE_multires_bake.h
+++ b/source/blender/render/RE_multires_bake.h
@@ -33,7 +33,8 @@ extern "C" {
typedef struct MultiresBakeRender {
Scene *scene;
DerivedMesh *lores_dm, *hires_dm;
- int bake_filter; /* Bake-filter, aka margin */
+ int bake_margin;
+ char bake_margin_type;
int lvl, tot_lvl;
short mode;
bool use_lores_mesh; /* Use low-resolution mesh when baking displacement maps */
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index 073bb0a3697..072fc7363b2 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -237,7 +237,7 @@ void RE_ReleaseResultImageViews(struct Render *re, struct RenderResult *rr);
* 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_AcquireResultImage(struct Render *re, struct RenderResult *rr, int view_id);
void RE_ReleaseResultImage(struct Render *re);
void RE_SwapResult(struct Render *re, struct RenderResult **rr);
void RE_ClearResult(struct Render *re);
@@ -255,12 +255,12 @@ void RE_ResultGet32(struct Render *re, unsigned int *rect);
void RE_AcquiredResultGet32(struct Render *re,
struct RenderResult *result,
unsigned int *rect,
- const int view_id);
+ int view_id);
void RE_render_result_rect_from_ibuf(struct RenderResult *rr,
struct RenderData *rd,
struct ImBuf *ibuf,
- const int view_id);
+ int view_id);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl,
@@ -283,7 +283,7 @@ void RE_create_render_pass(struct RenderResult *rr,
const char *chan_id,
const char *layername,
const char *viewname,
- const bool allocate);
+ bool allocate);
/**
* Obligatory initialize call, doesn't change during entire render sequence.
@@ -325,7 +325,7 @@ void RE_init_threadcount(Render *re);
bool RE_WriteRenderViewsImage(struct ReportList *reports,
struct RenderResult *rr,
struct Scene *scene,
- const bool stamp,
+ bool stamp,
char *name);
bool RE_WriteRenderViewsMovie(struct ReportList *reports,
struct RenderResult *rr,
@@ -333,7 +333,7 @@ bool RE_WriteRenderViewsMovie(struct ReportList *reports,
struct RenderData *rd,
struct bMovieHandle *mh,
void **movie_ctx_arr,
- const int totvideos,
+ int totvideos,
bool preview);
/**
@@ -347,7 +347,7 @@ void RE_RenderFrame(struct Render *re,
struct ViewLayer *single_layer,
struct Object *camera_override,
int frame,
- const bool write_still);
+ bool write_still);
/**
* Saves images to disk.
*/
@@ -461,8 +461,6 @@ void RE_GetCameraWindow(struct Render *re, struct Object *camera, float mat[4][4
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);
@@ -478,7 +476,7 @@ bool RE_allow_render_generic_object(struct Object *ob);
bool RE_HasCombinedLayer(RenderResult *res);
bool RE_HasFloatPixels(RenderResult *res);
bool RE_RenderResult_is_stereo(RenderResult *res);
-struct RenderView *RE_RenderViewGetById(struct RenderResult *rr, const int view_id);
+struct RenderView *RE_RenderViewGetById(struct RenderResult *rr, int view_id);
struct RenderView *RE_RenderViewGetByName(struct RenderResult *rr, const char *viewname);
RenderResult *RE_DuplicateRenderResult(RenderResult *rr);
diff --git a/source/blender/render/RE_texture.h b/source/blender/render/RE_texture.h
index cb18dc92415..d71c793f300 100644
--- a/source/blender/render/RE_texture.h
+++ b/source/blender/render/RE_texture.h
@@ -45,10 +45,10 @@ extern "C" {
*/
bool RE_texture_evaluate(const struct MTex *mtex,
const float vec[3],
- const int thread,
+ int thread,
struct ImagePool *pool,
- const bool skip_load_image,
- const bool texnode_preview,
+ bool skip_load_image,
+ bool texnode_preview,
/* Return arguments. */
float *r_intensity,
float r_rgba[4]) ATTR_NONNULL(1, 2, 7, 8);
@@ -88,7 +88,7 @@ void RE_point_density_minmax(struct Depsgraph *depsgraph,
*/
void RE_point_density_sample(struct Depsgraph *depsgraph,
struct PointDensity *pd,
- const int resolution,
+ int resolution,
float *values);
void RE_point_density_free(struct PointDensity *pd);
@@ -122,10 +122,10 @@ int multitex_ext(struct Tex *tex,
float dyt[3],
int osatex,
struct TexResult *texres,
- const short thread,
+ short thread,
struct ImagePool *pool,
bool scene_color_manage,
- const bool skip_load_image);
+ bool skip_load_image);
/**
* Nodes disabled.
@@ -138,7 +138,7 @@ int multitex_ext_safe(struct Tex *tex,
struct TexResult *texres,
struct ImagePool *pool,
bool scene_color_manage,
- const bool skip_load_image);
+ bool skip_load_image);
/**
* Only for internal node usage.
@@ -152,7 +152,7 @@ int multitex_nodes(struct Tex *tex,
float dyt[3],
int osatex,
struct TexResult *texres,
- const short thread,
+ short thread,
short which_output,
struct MTex *mtex,
struct ImagePool *pool);
diff --git a/source/blender/render/RE_texture_margin.h b/source/blender/render/RE_texture_margin.h
new file mode 100644
index 00000000000..8d1a6c45809
--- /dev/null
+++ b/source/blender/render/RE_texture_margin.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct DerivedMesh;
+struct IMBuf;
+struct ImBuf;
+struct MLoopUV;
+struct Mesh;
+
+/**
+ * Generate a margin around the textures uv islands by copying pixels from the adjacent polygon.
+ *
+ * \param ibuf: the texture image.
+ * \param mask: pixels with a mask value of 1 are not written to.
+ * \param margin: the size of the margin in pixels.
+ * \param me: the mesh to use the polygons of.
+ * \param mloopuv: the uv data to use.
+ */
+void RE_generate_texturemargin_adjacentfaces(
+ struct ImBuf *ibuf, char *mask, const int margin, struct Mesh const *me, char const *uv_layer);
+
+void RE_generate_texturemargin_adjacentfaces_dm(struct ImBuf *ibuf,
+ char *mask,
+ const int margin,
+ struct DerivedMesh *dm);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 6794a9cd1ad..93d2f721cc5 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -83,6 +83,7 @@
#include "IMB_imbuf_types.h"
#include "RE_bake.h"
+#include "RE_texture_margin.h"
/* local include */
#include "render_types.h"
@@ -107,6 +108,7 @@ typedef struct TSpace {
typedef struct TriTessFace {
const MVert *mverts[3];
+ const float *vert_normals[3];
const TSpace *tspace[3];
float *loop_normal[3];
float normal[3]; /* for flat faces */
@@ -153,10 +155,24 @@ void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, c
}
}
-void RE_bake_margin(ImBuf *ibuf, char *mask, const int margin)
+void RE_bake_margin(ImBuf *ibuf,
+ char *mask,
+ const int margin,
+ const char margin_type,
+ Mesh const *me,
+ char const *uv_layer)
{
/* margin */
- IMB_filter_extend(ibuf, mask, margin);
+ switch (margin_type) {
+ case R_BAKE_ADJACENT_FACES:
+ RE_generate_texturemargin_adjacentfaces(ibuf, mask, margin, me, uv_layer);
+ break;
+ default:
+ /* fall through */
+ case R_BAKE_EXTEND:
+ IMB_filter_extend(ibuf, mask, margin);
+ break;
+ }
if (ibuf->planes != R_IMF_PLANES_RGBA) {
/* clear alpha added by filtering */
@@ -241,9 +257,9 @@ static void calc_point_from_barycentric_extrusion(TriTessFace *triangles,
interp_barycentric_tri_v3(data, u, v, coord);
if (is_smooth) {
- normal_short_to_float_v3(data[0], triangle->mverts[0]->no);
- normal_short_to_float_v3(data[1], triangle->mverts[1]->no);
- normal_short_to_float_v3(data[2], triangle->mverts[2]->no);
+ copy_v3_v3(data[0], triangle->vert_normals[0]);
+ copy_v3_v3(data[1], triangle->vert_normals[1]);
+ copy_v3_v3(data[2], triangle->vert_normals[2]);
interp_barycentric_tri_v3(data, u, v, dir);
normalize_v3(dir);
@@ -488,6 +504,7 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
loop_normals = CustomData_get_layer(&me_eval->ldata, CD_NORMAL);
}
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me);
for (i = 0; i < tottri; i++) {
const MLoopTri *lt = &looptri[i];
const MPoly *mp = &me->mpoly[lt->poly];
@@ -495,6 +512,9 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v];
triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v];
triangles[i].mverts[2] = &mvert[me->mloop[lt->tri[2]].v];
+ triangles[i].vert_normals[0] = &vert_normals[me->mloop[lt->tri[0]].v][0];
+ triangles[i].vert_normals[1] = &vert_normals[me->mloop[lt->tri[1]].v][1];
+ triangles[i].vert_normals[2] = &vert_normals[me->mloop[lt->tri[2]].v][2];
triangles[i].is_smooth = (mp->flag & ME_SMOOTH) != 0;
if (tangent) {
@@ -878,7 +898,7 @@ void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[],
copy_v3_v3(normals[j], triangle->loop_normal[j]);
}
else {
- normal_short_to_float_v3(normals[j], triangle->mverts[j]->no);
+ copy_v3_v3(normals[j], triangle->vert_normals[j]);
}
}
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index e1778897777..04f27ff6cbc 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -435,8 +435,6 @@ void RE_engine_end_result(
return;
}
- re_ensure_passes_allocated_thread_safe(re);
-
if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES)) {
const HighlightedTile tile = highlighted_tile_from_result_get(re, result);
@@ -445,6 +443,7 @@ void RE_engine_end_result(
if (!cancel || merge_results) {
if (!(re->test_break(re->tbh) && (re->r.scemode & R_BUTS_PREVIEW))) {
+ re_ensure_passes_allocated_thread_safe(re);
render_result_merge(re->result, result);
}
@@ -923,8 +922,10 @@ static void engine_render_view_layer(Render *re,
}
}
- /* Optionally composite grease pencil over render result. */
- if (engine->has_grease_pencil && use_grease_pencil) {
+ /* Optionally composite grease pencil over render result.
+ * Only do it if the passes are allocated (and the engine will not override the grease pencil
+ * when reading its result from EXR file and writing to the Blender side. */
+ if (engine->has_grease_pencil && use_grease_pencil && re->result->passes_allocated) {
/* NOTE: External engine might have been requested to free its
* dependency graph, which is only allowed if there is no grease
* pencil (pipeline is taking care of that). */
@@ -1023,10 +1024,18 @@ bool RE_engine_render(Render *re, bool do_all)
re->draw_lock(re->dlh, false);
}
+ /* Render view layers. */
+ bool delay_grease_pencil = false;
+
if (type->render) {
FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer_iter) {
engine_render_view_layer(re, engine, view_layer_iter, true, true);
+ /* If render passes are not allocated the render engine deferred final pixels write for
+ * later. Need to defer the grease pencil for until after the engine has written the
+ * render result to Blender. */
+ delay_grease_pencil = engine->has_grease_pencil && !re->result->passes_allocated;
+
if (RE_engine_test_break(engine)) {
break;
}
@@ -1038,6 +1047,17 @@ bool RE_engine_render(Render *re, bool do_all)
type->render_frame_finish(engine);
}
+ /* Perform delayed grease pencil rendering. */
+ if (delay_grease_pencil) {
+ FOREACH_VIEW_LAYER_TO_RENDER_BEGIN (re, view_layer_iter) {
+ engine_render_view_layer(re, engine, view_layer_iter, false, true);
+ if (RE_engine_test_break(engine)) {
+ break;
+ }
+ }
+ FOREACH_VIEW_LAYER_TO_RENDER_END;
+ }
+
/* Clear tile data */
engine->flag &= ~RE_ENGINE_RENDERING;
diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c
index 930c7580f32..5cf328a3a73 100644
--- a/source/blender/render/intern/multires_bake.c
+++ b/source/blender/render/intern/multires_bake.c
@@ -47,6 +47,7 @@
#include "RE_multires_bake.h"
#include "RE_pipeline.h"
#include "RE_texture.h"
+#include "RE_texture_margin.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -72,6 +73,7 @@ typedef struct MultiresBakeResult {
typedef struct {
MVert *mvert;
+ const float (*vert_normals)[3];
MPoly *mpoly;
MLoop *mloop;
MLoopUV *mloopuv;
@@ -135,10 +137,7 @@ static void multiresbake_get_normal(const MResolvePixelData *data,
}
else {
const int vi = data->mloop[data->mlooptri[tri_num].tri[vert_index]].v;
- const short *no = data->mvert[vi].no;
-
- normal_short_to_float_v3(norm, no);
- normalize_v3(norm);
+ copy_v3_v3(norm, data->vert_normals[vi]);
}
}
@@ -1298,14 +1297,23 @@ static void apply_ao_callback(DerivedMesh *lores_dm,
/* ******$***************** Post processing ************************* */
-static void bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
+static void bake_ibuf_filter(
+ ImBuf *ibuf, char *mask, const int margin, const char margin_type, DerivedMesh *dm)
{
/* must check before filtering */
const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
- /* Margin */
- if (filter) {
- IMB_filter_extend(ibuf, mask, filter);
+ if (margin) {
+ switch (margin_type) {
+ case R_BAKE_ADJACENT_FACES:
+ RE_generate_texturemargin_adjacentfaces_dm(ibuf, mask, margin, dm);
+ break;
+ default:
+ /* fall through */
+ case R_BAKE_EXTEND:
+ IMB_filter_extend(ibuf, mask, margin);
+ break;
+ }
}
/* if the bake results in new alpha then change the image setting */
@@ -1313,7 +1321,7 @@ static void bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
ibuf->planes = R_IMF_PLANES_RGBA;
}
else {
- if (filter && ibuf->planes != R_IMF_PLANES_RGBA) {
+ if (margin && ibuf->planes != R_IMF_PLANES_RGBA) {
/* clear alpha added by filtering */
IMB_rectfill_alpha(ibuf, 1.0f);
}
@@ -1462,7 +1470,8 @@ static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
result->height_max);
}
- bake_ibuf_filter(ibuf, userdata->mask_buffer, bkr->bake_filter);
+ bake_ibuf_filter(
+ ibuf, userdata->mask_buffer, bkr->bake_margin, bkr->bake_margin_type, bkr->lores_dm);
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
BKE_image_mark_dirty(ima, ibuf);
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index a800361a41f..739202564af 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -73,6 +73,8 @@
#include "BKE_sound.h"
#include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */
+#include "NOD_composite.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_debug.h"
@@ -1131,7 +1133,7 @@ static void do_render_compositor_scenes(Render *re)
render_scene_has_layers_to_render(scene, false)) {
do_render_compositor_scene(re, scene, cfra);
BLI_gset_add(scenes_rendered, scene);
- nodeUpdate(restore_scene->nodetree, node);
+ node->typeinfo->updatefunc(restore_scene->nodetree, node);
}
}
}
@@ -1821,7 +1823,7 @@ void RE_RenderFrame(Render *re,
render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
/* Ugly global still...
- * is to prevent preview events and signal subsurfs etc to make full resol. */
+ * is to prevent preview events and signal subdivision-surface etc to make full resolution. */
G.is_rendering = true;
scene->r.cfra = frame;
@@ -2331,8 +2333,8 @@ void RE_RenderAnim(Render *re,
}
}
- /* Ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol
- * is also set by caller renderwin.c */
+ /* Ugly global still... is to prevent renderwin events and signal subdivision-surface etc
+ * to make full resolution is also set by caller renderwin.c */
G.is_rendering = true;
re->flag |= R_ANIMATION;
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index a21351539f6..d207ea0a38e 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -470,6 +470,12 @@ RenderResult *render_result_new(Render *re,
void render_result_passes_allocated_ensure(RenderResult *rr)
{
+ if (rr == NULL) {
+ /* Happens when the result was not yet allocated for the current scene or slot configuration.
+ */
+ return;
+ }
+
LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
if (rl->exrhandle != NULL && !STREQ(rp->name, RE_PASSNAME_COMBINED)) {
@@ -1232,7 +1238,7 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, const RenderData *rd, const
}
}
- /* color -> grayscale */
+ /* Color -> gray-scale. */
/* editing directly would alter the render view */
if (rd->im_format.planes == R_IMF_PLANES_BW) {
ImBuf *ibuf_bw = IMB_dupImBuf(ibuf);
diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h
index ede0a0d21ea..9084dbf95ce 100644
--- a/source/blender/render/intern/render_result.h
+++ b/source/blender/render/intern/render_result.h
@@ -107,7 +107,7 @@ struct RenderPass *render_layer_add_pass(struct RenderResult *rr,
const char *name,
const char *viewname,
const char *chan_id,
- const bool allocate);
+ bool allocate);
/**
* Called for reading temp files, and for external engines.
@@ -128,16 +128,16 @@ bool render_result_exr_file_cache_read(struct Render *re);
struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr,
const struct RenderData *rd,
- const int view_id);
+ int view_id);
-void render_result_rect_fill_zero(struct RenderResult *rr, const int view_id);
+void render_result_rect_fill_zero(struct RenderResult *rr, int view_id);
void render_result_rect_get_pixels(struct RenderResult *rr,
unsigned int *rect,
int rectx,
int recty,
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
- const int view_id);
+ int view_id);
/**
* Create a new views #ListBase in rr without duplicating the memory pointers.
diff --git a/source/blender/render/intern/render_types.h b/source/blender/render/intern/render_types.h
index ca4f72350e1..e5d766acf8d 100644
--- a/source/blender/render/intern/render_types.h
+++ b/source/blender/render/intern/render_types.h
@@ -106,7 +106,7 @@ struct Render {
struct RenderEngine *engine;
/* NOTE: This is a minimal dependency graph and evaluated scene which is enough to access view
- * layer visibility and use for post-precessing (compositor and sequencer). */
+ * layer visibility and use for postprocessing (compositor and sequencer). */
Depsgraph *pipeline_depsgraph;
Scene *pipeline_scene_eval;
diff --git a/source/blender/render/intern/texture_common.h b/source/blender/render/intern/texture_common.h
index b3a976c3fe0..5fc3af6153f 100644
--- a/source/blender/render/intern/texture_common.h
+++ b/source/blender/render/intern/texture_common.h
@@ -89,13 +89,13 @@ int imagewraposa(struct Tex *tex,
const float dyt[2],
struct TexResult *texres,
struct ImagePool *pool,
- const bool skip_load_image);
+ bool skip_load_image);
int imagewrap(struct Tex *tex,
struct Image *ima,
const float texvec[3],
struct TexResult *texres,
struct ImagePool *pool,
- const bool skip_load_image);
+ bool skip_load_image);
void image_sample(struct Image *ima,
float fx,
float fy,
diff --git a/source/blender/render/intern/texture_image.c b/source/blender/render/intern/texture_image.c
index dfeaec2341e..6ded799b773 100644
--- a/source/blender/render/intern/texture_image.c
+++ b/source/blender/render/intern/texture_image.c
@@ -912,7 +912,7 @@ static void feline_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata
(maxn ? (float)maxn : 1.0f);
float du = maxn ? cosf(AFD->theta) * ll : 0.0f;
float dv = maxn ? sinf(AFD->theta) * ll : 0.0f;
- /* const float D = -0.5f*(du*du + dv*dv) / (AFD->majrad*AFD->majrad); */
+ // const float D = -0.5f*(du*du + dv*dv) / (AFD->majrad*AFD->majrad);
const float D = (EWA_MAXIDX + 1) * 0.25f * (du * du + dv * dv) / (AFD->majrad * AFD->majrad);
float d; /* TXF alpha: cw = 0.0f; */
int n; /* TXF alpha: clip = 0; */
diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc
new file mode 100644
index 00000000000..0e47c2cec8a
--- /dev/null
+++ b/source/blender/render/intern/texture_margin.cc
@@ -0,0 +1,555 @@
+/*
+ * 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 render
+ */
+
+#include "BLI_assert.h"
+#include "BLI_math_geom.h"
+#include "BLI_math_vec_types.hh"
+#include "BLI_math_vector.hh"
+#include "BLI_vector.hh"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_mesh.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "zbuf.h" // for rasterizer
+
+#include "RE_texture_margin.h"
+
+#include <algorithm>
+#include <math.h>
+#include <valarray>
+
+namespace blender::render::texturemargin {
+
+/* The map class contains both a pixel map which maps out polygon indices for all UV-polygons and
+ * adjacency tables.
+ */
+class TextureMarginMap {
+ static const int directions[4][2];
+
+ /* Maps UV-edges to their corresponding UV-edge. */
+ Vector<int> loop_adjacency_map_;
+ /* Maps UV-edges to their corresponding polygon. */
+ Vector<int> loop_to_poly_map_;
+
+ int w_, h_;
+ Vector<uint32_t> pixel_data_;
+ ZSpan zspan_;
+ uint32_t value_to_store_;
+ char *mask_;
+
+ MPoly const *mpoly_;
+ MLoop const *mloop_;
+ MLoopUV const *mloopuv_;
+ int totpoly_;
+ int totloop_;
+ int totedge_;
+
+ public:
+ TextureMarginMap(size_t w,
+ size_t h,
+ MPoly const *mpoly,
+ MLoop const *mloop,
+ MLoopUV const *mloopuv,
+ int totpoly,
+ int totloop,
+ int totedge)
+ : w_(w),
+ h_(h),
+ mpoly_(mpoly),
+ mloop_(mloop),
+ mloopuv_(mloopuv),
+ totpoly_(totpoly),
+ totloop_(totloop),
+ totedge_(totedge)
+ {
+ pixel_data_.resize(w_ * h_, 0xFFFFFFFF);
+
+ zbuf_alloc_span(&zspan_, w_, h_);
+
+ build_tables();
+ }
+
+ ~TextureMarginMap()
+ {
+ zbuf_free_span(&zspan_);
+ }
+
+ inline void set_pixel(int x, int y, uint32_t value)
+ {
+ BLI_assert(x < w_);
+ BLI_assert(x >= 0);
+ pixel_data_[y * w_ + x] = value;
+ }
+
+ inline uint32_t get_pixel(int x, int y) const
+ {
+ if (x < 0 || y < 0 || x >= w_ || y >= h_) {
+ return 0xFFFFFFFF;
+ }
+
+ return pixel_data_[y * w_ + x];
+ }
+
+ void rasterize_tri(float *v1, float *v2, float *v3, uint32_t value, char *mask)
+ {
+ /* NOTE: This is not thread safe, because the value to be written by the rasterizer is
+ * a class member. If this is ever made multi-threaded each thread needs to get it's own. */
+ value_to_store_ = value;
+ mask_ = mask;
+ zspan_scanconvert(
+ &zspan_, this, &(v1[0]), &(v2[0]), &(v3[0]), TextureMarginMap::zscan_store_pixel);
+ }
+
+ static void zscan_store_pixel(void *map, int x, int y, float, float)
+ {
+ /* NOTE: Not thread safe, see comment above.
+ *
+ */
+ TextureMarginMap *m = static_cast<TextureMarginMap *>(map);
+ m->set_pixel(x, y, m->value_to_store_);
+ if (m->mask_) {
+ m->mask_[y * m->w_ + x] = 1;
+ }
+ }
+
+/* The map contains 2 kinds of pixels: DijkstraPixels and polygon indices. The top bit determines
+ * what kind it is. With the top bit set, it is a 'dijkstra' pixel. The bottom 3 bits encode the
+ * direction of the shortest path and the remaining 28 bits are used to store the distance. If
+ * the top bit is not set, the rest of the bits is used to store the polygon index.
+ */
+#define PackDijkstraPixel(dist, dir) (0x80000000 + ((dist) << 3) + (dir))
+#define DijkstraPixelGetDistance(dp) (((dp) ^ 0x80000000) >> 3)
+#define DijkstraPixelGetDirection(dp) ((dp)&0x7)
+#define IsDijkstraPixel(dp) ((dp)&0x80000000)
+#define DijkstraPixelIsUnset(dp) ((dp) == 0xFFFFFFFF)
+
+ /* Use dijkstra's algorithm to 'grow' a border around the polygons marked in the map.
+ * For each pixel mark which direction is the shortest way to a polygon.
+ */
+ void grow_dijkstra(int margin)
+ {
+ class DijkstraActivePixel {
+ public:
+ DijkstraActivePixel(int dist, int _x, int _y) : distance(dist), x(_x), y(_y)
+ {
+ }
+ int distance;
+ int x, y;
+ };
+ auto cmp_dijkstrapixel_fun = [](DijkstraActivePixel const &a1, DijkstraActivePixel const &a2) {
+ return a1.distance > a2.distance;
+ };
+
+ Vector<DijkstraActivePixel> active_pixels;
+ for (int y = 0; y < h_; y++) {
+ for (int x = 0; x < w_; x++) {
+ if (DijkstraPixelIsUnset(get_pixel(x, y))) {
+ for (int i = 0; i < 4; i++) {
+ int xx = x - directions[i][0];
+ int yy = y - directions[i][1];
+
+ if (xx >= 0 && xx < w_ && yy >= 0 && yy < w_ && !IsDijkstraPixel(get_pixel(xx, yy))) {
+ set_pixel(x, y, PackDijkstraPixel(1, i));
+ active_pixels.append(DijkstraActivePixel(1, x, y));
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // std::make_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
+ // Not strictly needed because at this point it already is a heap.
+
+ while (active_pixels.size()) {
+ std::pop_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
+ DijkstraActivePixel p = active_pixels.pop_last();
+
+ int dist = p.distance;
+
+ dist++;
+ if (dist < margin) {
+ for (int i = 0; i < 4; i++) {
+ int x = p.x + directions[i][0];
+ int y = p.y + directions[i][1];
+ if (x >= 0 && x < w_ && y >= 0 && y < h_) {
+ uint32_t dp = get_pixel(x, y);
+ if (IsDijkstraPixel(dp) && (DijkstraPixelGetDistance(dp) > dist)) {
+ BLI_assert(abs((int)DijkstraPixelGetDirection(dp) - (int)i) != 2);
+ set_pixel(x, y, PackDijkstraPixel(dist, i));
+ active_pixels.append(DijkstraActivePixel(dist, x, y));
+ std::push_heap(active_pixels.begin(), active_pixels.end(), cmp_dijkstrapixel_fun);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Walk over the map and for margin pixels follow the direction stored in the bottom 3
+ * bits back to the polygon.
+ * Then look up the pixel from the next polygon.
+ */
+ void lookup_pixels(ImBuf *ibuf, char *mask, int maxPolygonSteps)
+ {
+ for (int y = 0; y < h_; y++) {
+ for (int x = 0; x < w_; x++) {
+ uint32_t dp = get_pixel(x, y);
+ if (IsDijkstraPixel(dp) && !DijkstraPixelIsUnset(dp)) {
+ int dist = DijkstraPixelGetDistance(dp);
+ int direction = DijkstraPixelGetDirection(dp);
+
+ int xx = x;
+ int yy = y;
+
+ /* Follow the dijkstra directions to find the polygon this margin pixels belongs to. */
+ while (dist > 0) {
+ xx -= directions[direction][0];
+ yy -= directions[direction][1];
+ dp = get_pixel(xx, yy);
+ dist--;
+ BLI_assert(!dist || (dist == DijkstraPixelGetDistance(dp)));
+ direction = DijkstraPixelGetDirection(dp);
+ }
+
+ uint32_t poly = get_pixel(xx, yy);
+
+ BLI_assert(!IsDijkstraPixel(poly));
+
+ float destX, destY;
+
+ int other_poly;
+ bool found_pixel_in_polygon = false;
+ if (lookup_pixel(x, y, poly, &destX, &destY, &other_poly)) {
+
+ for (int i = 0; i < maxPolygonSteps; i++) {
+ /* Force to pixel grid. */
+ int nx = (int)round(destX);
+ int ny = (int)round(destY);
+ uint32_t polygon_from_map = get_pixel(nx, ny);
+ if (other_poly == polygon_from_map) {
+ found_pixel_in_polygon = true;
+ break;
+ }
+
+ /* Look up again, but starting from the polygon we were expected to land in. */
+ lookup_pixel(nx, ny, other_poly, &destX, &destY, &other_poly);
+ }
+
+ if (found_pixel_in_polygon) {
+ bilinear_interpolation(ibuf, ibuf, destX, destY, x, y);
+ /* Add our new pixels to the assigned pixel map. */
+ mask[y * w_ + x] = 1;
+ }
+ }
+ }
+ else if (DijkstraPixelIsUnset(dp) || !IsDijkstraPixel(dp)) {
+ /* These are not margin pixels, make sure the extend filter which is run after this step
+ * leaves them alone.
+ */
+ mask[y * w_ + x] = 1;
+ }
+ }
+ }
+ }
+
+ private:
+ float2 uv_to_xy(MLoopUV const &mloopuv) const
+ {
+ float2 ret;
+ ret.x = ((mloopuv.uv[0] * w_) - (0.5f + 0.001f));
+ ret.y = ((mloopuv.uv[1] * h_) - (0.5f + 0.001f));
+ return ret;
+ }
+
+ void build_tables()
+ {
+ loop_to_poly_map_.resize(totloop_);
+ for (int i = 0; i < totpoly_; i++) {
+ for (int j = 0; j < mpoly_[i].totloop; j++) {
+ int l = j + mpoly_[i].loopstart;
+ loop_to_poly_map_[l] = i;
+ }
+ }
+
+ loop_adjacency_map_.resize(totloop_, -1);
+
+ Vector<int> tmpmap;
+ tmpmap.resize(totedge_, -1);
+
+ for (size_t i = 0; i < totloop_; i++) {
+ int edge = mloop_[i].e;
+ if (tmpmap[edge] == -1) {
+ loop_adjacency_map_[i] = -1;
+ tmpmap[edge] = i;
+ }
+ else {
+ BLI_assert(tmpmap[edge] >= 0);
+ loop_adjacency_map_[i] = tmpmap[edge];
+ loop_adjacency_map_[tmpmap[edge]] = i;
+ }
+ }
+ }
+
+ /* Find which edge of the src_poly is closest to x,y. Look up it's adjacent UV-edge and polygon.
+ * Then return the location of the equivalent pixel in the other polygon.
+ * Returns true if a new pixel location was found, false if it wasn't, which can happen if the
+ * margin pixel is on a corner, or the UV-edge doesn't have an adjacent polygon. */
+ bool lookup_pixel(
+ float x, float y, int src_poly, float *r_destx, float *r_desty, int *r_other_poly)
+ {
+ float2 point(x, y);
+
+ *r_destx = *r_desty = 0;
+
+ int found_edge = -1;
+ float found_dist = -1;
+ float found_t = 0;
+
+ /* Find the closest edge on which the point x,y can be projected.
+ */
+ for (size_t i = 0; i < mpoly_[src_poly].totloop; i++) {
+ int l1 = mpoly_[src_poly].loopstart + i;
+ int l2 = l1 + 1;
+ if (l2 >= mpoly_[src_poly].loopstart + mpoly_[src_poly].totloop) {
+ l2 = mpoly_[src_poly].loopstart;
+ }
+ /* edge points */
+ float2 edgepoint1 = uv_to_xy(mloopuv_[l1]);
+ float2 edgepoint2 = uv_to_xy(mloopuv_[l2]);
+ /* Vector AB is the vector from the first edge point to the second edge point.
+ * Vector AP is the vector from the first edge point to our point under investigation. */
+ float2 ab = edgepoint2 - edgepoint1;
+ float2 ap = point - edgepoint1;
+
+ /* Project ap onto ab. */
+ float dotv = math::dot(ab, ap);
+
+ float ablensq = math::length_squared(ab);
+
+ float t = dotv / ablensq;
+
+ if (t >= 0.0 && t <= 1.0) {
+
+ /* Find the point on the edge closest to P */
+ float2 reflect_point = edgepoint1 + (t * ab);
+ /* This is the vector to P, so 90 degrees out from the edge. */
+ float2 reflect_vec = reflect_point - point;
+
+ float reflectLen = sqrt(reflect_vec[0] * reflect_vec[0] + reflect_vec[1] * reflect_vec[1]);
+ float cross = ab[0] * reflect_vec[1] - ab[1] * reflect_vec[0];
+ /* Only if P is on the outside of the edge, which means the cross product is positive,
+ * we consider this edge.
+ */
+ bool valid = (cross > 0.0);
+
+ if (valid && (found_dist < 0 || reflectLen < found_dist)) {
+ /* Stother_ab the info of the closest edge so far. */
+ found_dist = reflectLen;
+ found_t = t;
+ found_edge = i + mpoly_[src_poly].loopstart;
+ }
+ }
+ }
+
+ if (found_edge < 0) {
+ return false;
+ }
+
+ /* Get the 'other' edge. I.E. the UV edge from the neighbor polygon. */
+ int other_edge = loop_adjacency_map_[found_edge];
+
+ if (other_edge < 0) {
+ return false;
+ }
+
+ int dst_poly = loop_to_poly_map_[other_edge];
+
+ if (r_other_poly) {
+ *r_other_poly = dst_poly;
+ }
+
+ int other_edge2 = other_edge + 1;
+ if (other_edge2 >= mpoly_[dst_poly].loopstart + mpoly_[dst_poly].totloop) {
+ other_edge2 = mpoly_[dst_poly].loopstart;
+ }
+
+ float2 other_edgepoint1 = uv_to_xy(mloopuv_[other_edge]);
+ float2 other_edgepoint2 = uv_to_xy(mloopuv_[other_edge2]);
+
+ /* Calculate the vector from the order edges last point to it's first point. */
+ float2 other_ab = other_edgepoint1 - other_edgepoint2;
+ float2 other_reflect_point = other_edgepoint2 + (found_t * other_ab);
+ float2 perpendicular_other_ab;
+ perpendicular_other_ab.x = other_ab.y;
+ perpendicular_other_ab.y = -other_ab.x;
+
+ /* The new point is dound_dist distance from other_reflect_point at a 90 degree angle to
+ * other_ab */
+ float2 new_point = other_reflect_point + (found_dist / math::length(perpendicular_other_ab)) *
+ perpendicular_other_ab;
+
+ *r_destx = new_point.x;
+ *r_desty = new_point.y;
+
+ return true;
+ }
+}; // class TextureMarginMap
+
+const int TextureMarginMap::directions[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
+
+static void generate_margin(ImBuf *ibuf,
+ char *mask,
+ const int margin,
+ const Mesh *me,
+ DerivedMesh *dm,
+ char const *uv_layer)
+{
+
+ MPoly *mpoly;
+ MLoop *mloop;
+ MLoopUV const *mloopuv;
+ int totpoly, totloop, totedge;
+
+ int tottri;
+ MLoopTri const *looptri;
+ MLoopTri *looptri_mem = NULL;
+
+ if (me) {
+ BLI_assert(dm == NULL);
+ totpoly = me->totpoly;
+ totloop = me->totloop;
+ totedge = me->totedge;
+ mpoly = me->mpoly;
+ mloop = me->mloop;
+
+ if ((uv_layer == NULL) || (uv_layer[0] == '\0')) {
+ mloopuv = static_cast<MLoopUV const *>(CustomData_get_layer(&me->ldata, CD_MLOOPUV));
+ }
+ else {
+ int uv_id = CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer);
+ mloopuv = static_cast<MLoopUV const *>(
+ CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, uv_id));
+ }
+
+ tottri = poly_to_tri_count(me->totpoly, me->totloop);
+ looptri_mem = static_cast<MLoopTri *>(MEM_mallocN(sizeof(*looptri) * tottri, __func__));
+ BKE_mesh_recalc_looptri(
+ me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri_mem);
+ looptri = looptri_mem;
+ }
+ else {
+ BLI_assert(dm != NULL);
+ BLI_assert(me == NULL);
+ BLI_assert(mloopuv == NULL);
+ totpoly = dm->getNumPolys(dm);
+ totedge = dm->getNumEdges(dm);
+ totloop = dm->getNumLoops(dm);
+ mpoly = dm->getPolyArray(dm);
+ mloop = dm->getLoopArray(dm);
+ mloopuv = (MLoopUV const *)dm->getLoopDataArray(dm, CD_MLOOPUV);
+
+ looptri = dm->getLoopTriArray(dm);
+ tottri = dm->getNumLoopTri(dm);
+ }
+
+ TextureMarginMap map(ibuf->x, ibuf->y, mpoly, mloop, mloopuv, totpoly, totloop, totedge);
+
+ bool draw_new_mask = false;
+ /* Now the map contains 3 sorts of values: 0xFFFFFFFF for empty pixels, `0x80000000 + polyindex`
+ * for margin pixels, just `polyindex` for poly pixels. */
+ if (mask) {
+ mask = (char *)MEM_dupallocN(mask);
+ }
+ else {
+ mask = (char *)MEM_callocN(sizeof(char) * ibuf->x * ibuf->y, __func__);
+ draw_new_mask = true;
+ }
+
+ for (int i = 0; i < tottri; i++) {
+ const MLoopTri *lt = &looptri[i];
+ float vec[3][2];
+
+ for (int a = 0; a < 3; a++) {
+ const float *uv = mloopuv[lt->tri[a]].uv;
+
+ /* NOTE(campbell): workaround for pixel aligned UVs which are common and can screw up our
+ * intersection tests where a pixel gets in between 2 faces or the middle of a quad,
+ * camera aligned quads also have this problem but they are less common.
+ * Add a small offset to the UVs, fixes bug T18685. */
+ vec[a][0] = uv[0] * (float)ibuf->x - (0.5f + 0.001f);
+ vec[a][1] = uv[1] * (float)ibuf->y - (0.5f + 0.002f);
+ }
+
+ BLI_assert(lt->poly < 0x80000000); // NOTE: we need the top bit for the dijkstra distance map
+ map.rasterize_tri(vec[0], vec[1], vec[2], lt->poly, draw_new_mask ? mask : NULL);
+ }
+
+ char *tmpmask = (char *)MEM_dupallocN(mask);
+ /* Extend (with averaging) by 2 pixels. Those will be overwritten, but it
+ * helps linear interpolations on the edges of polygons. */
+ IMB_filter_extend(ibuf, tmpmask, 2);
+ MEM_freeN(tmpmask);
+
+ map.grow_dijkstra(margin);
+
+ /* Looking further than 3 polygons away leads to so much cumulative rounding
+ * that it isn't worth it. So hard-code it to 3. */
+ map.lookup_pixels(ibuf, mask, 3);
+
+ /* Use the extend filter to fill in the missing pixels at the corners, not strictly correct, but
+ * the visual difference seems very minimal. This also catches pixels we missed because of very
+ * narrow polygons.
+ */
+ IMB_filter_extend(ibuf, mask, margin);
+
+ MEM_freeN(mask);
+
+ if (looptri_mem) {
+ MEM_freeN(looptri_mem);
+ }
+}
+
+} // namespace blender::render::texturemargin
+
+void RE_generate_texturemargin_adjacentfaces(
+ ImBuf *ibuf, char *mask, const int margin, const Mesh *me, char const *uv_layer)
+{
+ blender::render::texturemargin::generate_margin(ibuf, mask, margin, me, NULL, uv_layer);
+}
+
+void RE_generate_texturemargin_adjacentfaces_dm(ImBuf *ibuf,
+ char *mask,
+ const int margin,
+ DerivedMesh *dm)
+{
+ blender::render::texturemargin::generate_margin(ibuf, mask, margin, NULL, dm, NULL);
+}
diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c
index 8ca1decdea7..683260f86cb 100644
--- a/source/blender/render/intern/texture_pointdensity.c
+++ b/source/blender/render/intern/texture_pointdensity.c
@@ -47,6 +47,7 @@
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_lattice.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
@@ -368,19 +369,11 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd,
}
}
-static void pointdensity_cache_vertex_normal(PointDensity *pd,
- Object *UNUSED(ob),
- Mesh *mesh,
- float *data_color)
+static void pointdensity_cache_vertex_normal(Mesh *mesh, float *data_color)
{
- MVert *mvert = mesh->mvert, *mv;
- int i;
-
BLI_assert(data_color);
-
- for (i = 0, mv = mvert; i < pd->totpoints; i++, mv++, data_color += 3) {
- normal_short_to_float_v3(data_color, mv->no);
- }
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ memcpy(data_color, vert_normals, sizeof(float[3]) * mesh->totvert);
}
static void pointdensity_cache_object(PointDensity *pd, Object *ob)
@@ -442,7 +435,7 @@ static void pointdensity_cache_object(PointDensity *pd, Object *ob)
pointdensity_cache_vertex_weight(pd, ob, mesh, data_color);
break;
case TEX_PD_COLOR_VERTNOR:
- pointdensity_cache_vertex_normal(pd, ob, mesh, data_color);
+ pointdensity_cache_vertex_normal(mesh, data_color);
break;
}
diff --git a/source/blender/render/intern/texture_procedural.c b/source/blender/render/intern/texture_procedural.c
index f563cb9f84a..c894d8d9f48 100644
--- a/source/blender/render/intern/texture_procedural.c
+++ b/source/blender/render/intern/texture_procedural.c
@@ -43,15 +43,15 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
-#include "BKE_image.h"
-#include "BKE_node.h"
-
#include "BKE_colorband.h"
+#include "BKE_image.h"
#include "BKE_material.h"
+#include "BKE_node.h"
#include "BKE_scene.h"
-
#include "BKE_texture.h"
+#include "NOD_texture.h"
+
#include "MEM_guardedalloc.h"
#include "render_types.h"
diff --git a/source/blender/render/intern/zbuf.c b/source/blender/render/intern/zbuf.c
index 1812a492ac0..beba10ad82a 100644
--- a/source/blender/render/intern/zbuf.c
+++ b/source/blender/render/intern/zbuf.c
@@ -19,6 +19,9 @@
/** \file
* \ingroup render
+ *
+ * \note Some of this logic has been duplicated in `COM_VectorBlurOperation.cc`
+ * changes here may also apply also apply to that file.
*/
/*---------------------------------------------------------------------------*/
diff --git a/source/blender/render/intern/zbuf.h b/source/blender/render/intern/zbuf.h
index c5108a9d6a7..3e4832e04d6 100644
--- a/source/blender/render/intern/zbuf.h
+++ b/source/blender/render/intern/zbuf.h
@@ -24,7 +24,7 @@
extern "C" {
#endif
-/* span fill in method, is also used to localize data for zbuffering */
+/** Span fill in method, is also used to localize data for Z-buffering. */
typedef struct ZSpan {
int rectx, recty; /* range for clipping */
diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt
index eccc336141a..54524e453d4 100644
--- a/source/blender/sequencer/CMakeLists.txt
+++ b/source/blender/sequencer/CMakeLists.txt
@@ -46,6 +46,7 @@ set(INC_SYS
set(SRC
SEQ_add.h
+ SEQ_animation.h
SEQ_clipboard.h
SEQ_edit.h
SEQ_effects.h
@@ -62,6 +63,7 @@ set(SRC
SEQ_transform.h
SEQ_utils.h
+ intern/animation.c
intern/clipboard.c
intern/disk_cache.c
intern/disk_cache.h
diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h
index 936868725b4..85f44ab914f 100644
--- a/source/blender/sequencer/SEQ_add.h
+++ b/source/blender/sequencer/SEQ_add.h
@@ -79,8 +79,8 @@ typedef struct SeqLoadData {
void SEQ_add_load_data_init(struct SeqLoadData *load_data,
const char *name,
const char *path,
- const int start_frame,
- const int channel);
+ int start_frame,
+ int channel);
/**
* Add image strip.
* \note Use #SEQ_add_image_set_directory() and #SEQ_add_image_load_file() to load image sequences
@@ -109,7 +109,7 @@ struct Sequence *SEQ_add_sound_strip(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct SeqLoadData *load_data,
- const double audio_offset);
+ double audio_offset);
/**
* Add meta strip.
*
@@ -206,7 +206,7 @@ void SEQ_add_image_init_alpha_mode(struct Sequence *seq);
void SEQ_add_reload_new_file(struct Main *bmain,
struct Scene *scene,
struct Sequence *seq,
- const bool lock_range);
+ bool lock_range);
void SEQ_add_movie_reload_if_needed(struct Main *bmain,
struct Scene *scene,
struct Sequence *seq,
diff --git a/source/blender/sequencer/SEQ_animation.h b/source/blender/sequencer/SEQ_animation.h
new file mode 100644
index 00000000000..028f932344f
--- /dev/null
+++ b/source/blender/sequencer/SEQ_animation.h
@@ -0,0 +1,41 @@
+/*
+ * 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) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct GSet;
+struct ListBase;
+struct Scene;
+struct Sequence;
+
+void SEQ_free_animdata(struct Scene *scene, struct Sequence *seq);
+void SEQ_offset_animdata(struct Scene *scene, struct Sequence *seq, int ofs);
+struct GSet *SEQ_fcurves_by_strip_get(const struct Sequence *seq, struct ListBase *fcurve_base);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/sequencer/SEQ_clipboard.h b/source/blender/sequencer/SEQ_clipboard.h
index 72388c5db64..dc78f8cc1a2 100644
--- a/source/blender/sequencer/SEQ_clipboard.h
+++ b/source/blender/sequencer/SEQ_clipboard.h
@@ -33,6 +33,7 @@ struct Scene;
struct Sequence;
extern struct ListBase seqbase_clipboard;
+extern struct ListBase fcurves_clipboard;
extern int seqbase_clipboard_frame;
void SEQ_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase);
void SEQ_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);
diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h
index fe12ac253b9..73723c23920 100644
--- a/source/blender/sequencer/SEQ_edit.h
+++ b/source/blender/sequencer/SEQ_edit.h
@@ -90,8 +90,8 @@ struct Sequence *SEQ_edit_strip_split(struct Main *bmain,
struct Scene *scene,
struct ListBase *seqbase,
struct Sequence *seq,
- const int timeline_frame,
- const eSeqSplitMethod method,
+ int timeline_frame,
+ eSeqSplitMethod method,
const char **r_error);
/**
* Find gap after initial_frame and move strips on right side to close the gap
@@ -104,8 +104,8 @@ struct Sequence *SEQ_edit_strip_split(struct Main *bmain,
*/
bool SEQ_edit_remove_gaps(struct Scene *scene,
struct ListBase *seqbase,
- const int initial_frame,
- const bool remove_all_gaps);
+ int initial_frame,
+ bool remove_all_gaps);
void SEQ_edit_sequence_name_set(struct Scene *scene, struct Sequence *seq, const char *new_name);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/SEQ_effects.h b/source/blender/sequencer/SEQ_effects.h
index 4bd5b54b36b..8a79abde7bc 100644
--- a/source/blender/sequencer/SEQ_effects.h
+++ b/source/blender/sequencer/SEQ_effects.h
@@ -59,19 +59,19 @@ struct SeqEffectHandle {
void (*load)(struct Sequence *seqconst);
/* duplicate */
- void (*copy)(struct Sequence *dst, struct Sequence *src, const int flag);
+ void (*copy)(struct Sequence *dst, struct Sequence *src, int flag);
/* destruct */
- void (*free)(struct Sequence *seq, const bool do_id_user);
+ void (*free)(struct Sequence *seq, bool do_id_user);
/* returns: -1: no input needed,
* 0: no early out,
* 1: out = ibuf1,
* 2: out = ibuf2 */
- int (*early_out)(struct Sequence *seq, float facf0, float facf1);
+ int (*early_out)(struct Sequence *seq, float fac);
- /* stores the default facf0 and facf1 if no IPO is present */
- void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *facf0, float *facf1);
+ /* sets the default `fac` value */
+ void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *fac);
/* execute the effect
* sequence effects are only required to either support
@@ -81,8 +81,7 @@ struct SeqEffectHandle {
struct ImBuf *(*execute)(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
struct ImBuf *ibuf1,
struct ImBuf *ibuf2,
struct ImBuf *ibuf3);
@@ -95,8 +94,7 @@ struct SeqEffectHandle {
void (*execute_slice)(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
struct ImBuf *ibuf1,
struct ImBuf *ibuf2,
struct ImBuf *ibuf3,
@@ -107,8 +105,8 @@ struct SeqEffectHandle {
struct SeqEffectHandle SEQ_effect_handle_get(struct Sequence *seq);
int SEQ_effect_get_num_inputs(int seq_type);
-void SEQ_effect_text_font_unload(struct TextVars *data, const bool do_id_user);
-void SEQ_effect_text_font_load(struct TextVars *data, const bool do_id_user);
+void SEQ_effect_text_font_unload(struct TextVars *data, bool do_id_user);
+void SEQ_effect_text_font_load(struct TextVars *data, bool do_id_user);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h
index 2826e6b75cb..c26886c2e6c 100644
--- a/source/blender/sequencer/SEQ_iterator.h
+++ b/source/blender/sequencer/SEQ_iterator.h
@@ -225,8 +225,8 @@ SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase);
* \return strip collection
*/
SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
- const int timeline_frame,
- const int displayed_channel);
+ int timeline_frame,
+ 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
diff --git a/source/blender/sequencer/SEQ_proxy.h b/source/blender/sequencer/SEQ_proxy.h
index 7bfe932ff1c..164b279245c 100644
--- a/source/blender/sequencer/SEQ_proxy.h
+++ b/source/blender/sequencer/SEQ_proxy.h
@@ -42,7 +42,8 @@ bool SEQ_proxy_rebuild_context(struct Main *bmain,
struct Scene *scene,
struct Sequence *seq,
struct GSet *file_list,
- struct ListBase *queue);
+ struct ListBase *queue,
+ bool build_only_on_bad_performance);
void SEQ_proxy_rebuild(struct SeqIndexBuildContext *context,
short *stop,
short *do_update,
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index a3ee716c3f6..2e340049dbd 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -68,7 +68,7 @@ int SEQ_tool_settings_pivot_point_get(struct Scene *scene);
struct SequencerToolSettings *SEQ_tool_settings_copy(struct SequencerToolSettings *tool_settings);
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);
+void SEQ_editing_free(struct Scene *scene, bool do_id_user);
/**
* Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
*
@@ -84,7 +84,7 @@ struct ListBase *SEQ_active_seqbase_get(const struct Editing *ed);
*/
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);
+void SEQ_sequence_free(struct Scene *scene, struct Sequence *seq);
/**
* Create and initialize #MetaStack, append it to `ed->metastack` ListBase
*
@@ -107,8 +107,6 @@ struct MetaStack *SEQ_meta_stack_active_get(const struct Editing *ed);
* \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);
struct Sequence *SEQ_sequence_dupli_recursive(const struct Scene *scene_src,
struct Scene *scene_dst,
struct ListBase *new_seq_list,
@@ -119,7 +117,7 @@ void SEQ_sequence_base_dupli_recursive(const struct Scene *scene_src,
struct ListBase *nseqbase,
const struct ListBase *seqbase,
int dupe_flag,
- const int flag);
+ int flag);
bool SEQ_valid_strip_channel(struct Sequence *seq);
/**
diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h
index e563e94da24..f08220e4958 100644
--- a/source/blender/sequencer/SEQ_time.h
+++ b/source/blender/sequencer/SEQ_time.h
@@ -59,10 +59,10 @@ void SEQ_timeline_boundbox(const struct Scene *scene,
float SEQ_time_sequence_get_fps(struct Scene *scene, struct Sequence *seq);
int SEQ_time_find_next_prev_edit(struct Scene *scene,
int timeline_frame,
- const short side,
- const bool do_skip_mute,
- const bool do_center,
- const bool do_unselected);
+ short side,
+ bool do_skip_mute,
+ bool do_center,
+ 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);
/**
@@ -74,7 +74,7 @@ void SEQ_time_update_recursive(struct Scene *scene, struct Sequence *changed_seq
* \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);
+bool SEQ_time_strip_intersects_frame(const struct Sequence *seq, int timeline_frame);
void SEQ_time_update_meta_strip_range(struct Scene *scene, struct Sequence *seq_meta);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h
index fe0c223bcb1..00d1f1c9955 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -65,7 +65,7 @@ bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
struct ListBase *seqbasep,
struct Scene *evil_scene,
struct ListBase *markers,
- const bool use_sync_markers);
+ bool use_sync_markers);
/**
* Check if the selected seq's reference unselected seq's.
*/
@@ -80,8 +80,8 @@ bool SEQ_transform_seqbase_isolated_sel_check(struct ListBase *seqbase);
*/
void SEQ_transform_offset_after_frame(struct Scene *scene,
struct ListBase *seqbase,
- const int delta,
- const int timeline_frame);
+ int delta,
+ int timeline_frame);
/* Image transformation. */
diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h
index 58d7a92f370..515c47f53fd 100644
--- a/source/blender/sequencer/SEQ_utils.h
+++ b/source/blender/sequencer/SEQ_utils.h
@@ -32,9 +32,9 @@ extern "C" {
struct ListBase;
struct Mask;
struct Scene;
+struct SeqRenderData;
struct Sequence;
struct StripElem;
-struct SeqRenderData;
/**
* Sort strips in provided seqbase. Effect strips are trailing the list and they are sorted by
@@ -66,11 +66,11 @@ struct Mask *SEQ_active_mask_get(struct Scene *scene);
void SEQ_alpha_mode_from_file_extension(struct Sequence *seq);
bool SEQ_sequence_has_source(const struct Sequence *seq);
void SEQ_set_scale_to_fit(const struct Sequence *seq,
- const int image_width,
- const int image_height,
- const int preview_width,
- const int preview_height,
- const eSeqImageFitMethod fit_method);
+ int image_width,
+ int image_height,
+ int preview_width,
+ int preview_height,
+ 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
diff --git a/source/blender/sequencer/intern/animation.c b/source/blender/sequencer/intern/animation.c
new file mode 100644
index 00000000000..492b757a4b1
--- /dev/null
+++ b/source/blender/sequencer/intern/animation.c
@@ -0,0 +1,122 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2022 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup sequencer
+ */
+
+#include <string.h>
+
+#include "DNA_anim_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+
+#include "BKE_animsys.h"
+#include "BKE_fcurve.h"
+
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "DEG_depsgraph.h"
+
+#include "SEQ_animation.h"
+
+static bool seq_animation_curves_exist(Scene *scene)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL ||
+ BLI_listbase_is_empty(&scene->adt->action->curves)) {
+ return false;
+ }
+ return true;
+}
+
+/* r_prefix + [" + escaped_name + "] + \0 */
+#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1)
+
+static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name)
+{
+ char name_esc[SEQ_NAME_MAXSTR * 2];
+
+ BLI_str_escape(name_esc, name, sizeof(name_esc));
+ return BLI_snprintf_rlen(
+ str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
+}
+
+GSet *SEQ_fcurves_by_strip_get(const Sequence *seq, ListBase *fcurve_base)
+{
+ char rna_path[SEQ_RNAPATH_MAXSTR];
+ size_t rna_path_len = sequencer_rna_path_prefix(rna_path, seq->name + 2);
+
+ GSet *fcurves = BLI_gset_ptr_new(__func__);
+ LISTBASE_FOREACH (FCurve *, fcurve, fcurve_base) {
+ if (STREQLEN(fcurve->rna_path, rna_path, rna_path_len)) {
+ BLI_gset_add(fcurves, fcurve);
+ }
+ }
+
+ return fcurves;
+}
+
+#undef SEQ_RNAPATH_MAXSTR
+
+void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs)
+{
+ if (!seq_animation_curves_exist(scene) || ofs == 0) {
+ return;
+ }
+
+ GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
+ GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
+ unsigned int i;
+ if (fcu->bezt) {
+ for (i = 0; i < fcu->totvert; i++) {
+ BezTriple *bezt = &fcu->bezt[i];
+ bezt->vec[0][0] += ofs;
+ bezt->vec[1][0] += ofs;
+ bezt->vec[2][0] += ofs;
+ }
+ }
+ if (fcu->fpt) {
+ for (i = 0; i < fcu->totvert; i++) {
+ FPoint *fpt = &fcu->fpt[i];
+ fpt->vec[0] += ofs;
+ }
+ }
+ }
+ GSET_FOREACH_END();
+ BLI_gset_free(fcurves, NULL);
+
+ DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION);
+}
+
+void SEQ_free_animdata(Scene *scene, Sequence *seq)
+{
+ if (!seq_animation_curves_exist(scene)) {
+ return;
+ }
+
+ GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
+ GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
+ BLI_remlink(&scene->adt->action->curves, fcu);
+ BKE_fcurve_free(fcu);
+ }
+ GSET_FOREACH_END();
+ BLI_gset_free(fcurves, NULL);
+}
diff --git a/source/blender/sequencer/intern/clipboard.c b/source/blender/sequencer/intern/clipboard.c
index 73e0f616da4..886ee89595b 100644
--- a/source/blender/sequencer/intern/clipboard.c
+++ b/source/blender/sequencer/intern/clipboard.c
@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_anim_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
@@ -35,6 +36,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BKE_fcurve.h"
#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_scene.h"
@@ -58,6 +60,7 @@
*/
ListBase seqbase_clipboard;
+ListBase fcurves_clipboard;
int seqbase_clipboard_frame;
static char seq_clipboard_active_seq_name[SEQ_NAME_MAXSTR];
@@ -65,15 +68,17 @@ void seq_clipboard_pointers_free(struct ListBase *seqbase);
void SEQ_clipboard_free(void)
{
- Sequence *seq, *nseq;
-
seq_clipboard_pointers_free(&seqbase_clipboard);
- for (seq = seqbase_clipboard.first; seq; seq = nseq) {
- nseq = seq->next;
- seq_free_sequence_recurse(NULL, seq, false, true);
+ LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqbase_clipboard) {
+ seq_free_sequence_recurse(NULL, seq, false);
}
BLI_listbase_clear(&seqbase_clipboard);
+
+ LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &fcurves_clipboard) {
+ BKE_fcurve_free(fcu);
+ }
+ BLI_listbase_clear(&fcurves_clipboard);
}
#define ID_PT (*id_pt)
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index 05ce35deeec..a35e83a8632 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -206,69 +206,22 @@ static void init_alpha_over_or_under(Sequence *seq)
seq->seq1 = seq2;
}
-static void do_alphaover_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- float fac2, mfac, fac, fac4;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float tempc[4], rt1[4], rt2[4];
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- /* rt = rt1 over rt2 (alpha from rt1) */
-
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
-
- fac = fac2;
- mfac = 1.0f - fac2 * rt1[3];
-
- if (fac <= 0.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp2);
- }
- else if (mfac <= 0.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp1);
- }
- else {
- tempc[0] = fac * rt1[0] + mfac * rt2[0];
- tempc[1] = fac * rt1[1] + mfac * rt2[1];
- tempc[2] = fac * rt1[2] + mfac * rt2[2];
- tempc[3] = fac * rt1[3] + mfac * rt2[3];
-
- premul_float_to_straight_uchar(rt, tempc);
- }
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
+static void do_alphaover_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- if (y == 0) {
- break;
- }
- y--;
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ /* rt = rt1 over rt2 (alpha from rt1) */
- x = xo;
- while (x--) {
+ float tempc[4], rt1[4], rt2[4];
straight_uchar_to_premul_float(rt1, cp1);
straight_uchar_to_premul_float(rt2, cp2);
- fac = fac4;
- mfac = 1.0f - (fac4 * rt1[3]);
+ float mfac = 1.0f - fac * rt1[3];
if (fac <= 0.0f) {
*((unsigned int *)rt) = *((unsigned int *)cp2);
@@ -292,27 +245,17 @@ static void do_alphaover_effect_byte(float facf0,
}
static void do_alphaover_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac2, mfac, fac, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
/* rt = rt1 over rt2 (alpha from rt1) */
- fac = fac2;
- mfac = 1.0f - (fac2 * rt1[3]);
+ float mfac = 1.0f - (fac * rt1[3]);
if (fac <= 0.0f) {
memcpy(rt, rt2, sizeof(float[4]));
@@ -330,41 +273,13 @@ static void do_alphaover_effect_float(
rt2 += 4;
rt += 4;
}
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- fac = fac4;
- mfac = 1.0f - (fac4 * rt1[3]);
-
- if (fac <= 0.0f) {
- memcpy(rt, rt2, sizeof(float[4]));
- }
- else if (mfac <= 0.0f) {
- memcpy(rt, rt1, sizeof(float[4]));
- }
- else {
- rt[0] = fac * rt1[0] + mfac * rt2[0];
- rt[1] = fac * rt1[1] + mfac * rt2[1];
- rt[2] = fac * rt1[2] + mfac * rt2[2];
- rt[3] = fac * rt1[3] + mfac * rt2[3];
- }
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
}
}
static void do_alphaover_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -378,7 +293,7 @@ static void do_alphaover_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaover_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaover_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -386,96 +301,47 @@ static void do_alphaover_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaover_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaover_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Alpha Under *************************/
-static void do_alphaunder_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- float fac2, fac, fac4;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float tempc[4], rt1[4], rt2[4];
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
+static void do_alphaunder_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
+
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
/* rt = rt1 under rt2 (alpha from rt2) */
+
+ float tempc[4], rt1[4], rt2[4];
straight_uchar_to_premul_float(rt1, cp1);
straight_uchar_to_premul_float(rt2, cp2);
/* this complex optimization is because the
* 'skybuf' can be crossed in
*/
- if (rt2[3] <= 0.0f && fac2 >= 1.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp1);
- }
- else if (rt2[3] >= 1.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp2);
- }
- else {
- fac = (fac2 * (1.0f - rt2[3]));
-
- if (fac <= 0) {
- *((unsigned int *)rt) = *((unsigned int *)cp2);
- }
- else {
- tempc[0] = (fac * rt1[0] + rt2[0]);
- tempc[1] = (fac * rt1[1] + rt2[1]);
- tempc[2] = (fac * rt1[2] + rt2[2]);
- tempc[3] = (fac * rt1[3] + rt2[3]);
-
- premul_float_to_straight_uchar(rt, tempc);
- }
- }
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
-
- if (rt2[3] <= 0.0f && fac4 >= 1.0f) {
+ if (rt2[3] <= 0.0f && fac >= 1.0f) {
*((unsigned int *)rt) = *((unsigned int *)cp1);
}
else if (rt2[3] >= 1.0f) {
*((unsigned int *)rt) = *((unsigned int *)cp2);
}
else {
- fac = (fac4 * (1.0f - rt2[3]));
+ float temp_fac = (fac * (1.0f - rt2[3]));
if (fac <= 0) {
*((unsigned int *)rt) = *((unsigned int *)cp2);
}
else {
- tempc[0] = (fac * rt1[0] + rt2[0]);
- tempc[1] = (fac * rt1[1] + rt2[1]);
- tempc[2] = (fac * rt1[2] + rt2[2]);
- tempc[3] = (fac * rt1[3] + rt2[3]);
+ tempc[0] = (temp_fac * rt1[0] + rt2[0]);
+ tempc[1] = (temp_fac * rt1[1] + rt2[1]);
+ tempc[2] = (temp_fac * rt1[2] + rt2[2]);
+ tempc[3] = (temp_fac * rt1[3] + rt2[3]);
premul_float_to_straight_uchar(rt, tempc);
}
@@ -488,76 +354,36 @@ static void do_alphaunder_effect_byte(float facf0,
}
static void do_alphaunder_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac2, fac, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- while (y--) {
- x = xo;
- while (x--) {
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
/* rt = rt1 under rt2 (alpha from rt2) */
/* this complex optimization is because the
* 'skybuf' can be crossed in
*/
- if (rt2[3] <= 0 && fac2 >= 1.0f) {
+ if (rt2[3] <= 0 && fac >= 1.0f) {
memcpy(rt, rt1, sizeof(float[4]));
}
else if (rt2[3] >= 1.0f) {
memcpy(rt, rt2, sizeof(float[4]));
}
else {
- fac = fac2 * (1.0f - rt2[3]);
+ float temp_fac = fac * (1.0f - rt2[3]);
if (fac == 0) {
memcpy(rt, rt2, sizeof(float[4]));
}
else {
- rt[0] = fac * rt1[0] + rt2[0];
- rt[1] = fac * rt1[1] + rt2[1];
- rt[2] = fac * rt1[2] + rt2[2];
- rt[3] = fac * rt1[3] + rt2[3];
- }
- }
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- if (rt2[3] <= 0 && fac4 >= 1.0f) {
- memcpy(rt, rt1, sizeof(float[4]));
- }
- else if (rt2[3] >= 1.0f) {
- memcpy(rt, rt2, sizeof(float[4]));
- }
- else {
- fac = fac4 * (1.0f - rt2[3]);
-
- if (fac == 0) {
- memcpy(rt, rt2, sizeof(float[4]));
- }
- else {
- rt[0] = fac * rt1[0] + rt2[0];
- rt[1] = fac * rt1[1] + rt2[1];
- rt[2] = fac * rt1[2] + rt2[2];
- rt[3] = fac * rt1[3] + rt2[3];
+ rt[0] = temp_fac * rt1[0] + rt2[0];
+ rt[1] = temp_fac * rt1[1] + rt2[1];
+ rt[2] = temp_fac * rt1[2] + rt2[2];
+ rt[3] = temp_fac * rt1[3] + rt2[3];
}
}
rt1 += 4;
@@ -570,8 +396,7 @@ static void do_alphaunder_effect_float(
static void do_alphaunder_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -585,7 +410,7 @@ static void do_alphaunder_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaunder_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaunder_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -593,58 +418,28 @@ static void do_alphaunder_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaunder_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaunder_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Cross *************************/
-static void do_cross_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
+static void do_cross_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
- int fac1, fac2, fac3, fac4;
- int xo;
- unsigned char *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = (int)(256.0f * facf0);
- fac1 = 256 - fac2;
- fac4 = (int)(256.0f * facf1);
- fac3 = 256 - fac4;
-
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = (fac1 * rt1[0] + fac2 * rt2[0]) >> 8;
- rt[1] = (fac1 * rt1[1] + fac2 * rt2[1]) >> 8;
- rt[2] = (fac1 * rt1[2] + fac2 * rt2[2]) >> 8;
- rt[3] = (fac1 * rt1[3] + fac2 * rt2[3]) >> 8;
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
+ unsigned char *rt1 = rect1;
+ unsigned char *rt2 = rect2;
+ unsigned char *rt = out;
- if (y == 0) {
- break;
- }
- y--;
+ int temp_fac = (int)(256.0f * fac);
+ int temp_mfac = 256 - temp_fac;
- x = xo;
- while (x--) {
- rt[0] = (fac3 * rt1[0] + fac4 * rt2[0]) >> 8;
- rt[1] = (fac3 * rt1[1] + fac4 * rt2[1]) >> 8;
- rt[2] = (fac3 * rt1[2] + fac4 * rt2[2]) >> 8;
- rt[3] = (fac3 * rt1[3] + fac4 * rt2[3]) >> 8;
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = (temp_mfac * rt1[0] + temp_fac * rt2[0]) >> 8;
+ rt[1] = (temp_mfac * rt1[1] + temp_fac * rt2[1]) >> 8;
+ rt[2] = (temp_mfac * rt1[2] + temp_fac * rt2[2]) >> 8;
+ rt[3] = (temp_mfac * rt1[3] + temp_fac * rt2[3]) >> 8;
rt1 += 4;
rt2 += 4;
@@ -653,47 +448,20 @@ static void do_cross_effect_byte(float facf0,
}
}
-static void do_cross_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_cross_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac1, fac2, fac3, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac1 = 1.0f - fac2;
- fac4 = facf1;
- fac3 = 1.0f - fac4;
-
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = fac1 * rt1[0] + fac2 * rt2[0];
- rt[1] = fac1 * rt1[1] + fac2 * rt2[1];
- rt[2] = fac1 * rt1[2] + fac2 * rt2[2];
- rt[3] = fac1 * rt1[3] + fac2 * rt2[3];
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- if (y == 0) {
- break;
- }
- y--;
+ float mfac = 1.0f - fac;
- x = xo;
- while (x--) {
- rt[0] = fac3 * rt1[0] + fac4 * rt2[0];
- rt[1] = fac3 * rt1[1] + fac4 * rt2[1];
- rt[2] = fac3 * rt1[2] + fac4 * rt2[2];
- rt[3] = fac3 * rt1[3] + fac4 * rt2[3];
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = mfac * rt1[0] + fac * rt2[0];
+ rt[1] = mfac * rt1[1] + fac * rt2[1];
+ rt[2] = mfac * rt1[2] + fac * rt2[2];
+ rt[3] = mfac * rt1[3] + fac * rt2[3];
rt1 += 4;
rt2 += 4;
@@ -705,8 +473,7 @@ static void do_cross_effect_float(
static void do_cross_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -720,7 +487,7 @@ static void do_cross_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_cross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_cross_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -728,7 +495,7 @@ static void do_cross_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_cross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_cross_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
@@ -888,58 +655,26 @@ static void free_gammacross(Sequence *UNUSED(seq), const bool UNUSED(do_id_user)
{
}
-static void do_gammacross_effect_byte(float facf0,
- float UNUSED(facf1),
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
+static void do_gammacross_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
- float fac1, fac2;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float rt1[4], rt2[4], tempc[4];
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac1 = 1.0f - fac2;
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- while (y--) {
- x = xo;
- while (x--) {
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
+ float mfac = 1.0f - fac;
- tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0]));
- tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1]));
- tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2]));
- tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3]));
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float rt1[4], rt2[4], tempc[4];
- premul_float_to_straight_uchar(rt, tempc);
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
straight_uchar_to_premul_float(rt1, cp1);
straight_uchar_to_premul_float(rt2, cp2);
- tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0]));
- tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1]));
- tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2]));
- tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3]));
+ tempc[0] = gammaCorrect(mfac * invGammaCorrect(rt1[0]) + fac * invGammaCorrect(rt2[0]));
+ tempc[1] = gammaCorrect(mfac * invGammaCorrect(rt1[1]) + fac * invGammaCorrect(rt2[1]));
+ tempc[2] = gammaCorrect(mfac * invGammaCorrect(rt1[2]) + fac * invGammaCorrect(rt2[2]));
+ tempc[3] = gammaCorrect(mfac * invGammaCorrect(rt1[3]) + fac * invGammaCorrect(rt2[3]));
premul_float_to_straight_uchar(rt, tempc);
cp1 += 4;
@@ -950,38 +685,17 @@ static void do_gammacross_effect_byte(float facf0,
}
static void do_gammacross_effect_float(
- float facf0, float UNUSED(facf1), int x, int y, float *rect1, float *rect2, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac1, fac2;
- int xo;
- float *rt1, *rt2, *rt;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac1 = 1.0f - fac2;
-
- while (y--) {
- x = xo * 4;
- while (x--) {
- *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2));
- rt1++;
- rt2++;
- rt++;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo * 4;
- while (x--) {
- *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2));
+ float mfac = 1.0f - fac;
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ *rt = gammaCorrect(mfac * invGammaCorrect(*rt1) + fac * invGammaCorrect(*rt2));
rt1++;
rt2++;
rt++;
@@ -1003,8 +717,7 @@ static struct ImBuf *gammacross_init_execution(const SeqRenderData *context,
static void do_gammacross_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1018,7 +731,7 @@ static void do_gammacross_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_gammacross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_gammacross_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1026,57 +739,27 @@ static void do_gammacross_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_gammacross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_gammacross_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Add *************************/
-static void do_add_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- int xo, fac1, fac3;
- unsigned char *cp1, *cp2, *rt;
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac1 = (int)(256.0f * facf0);
- fac3 = (int)(256.0f * facf1);
-
- while (y--) {
- x = xo;
-
- while (x--) {
- const int m = fac1 * (int)cp2[3];
- rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
- rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
- rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
- rt[3] = cp1[3];
+static void do_add_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
+ int temp_fac = (int)(256.0f * fac);
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const int m = fac3 * (int)cp2[3];
- rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
- rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
- rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const int temp_fac2 = temp_fac * (int)cp2[3];
+ rt[0] = min_ii(cp1[0] + ((temp_fac2 * cp2[0]) >> 16), 255);
+ rt[1] = min_ii(cp1[1] + ((temp_fac2 * cp2[1]) >> 16), 255);
+ rt[2] = min_ii(cp1[2] + ((temp_fac2 * cp2[2]) >> 16), 255);
rt[3] = cp1[3];
cp1 += 4;
@@ -1086,46 +769,18 @@ static void do_add_effect_byte(float facf0,
}
}
-static void do_add_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_add_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- int xo;
- float fac1, fac3;
- float *rt1, *rt2, *rt;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac1 = facf0;
- fac3 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * (1.0f - fac1))) * rt2[3];
- rt[0] = rt1[0] + m * rt2[0];
- rt[1] = rt1[1] + m * rt2[1];
- rt[2] = rt1[2] + m * rt2[2];
- rt[3] = rt1[3];
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * (1.0f - fac3))) * rt2[3];
- rt[0] = rt1[0] + m * rt2[0];
- rt[1] = rt1[1] + m * rt2[1];
- rt[2] = rt1[2] + m * rt2[2];
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const float temp_fac = (1.0f - (rt1[3] * (1.0f - fac))) * rt2[3];
+ rt[0] = rt1[0] + temp_fac * rt2[0];
+ rt[1] = rt1[1] + temp_fac * rt2[1];
+ rt[2] = rt1[2] + temp_fac * rt2[2];
rt[3] = rt1[3];
rt1 += 4;
@@ -1138,8 +793,7 @@ static void do_add_effect_float(
static void do_add_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1153,7 +807,7 @@ static void do_add_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_add_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_add_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1161,56 +815,27 @@ static void do_add_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_add_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_add_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Sub *************************/
-static void do_sub_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- int xo, fac1, fac3;
- unsigned char *cp1, *cp2, *rt;
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac1 = (int)(256.0f * facf0);
- fac3 = (int)(256.0f * facf1);
-
- while (y--) {
- x = xo;
- while (x--) {
- const int m = fac1 * (int)cp2[3];
- rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
- rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
- rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
- rt[3] = cp1[3];
+static void do_sub_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
+ int temp_fac = (int)(256.0f * fac);
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const int m = fac3 * (int)cp2[3];
- rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
- rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
- rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const int temp_fac2 = temp_fac * (int)cp2[3];
+ rt[0] = max_ii(cp1[0] - ((temp_fac2 * cp2[0]) >> 16), 0);
+ rt[1] = max_ii(cp1[1] - ((temp_fac2 * cp2[1]) >> 16), 0);
+ rt[2] = max_ii(cp1[2] - ((temp_fac2 * cp2[2]) >> 16), 0);
rt[3] = cp1[3];
cp1 += 4;
@@ -1220,47 +845,20 @@ static void do_sub_effect_byte(float facf0,
}
}
-static void do_sub_effect_float(
- float UNUSED(facf0), float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_sub_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- int xo;
- float /* fac1, */ fac3_inv;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- /* UNUSED */
- // fac1 = facf0;
- fac3_inv = 1.0f - facf1;
+ float mfac = 1.0f - fac;
- while (y--) {
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
- rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
- rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
- rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
- rt[3] = rt1[3];
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
- rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
- rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
- rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const float temp_fac = (1.0f - (rt1[3] * mfac)) * rt2[3];
+ rt[0] = max_ff(rt1[0] - temp_fac * rt2[0], 0.0f);
+ rt[1] = max_ff(rt1[1] - temp_fac * rt2[1], 0.0f);
+ rt[2] = max_ff(rt1[2] - temp_fac * rt2[2], 0.0f);
rt[3] = rt1[3];
rt1 += 4;
@@ -1273,8 +871,7 @@ static void do_sub_effect_float(
static void do_sub_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1288,7 +885,7 @@ static void do_sub_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_sub_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_sub_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1296,7 +893,7 @@ static void do_sub_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_sub_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_sub_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
@@ -1306,161 +903,95 @@ static void do_sub_effect(const SeqRenderData *context,
#define XOFF 8
#define YOFF 8
-static void do_drop_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect2i,
- unsigned char *rect1i,
- unsigned char *outi)
-{
- int temp, fac, fac1, fac2;
- unsigned char *rt1, *rt2, *out;
- int field = 1;
-
- const int width = x;
- const int height = y;
- const int xoff = min_ii(XOFF, width);
- const int yoff = min_ii(YOFF, height);
-
- fac1 = (int)(70.0f * facf0);
- fac2 = (int)(70.0f * facf1);
-
- rt2 = rect2i + yoff * 4 * width;
- rt1 = rect1i;
- out = outi;
- for (y = 0; y < height - yoff; y++) {
- if (field) {
- fac = fac1;
- }
- else {
- fac = fac2;
- }
- field = !field;
+static void do_drop_effect_byte(
+ float fac, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi)
+{
+ const int xoff = min_ii(XOFF, x);
+ const int yoff = min_ii(YOFF, y);
+
+ int temp_fac = (int)(70.0f * fac);
+ unsigned char *rt2 = rect2i + yoff * 4 * x;
+ unsigned char *rt1 = rect1i;
+ unsigned char *out = outi;
+ for (int i = 0; i < y - yoff; i++) {
memcpy(out, rt1, sizeof(*out) * xoff * 4);
rt1 += xoff * 4;
out += xoff * 4;
- for (x = xoff; x < width; x++) {
- temp = ((fac * rt2[3]) >> 8);
+ for (int j = xoff; j < x; j++) {
+ int temp_fac2 = ((temp_fac * rt2[3]) >> 8);
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
rt2 += 4;
}
rt2 += xoff * 4;
}
- memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * x);
}
static void do_drop_effect_float(
- float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi)
-{
- float temp, fac, fac1, fac2;
- float *rt1, *rt2, *out;
- int field = 1;
-
- const int width = x;
- const int height = y;
- const int xoff = min_ii(XOFF, width);
- const int yoff = min_ii(YOFF, height);
-
- fac1 = 70.0f * facf0;
- fac2 = 70.0f * facf1;
-
- rt2 = rect2i + yoff * 4 * width;
- rt1 = rect1i;
- out = outi;
- for (y = 0; y < height - yoff; y++) {
- if (field) {
- fac = fac1;
- }
- else {
- fac = fac2;
- }
- field = !field;
+ float fac, int x, int y, float *rect2i, float *rect1i, float *outi)
+{
+ const int xoff = min_ii(XOFF, x);
+ const int yoff = min_ii(YOFF, y);
+
+ float temp_fac = 70.0f * fac;
+ float *rt2 = rect2i + yoff * 4 * x;
+ float *rt1 = rect1i;
+ float *out = outi;
+ for (int i = 0; i < y - yoff; i++) {
memcpy(out, rt1, sizeof(*out) * xoff * 4);
rt1 += xoff * 4;
out += xoff * 4;
- for (x = xoff; x < width; x++) {
- temp = fac * rt2[3];
+ for (int j = xoff; j < x; j++) {
+ float temp_fac2 = temp_fac * rt2[3];
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
rt2 += 4;
}
rt2 += xoff * 4;
}
- memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * x);
}
/*********************** Mul *************************/
-static void do_mul_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
+static void do_mul_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
- int xo, fac1, fac3;
- unsigned char *rt1, *rt2, *rt;
+ unsigned char *rt1 = rect1;
+ unsigned char *rt2 = rect2;
+ unsigned char *rt = out;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac1 = (int)(256.0f * facf0);
- fac3 = (int)(256.0f * facf1);
+ int temp_fac = (int)(256.0f * fac);
/* Formula:
* `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s;` // + centx
* `yaux = -s * px + c * py;` // + centy */
- while (y--) {
-
- x = xo;
- while (x--) {
-
- rt[0] = rt1[0] + ((fac1 * rt1[0] * (rt2[0] - 255)) >> 16);
- rt[1] = rt1[1] + ((fac1 * rt1[1] * (rt2[1] - 255)) >> 16);
- rt[2] = rt1[2] + ((fac1 * rt1[2] * (rt2[2] - 255)) >> 16);
- rt[3] = rt1[3] + ((fac1 * rt1[3] * (rt2[3] - 255)) >> 16);
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
-
- rt[0] = rt1[0] + ((fac3 * rt1[0] * (rt2[0] - 255)) >> 16);
- rt[1] = rt1[1] + ((fac3 * rt1[1] * (rt2[1] - 255)) >> 16);
- rt[2] = rt1[2] + ((fac3 * rt1[2] * (rt2[2] - 255)) >> 16);
- rt[3] = rt1[3] + ((fac3 * rt1[3] * (rt2[3] - 255)) >> 16);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = rt1[0] + ((temp_fac * rt1[0] * (rt2[0] - 255)) >> 16);
+ rt[1] = rt1[1] + ((temp_fac * rt1[1] * (rt2[1] - 255)) >> 16);
+ rt[2] = rt1[2] + ((temp_fac * rt1[2] * (rt2[2] - 255)) >> 16);
+ rt[3] = rt1[3] + ((temp_fac * rt1[3] * (rt2[3] - 255)) >> 16);
rt1 += 4;
rt2 += 4;
@@ -1469,48 +1000,21 @@ static void do_mul_effect_byte(float facf0,
}
}
-static void do_mul_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_mul_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- int xo;
- float fac1, fac3;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac1 = facf0;
- fac3 = facf1;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
/* Formula:
* `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a`. */
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = rt1[0] + fac1 * rt1[0] * (rt2[0] - 1.0f);
- rt[1] = rt1[1] + fac1 * rt1[1] * (rt2[1] - 1.0f);
- rt[2] = rt1[2] + fac1 * rt1[2] * (rt2[2] - 1.0f);
- rt[3] = rt1[3] + fac1 * rt1[3] * (rt2[3] - 1.0f);
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- rt[0] = rt1[0] + fac3 * rt1[0] * (rt2[0] - 1.0f);
- rt[1] = rt1[1] + fac3 * rt1[1] * (rt2[1] - 1.0f);
- rt[2] = rt1[2] + fac3 * rt1[2] * (rt2[2] - 1.0f);
- rt[3] = rt1[3] + fac3 * rt1[3] * (rt2[3] - 1.0f);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = rt1[0] + fac * rt1[0] * (rt2[0] - 1.0f);
+ rt[1] = rt1[1] + fac * rt1[1] * (rt2[1] - 1.0f);
+ rt[2] = rt1[2] + fac * rt1[2] * (rt2[2] - 1.0f);
+ rt[3] = rt1[3] + fac * rt1[3] * (rt2[3] - 1.0f);
rt1 += 4;
rt2 += 4;
@@ -1522,8 +1026,7 @@ static void do_mul_effect_float(
static void do_mul_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1537,7 +1040,7 @@ static void do_mul_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_mul_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_mul_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1545,7 +1048,7 @@ static void do_mul_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_mul_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_mul_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
@@ -1555,8 +1058,7 @@ typedef void (*IMB_blend_func_byte)(unsigned char *dst,
const unsigned char *src2);
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
-BLI_INLINE void apply_blend_function_byte(float facf0,
- float facf1,
+BLI_INLINE void apply_blend_function_byte(float fac,
int x,
int y,
unsigned char *rect1,
@@ -1564,33 +1066,16 @@ BLI_INLINE void apply_blend_function_byte(float facf0,
unsigned char *out,
IMB_blend_func_byte blend_function)
{
- int xo;
- unsigned char *rt1, *rt2, *rt;
- unsigned int achannel;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
- while (y--) {
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = (unsigned int)achannel * facf0;
- blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
- rt[3] = rt1[3];
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
- if (y == 0) {
- break;
- }
- y--;
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = (unsigned int)achannel * facf1;
+ unsigned char *rt1 = rect1;
+ unsigned char *rt2 = rect2;
+ unsigned char *rt = out;
+
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ unsigned int achannel = rt2[3];
+ rt2[3] = (unsigned int)achannel * fac;
blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
+ rt2[3] = achannel;
rt[3] = rt1[3];
rt1 += 4;
rt2 += 4;
@@ -1599,8 +1084,7 @@ BLI_INLINE void apply_blend_function_byte(float facf0,
}
}
-BLI_INLINE void apply_blend_function_float(float facf0,
- float facf1,
+BLI_INLINE void apply_blend_function_float(float fac,
int x,
int y,
float *rect1,
@@ -1608,33 +1092,16 @@ BLI_INLINE void apply_blend_function_float(float facf0,
float *out,
IMB_blend_func_float blend_function)
{
- int xo;
- float *rt1, *rt2, *rt;
- float achannel;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
- while (y--) {
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = achannel * facf0;
- blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
- rt[3] = rt1[3];
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
- if (y == 0) {
- break;
- }
- y--;
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = achannel * facf1;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
+
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float achannel = rt2[3];
+ rt2[3] = achannel * fac;
blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
+ rt2[3] = achannel;
rt[3] = rt1[3];
rt1 += 4;
rt2 += 4;
@@ -1644,89 +1111,78 @@ BLI_INLINE void apply_blend_function_float(float facf0,
}
static void do_blend_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, int btype, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, int btype, float *out)
{
switch (btype) {
case SEQ_TYPE_ADD:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_add_float);
break;
case SEQ_TYPE_SUB:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_sub_float);
break;
case SEQ_TYPE_MUL:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_mul_float);
break;
case SEQ_TYPE_DARKEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_darken_float);
break;
case SEQ_TYPE_COLOR_BURN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_burn_float);
break;
case SEQ_TYPE_LINEAR_BURN:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_linearburn_float);
break;
case SEQ_TYPE_SCREEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_screen_float);
break;
case SEQ_TYPE_LIGHTEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_lighten_float);
break;
case SEQ_TYPE_DODGE:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_dodge_float);
break;
case SEQ_TYPE_OVERLAY:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_overlay_float);
break;
case SEQ_TYPE_SOFT_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_softlight_float);
break;
case SEQ_TYPE_HARD_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_hardlight_float);
break;
case SEQ_TYPE_PIN_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_pinlight_float);
break;
case SEQ_TYPE_LIN_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_linearlight_float);
break;
case SEQ_TYPE_VIVID_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_vividlight_float);
break;
case SEQ_TYPE_BLEND_COLOR:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_color_float);
break;
case SEQ_TYPE_HUE:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_hue_float);
break;
case SEQ_TYPE_SATURATION:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_saturation_float);
break;
case SEQ_TYPE_VALUE:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_luminosity_float);
break;
case SEQ_TYPE_DIFFERENCE:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_difference_float);
break;
case SEQ_TYPE_EXCLUSION:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_exclusion_float);
break;
default:
break;
}
}
-static void do_blend_effect_byte(float facf0,
- float facf1,
+static void do_blend_effect_byte(float fac,
int x,
int y,
unsigned char *rect1,
@@ -1736,73 +1192,67 @@ static void do_blend_effect_byte(float facf0,
{
switch (btype) {
case SEQ_TYPE_ADD:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_add_byte);
break;
case SEQ_TYPE_SUB:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_sub_byte);
break;
case SEQ_TYPE_MUL:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_mul_byte);
break;
case SEQ_TYPE_DARKEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_darken_byte);
break;
case SEQ_TYPE_COLOR_BURN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_burn_byte);
break;
case SEQ_TYPE_LINEAR_BURN:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_linearburn_byte);
break;
case SEQ_TYPE_SCREEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_screen_byte);
break;
case SEQ_TYPE_LIGHTEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_lighten_byte);
break;
case SEQ_TYPE_DODGE:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_dodge_byte);
break;
case SEQ_TYPE_OVERLAY:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_overlay_byte);
break;
case SEQ_TYPE_SOFT_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_softlight_byte);
break;
case SEQ_TYPE_HARD_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_hardlight_byte);
break;
case SEQ_TYPE_PIN_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_pinlight_byte);
break;
case SEQ_TYPE_LIN_LIGHT:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_linearlight_byte);
break;
case SEQ_TYPE_VIVID_LIGHT:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_vividlight_byte);
break;
case SEQ_TYPE_BLEND_COLOR:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_color_byte);
break;
case SEQ_TYPE_HUE:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_hue_byte);
break;
case SEQ_TYPE_SATURATION:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_saturation_byte);
break;
case SEQ_TYPE_VALUE:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_luminosity_byte);
break;
case SEQ_TYPE_DIFFERENCE:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_difference_byte);
break;
case SEQ_TYPE_EXCLUSION:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_exclusion_byte);
break;
default:
break;
@@ -1812,8 +1262,7 @@ static void do_blend_effect_byte(float facf0,
static void do_blend_mode_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1826,14 +1275,14 @@ static void do_blend_mode_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_float(
- facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_byte(
- facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
}
}
/*********************** Color Mix Effect *************************/
@@ -1853,8 +1302,7 @@ static void init_colormix_effect(Sequence *seq)
static void do_colormix_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1862,24 +1310,24 @@ static void do_colormix_effect(const SeqRenderData *context,
int total_lines,
ImBuf *out)
{
- float facf;
+ float fac;
ColorMixVars *data = seq->effectdata;
- facf = data->factor;
+ fac = data->factor;
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_float(
- facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_byte(
- facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
}
}
@@ -1930,7 +1378,7 @@ static float in_band(float width, float dist, int side, int dir)
return alpha;
}
-static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float facf0)
+static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float fac)
{
float posx, posy, hyp, hyp2, angle, hwidth, b1, b2, b3, pointdist;
/* some future stuff */
@@ -1950,18 +1398,18 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
angle = wipezone->angle;
if (wipe->forward) {
- posx = facf0 * xo;
- posy = facf0 * yo;
+ posx = fac * xo;
+ posy = fac * yo;
}
else {
- posx = xo - facf0 * xo;
- posy = yo - facf0 * yo;
+ posx = xo - fac * xo;
+ posy = yo - fac * yo;
}
switch (wipe->wipetype) {
case DO_SINGLE_WIPE:
- width = min_ii(wipezone->width, facf0 * yo);
- width = min_ii(width, yo - facf0 * yo);
+ width = min_ii(wipezone->width, fac * yo);
+ width = min_ii(width, yo - fac * yo);
if (angle == 0.0f) {
b1 = posy;
@@ -2000,7 +1448,7 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
case DO_DOUBLE_WIPE:
if (!wipe->forward) {
- facf0 = 1.0f - facf0; /* Go the other direction */
+ fac = 1.0f - fac; /* Go the other direction */
}
width = wipezone->width; /* calculate the blur width */
@@ -2053,9 +1501,9 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
* temp3: angle of low side of blur
* temp4: angle of high side of blur
*/
- output = 1.0f - facf0;
+ output = 1.0f - fac;
widthf = wipe->edgeWidth * 2.0f * (float)M_PI;
- temp1 = 2.0f * (float)M_PI * facf0;
+ temp1 = 2.0f * (float)M_PI * fac;
if (wipe->forward) {
temp1 = 2.0f * (float)M_PI - temp1;
@@ -2076,12 +1524,12 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
}
if (wipe->forward) {
- temp3 = temp1 - (widthf * 0.5f) * facf0;
- temp4 = temp1 + (widthf * 0.5f) * (1 - facf0);
+ temp3 = temp1 - (widthf * 0.5f) * fac;
+ temp4 = temp1 + (widthf * 0.5f) * (1 - fac);
}
else {
- temp3 = temp1 - (widthf * 0.5f) * (1 - facf0);
- temp4 = temp1 + (widthf * 0.5f) * facf0;
+ temp3 = temp1 - (widthf * 0.5f) * (1 - fac);
+ temp4 = temp1 + (widthf * 0.5f) * fac;
}
if (temp3 < 0) {
temp3 = 0;
@@ -2118,13 +1566,13 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
}
if (!wipe->forward) {
- facf0 = 1 - facf0;
+ fac = 1 - fac;
}
width = wipezone->width;
hwidth = width * 0.5f;
- temp1 = (halfx - (halfx)*facf0);
+ temp1 = (halfx - (halfx)*fac);
pointdist = hypotf(temp1, temp1);
temp2 = hypotf(halfx - x, halfy - y);
@@ -2175,8 +1623,7 @@ static void copy_wipe_effect(Sequence *dst, Sequence *src, const int UNUSED(flag
}
static void do_wipe_effect_byte(Sequence *seq,
- float facf0,
- float UNUSED(facf1),
+ float fac,
int x,
int y,
unsigned char *rect1,
@@ -2185,20 +1632,15 @@ static void do_wipe_effect_byte(Sequence *seq,
{
WipeZone wipezone;
WipeVars *wipe = (WipeVars *)seq->effectdata;
- int xo, yo;
- unsigned char *cp1, *cp2, *rt;
-
precalc_wipe_zone(&wipezone, wipe, x, y);
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- xo = x;
- yo = y;
- for (y = 0; y < yo; y++) {
- for (x = 0; x < xo; x++) {
- float check = check_zone(&wipezone, x, y, seq, facf0);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float check = check_zone(&wipezone, x, y, seq, fac);
if (check) {
if (cp1) {
float rt1[4], rt2[4], tempc[4];
@@ -2246,31 +1688,20 @@ static void do_wipe_effect_byte(Sequence *seq,
}
}
-static void do_wipe_effect_float(Sequence *seq,
- float facf0,
- float UNUSED(facf1),
- int x,
- int y,
- float *rect1,
- float *rect2,
- float *out)
+static void do_wipe_effect_float(
+ Sequence *seq, float fac, int x, int y, float *rect1, float *rect2, float *out)
{
WipeZone wipezone;
WipeVars *wipe = (WipeVars *)seq->effectdata;
- int xo, yo;
- float *rt1, *rt2, *rt;
-
precalc_wipe_zone(&wipezone, wipe, x, y);
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- xo = x;
- yo = y;
- for (y = 0; y < yo; y++) {
- for (x = 0; x < xo; x++) {
- float check = check_zone(&wipezone, x, y, seq, facf0);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float check = check_zone(&wipezone, x, y, seq, fac);
if (check) {
if (rt1) {
rt[0] = rt1[0] * check + rt2[0] * (1 - check);
@@ -2314,8 +1745,7 @@ static void do_wipe_effect_float(Sequence *seq,
static ImBuf *do_wipe_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -2324,8 +1754,7 @@ static ImBuf *do_wipe_effect(const SeqRenderData *context,
if (out->rect_float) {
do_wipe_effect_float(seq,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
ibuf1->rect_float,
@@ -2334,8 +1763,7 @@ static ImBuf *do_wipe_effect(const SeqRenderData *context,
}
else {
do_wipe_effect_byte(seq,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
(unsigned char *)ibuf1->rect,
@@ -2442,8 +1870,7 @@ static void transform_image(int x,
static void do_transform_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3),
@@ -2731,8 +2158,7 @@ static void copy_glow_effect(Sequence *dst, Sequence *src, const int UNUSED(flag
static void do_glow_effect_byte(Sequence *seq,
int render_size,
- float facf0,
- float UNUSED(facf1),
+ float fac,
int x,
int y,
unsigned char *rect1,
@@ -2749,7 +2175,7 @@ static void do_glow_effect_byte(Sequence *seq,
IMB_buffer_float_premultiply(inbuf, x, y);
RVIsolateHighlights_float(
- inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp);
+ inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp);
RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality);
if (!glow->bNoComp) {
RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y);
@@ -2765,8 +2191,7 @@ static void do_glow_effect_byte(Sequence *seq,
static void do_glow_effect_float(Sequence *seq,
int render_size,
- float facf0,
- float UNUSED(facf1),
+ float fac,
int x,
int y,
float *rect1,
@@ -2778,7 +2203,7 @@ static void do_glow_effect_float(Sequence *seq,
GlowVars *glow = (GlowVars *)seq->effectdata;
RVIsolateHighlights_float(
- inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp);
+ inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp);
RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality);
if (!glow->bNoComp) {
RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y);
@@ -2788,8 +2213,7 @@ static void do_glow_effect_float(Sequence *seq,
static ImBuf *do_glow_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -2801,8 +2225,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context,
if (out->rect_float) {
do_glow_effect_float(seq,
render_size,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
ibuf1->rect_float,
@@ -2812,8 +2235,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context,
else {
do_glow_effect_byte(seq,
render_size,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
(unsigned char *)ibuf1->rect,
@@ -2855,7 +2277,7 @@ static void copy_solid_color(Sequence *dst, Sequence *src, const int UNUSED(flag
dst->effectdata = MEM_dupallocN(src->effectdata);
}
-static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_color(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_NO_INPUT;
}
@@ -2863,8 +2285,7 @@ static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNU
static ImBuf *do_solid_color(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -2873,72 +2294,44 @@ static ImBuf *do_solid_color(const SeqRenderData *context,
SolidColorVars *cv = (SolidColorVars *)seq->effectdata;
- unsigned char *rect;
- float *rect_float;
- int x; /*= context->rectx;*/ /*UNUSED*/
- int y; /*= context->recty;*/ /*UNUSED*/
+ int x = out->x;
+ int y = out->y;
if (out->rect) {
- unsigned char col0[3];
- unsigned char col1[3];
-
- col0[0] = facf0 * cv->col[0] * 255;
- col0[1] = facf0 * cv->col[1] * 255;
- col0[2] = facf0 * cv->col[2] * 255;
+ unsigned char color[4];
+ color[0] = cv->col[0] * 255;
+ color[1] = cv->col[1] * 255;
+ color[2] = cv->col[2] * 255;
+ color[3] = 255;
- col1[0] = facf1 * cv->col[0] * 255;
- col1[1] = facf1 * cv->col[1] * 255;
- col1[2] = facf1 * cv->col[2] * 255;
+ unsigned char *rect = (unsigned char *)out->rect;
- rect = (unsigned char *)out->rect;
-
- for (y = 0; y < out->y; y++) {
- for (x = 0; x < out->x; x++, rect += 4) {
- rect[0] = col0[0];
- rect[1] = col0[1];
- rect[2] = col0[2];
- rect[3] = 255;
- }
- y++;
- if (y < out->y) {
- for (x = 0; x < out->x; x++, rect += 4) {
- rect[0] = col1[0];
- rect[1] = col1[1];
- rect[2] = col1[2];
- rect[3] = 255;
- }
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rect[0] = color[0];
+ rect[1] = color[1];
+ rect[2] = color[2];
+ rect[3] = color[3];
+ rect += 4;
}
}
}
else if (out->rect_float) {
- float col0[3];
- float col1[3];
-
- col0[0] = facf0 * cv->col[0];
- col0[1] = facf0 * cv->col[1];
- col0[2] = facf0 * cv->col[2];
+ float color[4];
+ color[0] = cv->col[0];
+ color[1] = cv->col[1];
+ color[2] = cv->col[2];
+ color[3] = 255;
- col1[0] = facf1 * cv->col[0];
- col1[1] = facf1 * cv->col[1];
- col1[2] = facf1 * cv->col[2];
+ float *rect_float = out->rect_float;
- rect_float = out->rect_float;
-
- for (y = 0; y < out->y; y++) {
- for (x = 0; x < out->x; x++, rect_float += 4) {
- rect_float[0] = col0[0];
- rect_float[1] = col0[1];
- rect_float[2] = col0[2];
- rect_float[3] = 1.0;
- }
- y++;
- if (y < out->y) {
- for (x = 0; x < out->x; x++, rect_float += 4) {
- rect_float[0] = col1[0];
- rect_float[1] = col1[1];
- rect_float[2] = col1[2];
- rect_float[3] = 1.0;
- }
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rect_float[0] = color[0];
+ rect_float[1] = color[1];
+ rect_float[2] = color[2];
+ rect_float[3] = color[3];
+ rect_float += 4;
}
}
}
@@ -2956,7 +2349,7 @@ static int num_inputs_multicam(void)
return 0;
}
-static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_NO_INPUT;
}
@@ -2964,8 +2357,7 @@ static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float
static ImBuf *do_multicam(const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *UNUSED(ibuf1),
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3))
@@ -3000,7 +2392,7 @@ static int num_inputs_adjustment(void)
return 0;
}
-static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_NO_INPUT;
}
@@ -3044,8 +2436,7 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl
static ImBuf *do_adjustment(const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *UNUSED(ibuf1),
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3))
@@ -3111,7 +2502,7 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla
v->frameMap = NULL;
}
-static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_DO_EFFECT;
}
@@ -3243,8 +2634,7 @@ static float speed_effect_interpolation_ratio_get(Scene *scene,
static ImBuf *do_speed_effect(const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -3255,10 +2645,10 @@ static ImBuf *do_speed_effect(const SeqRenderData *context,
if (s->flags & SEQ_SPEED_USE_INTERPOLATION) {
out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
- facf0 = facf1 = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame);
+ fac = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame);
/* Current frame is ibuf1, next frame is ibuf2. */
out = seq_render_effect_execute_threaded(
- &cross_effect, context, NULL, timeline_frame, facf0, facf1, ibuf1, ibuf2, ibuf3);
+ &cross_effect, context, NULL, timeline_frame, fac, ibuf1, ibuf2, ibuf3);
return out;
}
@@ -3271,8 +2661,7 @@ static ImBuf *do_speed_effect(const SeqRenderData *context,
static void do_overdrop_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -3289,8 +2678,8 @@ static void do_overdrop_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_drop_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out);
- do_alphaover_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out);
+ do_drop_effect_float(fac, x, y, rect1, rect2, rect_out);
+ do_alphaover_effect_float(fac, x, y, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -3298,8 +2687,8 @@ static void do_overdrop_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_drop_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out);
- do_alphaover_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out);
+ do_drop_effect_byte(fac, x, y, rect1, rect2, rect_out);
+ do_alphaover_effect_byte(fac, x, y, rect1, rect2, rect_out);
}
}
@@ -3337,7 +2726,7 @@ static void copy_gaussian_blur_effect(Sequence *dst, Sequence *src, const int UN
dst->effectdata = MEM_dupallocN(src->effectdata);
}
-static int early_out_gaussian_blur(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_gaussian_blur(Sequence *seq, float UNUSED(fac))
{
GaussianBlurVars *data = seq->effectdata;
if (data->size_x == 0.0f && data->size_y == 0) {
@@ -3691,8 +3080,7 @@ static void *render_effect_execute_do_y_thread(void *thread_data_v)
static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3))
@@ -3839,7 +3227,7 @@ static int num_inputs_text(void)
return 0;
}
-static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_text(Sequence *seq, float UNUSED(fac))
{
TextVars *data = seq->effectdata;
if (data->text[0] == 0 || data->text_size < 1.0f ||
@@ -3853,8 +3241,7 @@ static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1
static ImBuf *do_text_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -3957,12 +3344,12 @@ static ImBuf *do_text_effect(const SeqRenderData *context,
fonty = line_height;
BLF_position(font, x + max_ii(fontx / 55, 1), y - max_ii(fonty / 30, 1), 0.0f);
BLF_buffer_col(font, data->shadow_color);
- BLF_draw_buffer(font, data->text, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(font, data->text, sizeof(data->text));
}
BLF_position(font, x, y, 0.0f);
BLF_buffer_col(font, data->color);
- BLF_draw_buffer(font, data->text, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_buffer(font, data->text, sizeof(data->text));
BLF_buffer(font, NULL, NULL, 0, 0, 0, NULL);
@@ -4000,52 +3387,47 @@ static void free_effect_default(Sequence *seq, const bool UNUSED(do_id_user))
MEM_SAFE_FREE(seq->effectdata);
}
-static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_DO_EFFECT;
}
-static int early_out_fade(Sequence *UNUSED(seq), float facf0, float facf1)
+static int early_out_fade(Sequence *UNUSED(seq), float fac)
{
- if (facf0 == 0.0f && facf1 == 0.0f) {
+ if (fac == 0.0f) {
return EARLY_USE_INPUT_1;
}
- if (facf0 == 1.0f && facf1 == 1.0f) {
+ if (fac == 1.0f) {
return EARLY_USE_INPUT_2;
}
return EARLY_DO_EFFECT;
}
-static int early_out_mul_input2(Sequence *UNUSED(seq), float facf0, float facf1)
+static int early_out_mul_input2(Sequence *UNUSED(seq), float fac)
{
- if (facf0 == 0.0f && facf1 == 0.0f) {
+ if (fac == 0.0f) {
return EARLY_USE_INPUT_1;
}
return EARLY_DO_EFFECT;
}
-static int early_out_mul_input1(Sequence *UNUSED(seq), float facf0, float facf1)
+static int early_out_mul_input1(Sequence *UNUSED(seq), float fac)
{
- if (facf0 == 0.0f && facf1 == 0.0f) {
+ if (fac == 0.0f) {
return EARLY_USE_INPUT_2;
}
return EARLY_DO_EFFECT;
}
-static void get_default_fac_noop(Sequence *UNUSED(seq),
- float UNUSED(timeline_frame),
- float *facf0,
- float *facf1)
+static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_frame), float *fac)
{
- *facf0 = *facf1 = 1.0;
+ *fac = 1.0f;
}
-static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *facf0, float *facf1)
+static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *fac)
{
- *facf0 = (float)(timeline_frame - seq->startdisp);
- *facf1 = (float)(*facf0 + 0.5f);
- *facf0 /= seq->len;
- *facf1 /= seq->len;
+ *fac = (float)(timeline_frame - seq->startdisp);
+ *fac /= seq->len;
}
static struct ImBuf *init_execution(const SeqRenderData *context,
diff --git a/source/blender/sequencer/intern/multiview.h b/source/blender/sequencer/intern/multiview.h
index 3d528c22fff..79d99c88b50 100644
--- a/source/blender/sequencer/intern/multiview.h
+++ b/source/blender/sequencer/intern/multiview.h
@@ -36,9 +36,9 @@ struct Scene;
* **********************************************************************
*/
-void seq_anim_add_suffix(struct Scene *scene, struct anim *anim, const int view_id);
+void seq_anim_add_suffix(struct Scene *scene, struct anim *anim, int view_id);
void seq_multiview_name(struct Scene *scene,
- const int view_id,
+ int view_id,
const char *prefix,
const char *ext,
char *r_path,
@@ -46,7 +46,7 @@ void seq_multiview_name(struct Scene *scene,
/**
* 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);
+int seq_num_files(struct Scene *scene, char views_format, bool is_multiview);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c
index 0c45eb09492..42affae26ed 100644
--- a/source/blender/sequencer/intern/prefetch.c
+++ b/source/blender/sequencer/intern/prefetch.c
@@ -328,6 +328,20 @@ static void seq_prefetch_update_scene(Scene *scene)
seq_prefetch_init_depsgraph(pfjob);
}
+static void seq_prefetch_update_active_seqbase(PrefetchJob *pfjob)
+{
+ MetaStack *ms_orig = SEQ_meta_stack_active_get(SEQ_editing_get(pfjob->scene));
+ Editing *ed_eval = SEQ_editing_get(pfjob->scene_eval);
+
+ if (ms_orig != NULL) {
+ Sequence *meta_eval = seq_prefetch_get_original_sequence(ms_orig->parseq, pfjob->scene_eval);
+ SEQ_seqbase_active_set(ed_eval, &meta_eval->seqbase);
+ }
+ else {
+ SEQ_seqbase_active_set(ed_eval, &ed_eval->seqbase);
+ }
+}
+
static void seq_prefetch_resume(Scene *scene)
{
PrefetchJob *pfjob = seq_prefetch_job_get(scene);
@@ -486,7 +500,7 @@ static void *seq_prefetch_frames(void *job)
*/
pfjob->scene_eval->ed->prefetch_job = pfjob;
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(pfjob->scene));
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(pfjob->scene_eval));
if (seq_prefetch_must_skip_frame(pfjob, seqbase)) {
pfjob->num_frames_prefetched++;
continue;
@@ -549,6 +563,7 @@ static PrefetchJob *seq_prefetch_start_ex(const SeqRenderData *context, float cf
seq_prefetch_update_scene(context->scene);
seq_prefetch_update_context(context);
+ seq_prefetch_update_active_seqbase(pfjob);
BLI_threadpool_remove(&pfjob->threads, pfjob);
BLI_threadpool_insert(&pfjob->threads, pfjob);
diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c
index 30afa3f9c59..5982f89a287 100644
--- a/source/blender/sequencer/intern/proxy.c
+++ b/source/blender/sequencer/intern/proxy.c
@@ -415,7 +415,8 @@ bool SEQ_proxy_rebuild_context(Main *bmain,
Scene *scene,
Sequence *seq,
struct GSet *file_list,
- ListBase *queue)
+ ListBase *queue,
+ bool build_only_on_bad_performance)
{
SeqIndexBuildContext *context;
Sequence *nseq;
@@ -476,7 +477,8 @@ bool SEQ_proxy_rebuild_context(Main *bmain,
context->size_flags,
context->quality,
context->overwrite,
- file_list);
+ file_list,
+ build_only_on_bad_performance);
}
if (!context->index_context) {
MEM_freeN(context);
@@ -591,7 +593,7 @@ void SEQ_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop)
IMB_anim_index_rebuild_finish(context->index_context, stop);
}
- seq_free_sequence_recurse(NULL, context->seq, true, true);
+ seq_free_sequence_recurse(NULL, context->seq, true);
MEM_freeN(context);
}
@@ -601,10 +603,7 @@ void SEQ_proxy_set(struct Sequence *seq, bool value)
if (value) {
seq->flag |= SEQ_USE_PROXY;
if (seq->strip->proxy == NULL) {
- seq->strip->proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy");
- seq->strip->proxy->quality = 50;
- seq->strip->proxy->build_tc_flags = SEQ_PROXY_TC_ALL;
- seq->strip->proxy->build_size_flags = SEQ_PROXY_IMAGE_SIZE_25;
+ seq->strip->proxy = seq_strip_proxy_alloc();
}
}
else {
diff --git a/source/blender/sequencer/intern/proxy.h b/source/blender/sequencer/intern/proxy.h
index a65fdcd42fe..e92cd8de429 100644
--- a/source/blender/sequencer/intern/proxy.h
+++ b/source/blender/sequencer/intern/proxy.h
@@ -36,7 +36,7 @@ struct anim;
struct ImBuf *seq_proxy_fetch(const struct SeqRenderData *context,
struct Sequence *seq,
int timeline_frame);
-bool seq_proxy_get_custom_file_fname(struct Sequence *seq, char *name, const int view_id);
+bool seq_proxy_get_custom_file_fname(struct Sequence *seq, char *name, int view_id);
void free_proxy_seq(Sequence *seq);
void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir);
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index a391deaccb4..482425e70d3 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -29,6 +29,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
+#include "DNA_defaults.h"
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
@@ -303,9 +304,9 @@ int seq_get_shown_sequences(ListBase *seqbase,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Preprocessing and Effects
+/** \name Preprocessing & Effects
*
- * Input pre-processing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE.
+ * Input preprocessing 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 re-scaling to render resolution has been done).
@@ -683,7 +684,7 @@ typedef struct RenderEffectInitData {
struct SeqEffectHandle *sh;
const SeqRenderData *context;
Sequence *seq;
- float timeline_frame, facf0, facf1;
+ float timeline_frame, fac;
ImBuf *ibuf1, *ibuf2, *ibuf3;
ImBuf *out;
@@ -693,7 +694,7 @@ typedef struct RenderEffectThread {
struct SeqEffectHandle *sh;
const SeqRenderData *context;
Sequence *seq;
- float timeline_frame, facf0, facf1;
+ float timeline_frame, fac;
ImBuf *ibuf1, *ibuf2, *ibuf3;
ImBuf *out;
@@ -712,8 +713,7 @@ static void render_effect_execute_init_handle(void *handle_v,
handle->context = init_data->context;
handle->seq = init_data->seq;
handle->timeline_frame = init_data->timeline_frame;
- handle->facf0 = init_data->facf0;
- handle->facf1 = init_data->facf1;
+ handle->fac = init_data->fac;
handle->ibuf1 = init_data->ibuf1;
handle->ibuf2 = init_data->ibuf2;
handle->ibuf3 = init_data->ibuf3;
@@ -730,8 +730,7 @@ static void *render_effect_execute_do_thread(void *thread_data_v)
thread_data->sh->execute_slice(thread_data->context,
thread_data->seq,
thread_data->timeline_frame,
- thread_data->facf0,
- thread_data->facf1,
+ thread_data->fac,
thread_data->ibuf1,
thread_data->ibuf2,
thread_data->ibuf3,
@@ -746,8 +745,7 @@ ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -759,8 +757,7 @@ ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
init_data.context = context;
init_data.seq = seq;
init_data.timeline_frame = timeline_frame;
- init_data.facf0 = facf0;
- init_data.facf1 = facf1;
+ init_data.fac = fac;
init_data.ibuf1 = ibuf1;
init_data.ibuf2 = ibuf2;
init_data.ibuf3 = ibuf3;
@@ -781,7 +778,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
float timeline_frame)
{
Scene *scene = context->scene;
- float fac, facf;
+ float fac;
int early_out;
int i;
struct SeqEffectHandle sh = SEQ_effect_handle_get(seq);
@@ -803,24 +800,23 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
}
if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
- sh.get_default_fac(seq, timeline_frame, &fac, &facf);
- facf = fac;
+ sh.get_default_fac(seq, timeline_frame, &fac);
}
else {
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
if (fcu) {
- fac = facf = evaluate_fcurve(fcu, timeline_frame);
+ fac = evaluate_fcurve(fcu, timeline_frame);
}
else {
- fac = facf = seq->effect_fader;
+ fac = seq->effect_fader;
}
}
- early_out = sh.early_out(seq, fac, facf);
+ early_out = sh.early_out(seq, fac);
switch (early_out) {
case EARLY_NO_INPUT:
- out = sh.execute(context, seq, timeline_frame, fac, facf, NULL, NULL, NULL);
+ out = sh.execute(context, seq, timeline_frame, fac, NULL, NULL, NULL);
break;
case EARLY_DO_EFFECT:
for (i = 0; i < 3; i++) {
@@ -839,10 +835,10 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
if (ibuf[0] && (ibuf[1] || SEQ_effect_get_num_inputs(seq->type) == 1)) {
if (sh.multithreaded) {
out = seq_render_effect_execute_threaded(
- &sh, context, seq, timeline_frame, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
+ &sh, context, seq, timeline_frame, fac, ibuf[0], ibuf[1], ibuf[2]);
}
else {
- out = sh.execute(context, seq, timeline_frame, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
+ out = sh.execute(context, seq, timeline_frame, fac, ibuf[0], ibuf[1], ibuf[2]);
}
}
break;
@@ -1193,15 +1189,13 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context,
bool *r_is_proxy_image)
{
ImBuf *ibuf = NULL;
- MovieClipUser user;
+ MovieClipUser user = *DNA_struct_default_get(MovieClipUser);
IMB_Proxy_Size psize = SEQ_rendersize_to_proxysize(context->preview_render_size);
if (!seq->clip) {
return NULL;
}
- memset(&user, 0, sizeof(MovieClipUser));
-
BKE_movieclip_user_set_frame(&user, frame_index + seq->anim_startofs + seq->clip->start_frame);
user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
@@ -1774,8 +1768,8 @@ static bool seq_must_swap_input_in_blend_mode(Sequence *seq)
static int seq_get_early_out_for_blend_mode(Sequence *seq)
{
struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq);
- float facf = seq->blend_opacity / 100.0f;
- int early_out = sh.early_out(seq, facf, facf);
+ float fac = seq->blend_opacity / 100.0f;
+ int early_out = sh.early_out(seq, fac);
if (ELEM(early_out, EARLY_DO_EFFECT, EARLY_NO_INPUT)) {
return early_out;
@@ -1797,25 +1791,25 @@ static ImBuf *seq_render_strip_stack_apply_effect(
{
ImBuf *out;
struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq);
- float facf = seq->blend_opacity / 100.0f;
+ float fac = seq->blend_opacity / 100.0f;
int swap_input = seq_must_swap_input_in_blend_mode(seq);
if (swap_input) {
if (sh.multithreaded) {
out = seq_render_effect_execute_threaded(
- &sh, context, seq, timeline_frame, facf, facf, ibuf2, ibuf1, NULL);
+ &sh, context, seq, timeline_frame, fac, ibuf2, ibuf1, NULL);
}
else {
- out = sh.execute(context, seq, timeline_frame, facf, facf, ibuf2, ibuf1, NULL);
+ out = sh.execute(context, seq, timeline_frame, fac, ibuf2, ibuf1, NULL);
}
}
else {
if (sh.multithreaded) {
out = seq_render_effect_execute_threaded(
- &sh, context, seq, timeline_frame, facf, facf, ibuf1, ibuf2, NULL);
+ &sh, context, seq, timeline_frame, fac, ibuf1, ibuf2, NULL);
}
else {
- out = sh.execute(context, seq, timeline_frame, facf, facf, ibuf1, ibuf2, NULL);
+ out = sh.execute(context, seq, timeline_frame, fac, ibuf1, ibuf2, NULL);
}
}
diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h
index a0cdf24d84b..eb1f71769a6 100644
--- a/source/blender/sequencer/intern/render.h
+++ b/source/blender/sequencer/intern/render.h
@@ -54,8 +54,7 @@ struct ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
struct ImBuf *ibuf1,
struct ImBuf *ibuf2,
struct ImBuf *ibuf3);
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index 908a5bd4f79..1c7fe927381 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -34,10 +34,7 @@
#include "DNA_sound_types.h"
#include "BLI_listbase.h"
-#include "BLI_string.h"
-#include "BKE_animsys.h"
-#include "BKE_fcurve.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
#include "BKE_sound.h"
@@ -65,12 +62,19 @@
#include "sequencer.h"
#include "utils.h"
-static void seq_free_animdata(Scene *scene, Sequence *seq);
-
/* -------------------------------------------------------------------- */
/** \name Allocate / Free Functions
* \{ */
+StripProxy *seq_strip_proxy_alloc(void)
+{
+ StripProxy *strip_proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy");
+ strip_proxy->quality = 50;
+ strip_proxy->build_tc_flags = SEQ_PROXY_TC_ALL;
+ strip_proxy->tc = SEQ_PROXY_TC_RECORD_RUN;
+ return strip_proxy;
+}
+
static Strip *seq_strip_alloc(int type)
{
Strip *strip = MEM_callocN(sizeof(Strip), "strip");
@@ -140,6 +144,7 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int
seq->pitch = 1.0f;
seq->scene_sound = NULL;
seq->type = type;
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->strip = seq_strip_alloc(type);
seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
@@ -155,8 +160,7 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int
static void seq_sequence_free_ex(Scene *scene,
Sequence *seq,
const bool do_cache,
- const bool do_id_user,
- const bool do_clean_animdata)
+ const bool do_id_user)
{
if (seq->strip) {
seq_free_strip(seq->strip);
@@ -190,11 +194,6 @@ static void seq_sequence_free_ex(Scene *scene,
if (seq->scene_sound && ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
BKE_sound_remove_scene_sound(scene, seq->scene_sound);
}
-
- /* XXX This must not be done in BKE code. */
- if (do_clean_animdata) {
- seq_free_animdata(scene, seq);
- }
}
if (seq->prop) {
@@ -222,24 +221,21 @@ static void seq_sequence_free_ex(Scene *scene,
MEM_freeN(seq);
}
-void SEQ_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata)
+void SEQ_sequence_free(Scene *scene, Sequence *seq)
{
- seq_sequence_free_ex(scene, seq, true, true, do_clean_animdata);
+ seq_sequence_free_ex(scene, seq, true, true);
}
-void seq_free_sequence_recurse(Scene *scene,
- Sequence *seq,
- const bool do_id_user,
- const bool do_clean_animdata)
+void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do_id_user)
{
Sequence *iseq, *iseq_next;
for (iseq = seq->seqbase.first; iseq; iseq = iseq_next) {
iseq_next = iseq->next;
- seq_free_sequence_recurse(scene, iseq, do_id_user, do_clean_animdata);
+ seq_free_sequence_recurse(scene, iseq, do_id_user);
}
- seq_sequence_free_ex(scene, seq, false, do_id_user, do_clean_animdata);
+ seq_sequence_free_ex(scene, seq, false, do_id_user);
}
Editing *SEQ_editing_get(const Scene *scene)
@@ -275,7 +271,7 @@ void SEQ_editing_free(Scene *scene, const bool do_id_user)
/* handle cache freeing above */
LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &ed->seqbase) {
- seq_free_sequence_recurse(scene, seq, do_id_user, false);
+ seq_free_sequence_recurse(scene, seq, do_id_user);
}
BLI_freelistN(&ed->metastack);
@@ -418,6 +414,10 @@ void SEQ_meta_stack_free(Editing *ed, MetaStack *ms)
MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
{
+ if (ed == NULL) {
+ return NULL;
+ }
+
return ed->metastack.last;
}
@@ -618,120 +618,6 @@ bool SEQ_valid_strip_channel(Sequence *seq)
return true;
}
-/* r_prefix + [" + escaped_name + "] + \0 */
-#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1)
-
-static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name)
-{
- char name_esc[SEQ_NAME_MAXSTR * 2];
-
- BLI_str_escape(name_esc, name, sizeof(name_esc));
- return BLI_snprintf_rlen(
- str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc);
-}
-
-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;
-
- if (scene->adt == NULL || ofs == 0 || scene->adt->action == NULL) {
- return;
- }
-
- str_len = sequencer_rna_path_prefix(str, seq->name + 2);
-
- for (fcu = scene->adt->action->curves.first; fcu; fcu = fcu->next) {
- if (STREQLEN(fcu->rna_path, str, str_len)) {
- unsigned int i;
- if (fcu->bezt) {
- for (i = 0; i < fcu->totvert; i++) {
- BezTriple *bezt = &fcu->bezt[i];
- bezt->vec[0][0] += ofs;
- bezt->vec[1][0] += ofs;
- bezt->vec[2][0] += ofs;
- }
- }
- if (fcu->fpt) {
- for (i = 0; i < fcu->totvert; i++) {
- FPoint *fpt = &fcu->fpt[i];
- fpt->vec[0] += ofs;
- }
- }
- }
- }
-
- DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION);
-}
-
-void SEQ_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst)
-{
- char str_from[SEQ_RNAPATH_MAXSTR];
- size_t str_from_len;
- FCurve *fcu;
- FCurve *fcu_last;
- FCurve *fcu_cpy;
- ListBase lb = {NULL, NULL};
-
- if (scene->adt == NULL || scene->adt->action == NULL) {
- return;
- }
-
- str_from_len = sequencer_rna_path_prefix(str_from, name_src);
-
- fcu_last = scene->adt->action->curves.last;
-
- for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) {
- if (STREQLEN(fcu->rna_path, str_from, str_from_len)) {
- fcu_cpy = BKE_fcurve_copy(fcu);
- BLI_addtail(&lb, fcu_cpy);
- }
- }
-
- /* notice validate is 0, keep this because the seq may not be added to the scene yet */
- BKE_animdata_fix_paths_rename(
- &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name_src, name_dst, 0, 0, 0);
-
- /* add the original fcurves back */
- BLI_movelisttolist(&scene->adt->action->curves, &lb);
-}
-
-/* XXX: hackish function needed to remove all fcurves belonging to a sequencer strip. */
-static void seq_free_animdata(Scene *scene, Sequence *seq)
-{
- char str[SEQ_RNAPATH_MAXSTR];
- size_t str_len;
- FCurve *fcu;
-
- if (scene->adt == NULL || scene->adt->action == NULL) {
- return;
- }
-
- str_len = sequencer_rna_path_prefix(str, seq->name + 2);
-
- fcu = scene->adt->action->curves.first;
-
- while (fcu) {
- if (STREQLEN(fcu->rna_path, str, str_len)) {
- FCurve *next_fcu = fcu->next;
-
- BLI_remlink(&scene->adt->action->curves, fcu);
- BKE_fcurve_free(fcu);
-
- fcu = next_fcu;
- }
- else {
- fcu = fcu->next;
- }
- }
-}
-
-#undef SEQ_RNAPATH_MAXSTR
-
SequencerToolSettings *SEQ_tool_settings_copy(SequencerToolSettings *tool_settings)
{
SequencerToolSettings *tool_settings_copy = MEM_dupallocN(tool_settings);
diff --git a/source/blender/sequencer/intern/sequencer.h b/source/blender/sequencer/intern/sequencer.h
index f8ad17e9032..2a82f966f02 100644
--- a/source/blender/sequencer/intern/sequencer.h
+++ b/source/blender/sequencer/intern/sequencer.h
@@ -29,15 +29,13 @@ extern "C" {
struct Scene;
struct Sequence;
-
+struct StripProxy;
/**
* 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,
- const bool do_clean_animdata);
+void seq_free_sequence_recurse(struct Scene *scene, struct Sequence *seq, bool do_id_user);
+struct StripProxy *seq_strip_proxy_alloc(void);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/sound.c b/source/blender/sequencer/intern/sound.c
index 86a37aca4a9..0788003fb12 100644
--- a/source/blender/sequencer/intern/sound.c
+++ b/source/blender/sequencer/intern/sound.c
@@ -31,6 +31,7 @@
#include "DNA_sound_types.h"
#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
#include "BKE_main.h"
#include "BKE_scene.h"
@@ -56,11 +57,15 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene,
}
}
else if (seq->type == SEQ_TYPE_SOUND_RAM && seq->sound) {
- const float length = BKE_sound_get_length(bmain, seq->sound);
+ SoundInfo info;
+ if (!BKE_sound_info_get(bmain, seq->sound, &info)) {
+ continue;
+ }
+
int old = seq->len;
float fac;
- seq->len = (int)ceil((double)length * FPS);
+ seq->len = MAX2(1, round((info.length - seq->sound->offset_time) * FPS));
fac = (float)seq->len / (float)old;
old = seq->startofs;
seq->startofs *= fac;
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index a4b537b9074..f342765eec9 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -141,7 +141,6 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SCENE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->scene = load_data->scene;
seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1;
id_us_ensure_real((ID *)load_data->scene);
@@ -154,7 +153,6 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIECLIP);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->clip = load_data->clip;
seq->len = BKE_movieclip_get_duration(load_data->clip);
id_us_ensure_real((ID *)load_data->clip);
@@ -167,7 +165,6 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MASK);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->mask = load_data->mask;
seq->len = BKE_mask_get_duration(load_data->mask);
id_us_ensure_real((ID *)load_data->mask);
@@ -191,9 +188,6 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa
if (SEQ_effect_get_num_inputs(seq->type) == 1) {
seq->blend_mode = seq->seq1->blend_mode;
}
- else {
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
- }
if (!load_data->effect.seq1) {
seq->len = 1; /* Effect is generator, set non zero length. */
@@ -250,7 +244,6 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_IMAGE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */
seq->len = load_data->image.len;
Strip *strip = seq->strip;
strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem");
@@ -482,8 +475,6 @@ Sequence *SEQ_add_movie_strip(
}
}
- seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */
-
if (anim_arr[0] != NULL) {
seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 912ba9d41db..0479d3012fa 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -43,6 +43,7 @@
#include "utils.h"
#include "SEQ_add.h"
+#include "SEQ_animation.h"
#include "SEQ_edit.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
@@ -199,8 +200,9 @@ void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
if (seq->type == SEQ_TYPE_META) {
SEQ_edit_remove_flagged_sequences(scene, &seq->seqbase);
}
+ SEQ_free_animdata(scene, seq);
BLI_remlink(seqbase, seq);
- SEQ_sequence_free(scene, seq, true);
+ SEQ_sequence_free(scene, seq);
SEQ_sequence_lookup_tag(scene, SEQ_LOOKUP_TAG_INVALID);
}
}
@@ -489,21 +491,27 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
ListBase right_strips = {NULL, NULL};
SEQ_sequence_base_dupli_recursive(scene, scene, &right_strips, &left_strips, SEQ_DUPE_ALL, 0);
- /* Split strips. */
Sequence *left_seq = left_strips.first;
Sequence *right_seq = right_strips.first;
- Sequence *return_seq = right_strips.first;
+ Sequence *return_seq = NULL;
- /* Strips can't be tagged while in detached `seqbase`. Collect all strips which needs to be
- * deleted and delay tagging until they are moved back to `seqbase` in `Editing`. */
- SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
+ /* Move strips from detached `ListBase`, otherwise they can't be flagged for removal,
+ * SEQ_time_update_sequence can fail to update meta strips and they can't be renamed.
+ * This is because these functions check all strips in `Editing` to manage relationships. */
+ BLI_movelisttolist(seqbase, &left_strips);
+ BLI_movelisttolist(seqbase, &right_strips);
+ /* Split strips. */
while (left_seq && right_seq) {
if (left_seq->startdisp >= timeline_frame) {
- SEQ_collection_append_strip(left_seq, strips_to_delete);
+ SEQ_edit_flag_for_removal(scene, seqbase, left_seq);
}
if (right_seq->enddisp <= timeline_frame) {
- SEQ_collection_append_strip(right_seq, strips_to_delete);
+ SEQ_edit_flag_for_removal(scene, seqbase, right_seq);
+ }
+ else if (return_seq == NULL) {
+ /* Store return value - pointer to strip that will not be removed. */
+ return_seq = right_seq;
}
seq_edit_split_handle_strip_offsets(
@@ -512,20 +520,14 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
right_seq = right_seq->next;
}
- seq = right_strips.first;
- BLI_movelisttolist(seqbase, &left_strips);
- BLI_movelisttolist(seqbase, &right_strips);
+ SEQ_edit_remove_flagged_sequences(scene, seqbase);
- for (; seq; seq = seq->next) {
- SEQ_ensure_unique_name(seq, scene);
+ /* Rename duplicated strips. */
+ Sequence *seq_rename = return_seq;
+ for (; seq_rename; seq_rename = seq_rename->next) {
+ SEQ_ensure_unique_name(seq_rename, scene);
}
- Sequence *seq_delete;
- SEQ_ITERATOR_FOREACH (seq_delete, strips_to_delete) {
- SEQ_edit_flag_for_removal(scene, seqbase, seq_delete);
- }
- SEQ_edit_remove_flagged_sequences(scene, seqbase);
- SEQ_collection_free(strips_to_delete);
return return_seq;
}
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index 3228277ce72..31ee20cb6ca 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -193,6 +193,10 @@ static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta)
void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta)
{
+ if (seq_meta == NULL) {
+ return;
+ }
+
seq_time_update_meta_strip(scene, seq_meta);
/* Prevent meta-strip to move in timeline. */
diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h
index aa807b6da25..4fe8d03e641 100644
--- a/source/blender/sequencer/intern/strip_time.h
+++ b/source/blender/sequencer/intern/strip_time.h
@@ -51,7 +51,7 @@ typedef struct GapInfo {
*/
void seq_time_gap_info_get(const struct Scene *scene,
struct ListBase *seqbase,
- const int initial_frame,
+ int initial_frame,
struct GapInfo *r_gap_info);
#ifdef __cplusplus
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index ce5917b999f..432fc1c166f 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -33,6 +33,7 @@
#include "BKE_scene.h"
#include "BKE_sound.h"
+#include "SEQ_animation.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index cd779b0b0c7..140aa2d67c5 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -35,10 +35,12 @@
#include "BLI_blenlib.h"
+#include "BKE_animsys.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "SEQ_animation.h"
#include "SEQ_edit.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
@@ -446,7 +448,7 @@ Sequence *SEQ_get_meta_by_seqbase(ListBase *seqbase_main, ListBase *meta_seqbase
{
SeqCollection *strips = SEQ_query_all_strips_recursive(seqbase_main);
- Sequence *seq;
+ Sequence *seq = NULL;
SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->type == SEQ_TYPE_META && &seq->seqbase == meta_seqbase) {
break;
@@ -583,7 +585,8 @@ void SEQ_ensure_unique_name(Sequence *seq, Scene *scene)
BLI_strncpy_utf8(name, seq->name + 2, sizeof(name));
SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq);
- SEQ_dupe_animdata(scene, name, seq->name + 2);
+ BKE_animdata_fix_paths_rename(
+ &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name, seq->name + 2, 0, 0, 0);
if (seq->type == SEQ_TYPE_META) {
LISTBASE_FOREACH (Sequence *, seq_child, &seq->seqbase) {
diff --git a/source/blender/sequencer/intern/utils.h b/source/blender/sequencer/intern/utils.h
index 512647ed2e2..b5aa66804c6 100644
--- a/source/blender/sequencer/intern/utils.h
+++ b/source/blender/sequencer/intern/utils.h
@@ -27,8 +27,8 @@
extern "C" {
#endif
-struct Scene;
struct ListBase;
+struct Scene;
bool sequencer_seq_generates_image(struct Sequence *seq);
void seq_open_anim_file(struct Scene *scene, struct Sequence *seq, bool openfile);
diff --git a/source/blender/simulation/intern/SIM_mass_spring.cpp b/source/blender/simulation/intern/SIM_mass_spring.cpp
index f9a22276363..73b287b4233 100644
--- a/source/blender/simulation/intern/SIM_mass_spring.cpp
+++ b/source/blender/simulation/intern/SIM_mass_spring.cpp
@@ -625,7 +625,7 @@ static void cloth_calc_force(
}
#endif
- /* cloth_calc_volume_force(clmd); */
+ // cloth_calc_volume_force(clmd);
#ifdef CLOTH_FORCE_DRAG
SIM_mass_spring_force_drag(data, drag);
@@ -1295,8 +1295,7 @@ int SIM_cloth_solve(
BKE_sim_debug_data_clear_category("collision");
if (!clmd->solver_result) {
- clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult),
- "cloth solver result");
+ clmd->solver_result = MEM_cnew<ClothSolverResult>("cloth solver result");
}
cloth_clear_result(clmd);
diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp
index e47593eda05..f9b61fe9942 100644
--- a/source/blender/simulation/intern/hair_volume.cpp
+++ b/source/blender/simulation/intern/hair_volume.cpp
@@ -842,8 +842,8 @@ bool SIM_hair_volume_solve_divergence(HairGrid *grid,
}
/* Main Poisson equation system:
- * This is derived from the discretezation of the Poisson equation
- * div(grad(p)) = div(v)
+ * This is derived from the discretization of the Poisson equation:
+ * `div(grad(p)) = div(v)`
*
* The finite difference approximation yields the linear equation system described here:
* https://en.wikipedia.org/wiki/Discrete_Poisson_equation
@@ -1160,7 +1160,7 @@ HairGrid *SIM_hair_volume_create_vertex_grid(float cellsize,
}
size = hair_grid_size(res);
- grid = (HairGrid *)MEM_callocN(sizeof(HairGrid), "hair grid");
+ grid = MEM_cnew<HairGrid>("hair grid");
grid->res[0] = res[0];
grid->res[1] = res[1];
grid->res[2] = res[2];
diff --git a/source/blender/simulation/intern/implicit_blender.c b/source/blender/simulation/intern/implicit_blender.c
index add047bf8c8..95bf59101e6 100644
--- a/source/blender/simulation/intern/implicit_blender.c
+++ b/source/blender/simulation/intern/implicit_blender.c
@@ -830,7 +830,7 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z,
s_prev = s;
s = dot_lfvector(r, r, numverts);
- /* d = r+d*(s/s_prev); */
+ // d = r+d*(s/s_prev);
add_lfvector_lfvectorS(d, r, d, (s / s_prev), numverts);
filter(d, S);
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 4ffd31a9923..ff3e1b7474c 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -47,6 +47,7 @@ struct GHashIterator;
struct GPUViewport;
struct ID;
struct IDProperty;
+struct IDRemapper;
struct ImBuf;
struct ImageFormatData;
struct Main;
@@ -118,7 +119,7 @@ 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);
+void WM_exit_ex(struct bContext *C, bool do_python);
/**
* \brief Main exit function to close Blender ordinarily.
@@ -277,7 +278,7 @@ struct ID *WM_file_link_datablock(struct Main *bmain,
struct ViewLayer *view_layer,
struct View3D *v3d,
const char *filepath,
- const short id_code,
+ short id_code,
const char *id_name,
int flag);
/**
@@ -289,7 +290,7 @@ struct ID *WM_file_append_datablock(struct Main *bmain,
struct ViewLayer *view_layer,
struct View3D *v3d,
const char *filepath,
- const short id_code,
+ short id_code,
const char *id_name,
int flag);
void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports);
@@ -404,7 +405,7 @@ struct wmEventHandler_UI *WM_event_add_ui_handler(const struct bContext *C,
wmUIHandlerFunc handle_fn,
wmUIHandlerRemoveFunc remove_fn,
void *user_data,
- const char flag);
+ char flag);
/**
* \param postpone: Enable for `win->modalhandlers`,
* this is in a running for () loop in wm_handlers_do().
@@ -413,7 +414,7 @@ void WM_event_remove_ui_handler(ListBase *handlers,
wmUIHandlerFunc handle_fn,
wmUIHandlerRemoveFunc remove_fn,
void *user_data,
- const bool postpone);
+ bool postpone);
void WM_event_remove_area_handler(struct ListBase *handlers, void *area);
void WM_event_free_ui_handler_all(struct bContext *C,
ListBase *handlers,
@@ -471,7 +472,7 @@ 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);
+void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings);
/* reports */
/**
@@ -605,9 +606,9 @@ int WM_operator_ui_popup(struct bContext *C, struct wmOperator *op, int width);
int WM_operator_confirm_message_ex(struct bContext *C,
struct wmOperator *op,
const char *title,
- const int icon,
+ int icon,
const char *message,
- const wmOperatorCallContext opcontext);
+ wmOperatorCallContext opcontext);
int WM_operator_confirm_message(struct bContext *C, struct wmOperator *op, const char *message);
/* Operator API. */
@@ -636,12 +637,12 @@ bool WM_operator_poll_context(struct bContext *C, struct wmOperatorType *ot, sho
*
* \param store: Store settings for re-use.
*
- * \warning do not use this within an operator to call its self! T29537.
+ * \warning do not use this within an operator to call itself! T29537.
*/
-int WM_operator_call_ex(struct bContext *C, struct wmOperator *op, const bool store);
+int WM_operator_call_ex(struct bContext *C, struct wmOperator *op, 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
+ * This is intended to be used when an invoke operator wants to call exec on itself
* 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
*/
@@ -688,7 +689,7 @@ int WM_operator_call_py(struct bContext *C,
wmOperatorCallContext context,
struct PointerRNA *properties,
struct ReportList *reports,
- const bool is_undo);
+ bool is_undo);
void WM_operator_name_call_ptr_with_depends_on_cursor(struct bContext *C,
wmOperatorType *ot,
@@ -706,7 +707,7 @@ void WM_operator_properties_alloc(struct PointerRNA **ptr,
/**
* Make props context sensitive or not.
*/
-void WM_operator_properties_sanitize(struct PointerRNA *ptr, const bool no_context);
+void WM_operator_properties_sanitize(struct PointerRNA *ptr, bool no_context);
/**
* Set all props to their default.
@@ -716,7 +717,7 @@ void WM_operator_properties_sanitize(struct PointerRNA *ptr, const bool no_conte
* \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);
+bool WM_operator_properties_default(struct PointerRNA *ptr, bool do_update);
/**
* Remove all props without #PROP_SKIP_SAVE.
*/
@@ -738,7 +739,7 @@ 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);
+ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, short idcode);
bool WM_operator_last_properties_init(struct wmOperator *op);
bool WM_operator_last_properties_store(struct wmOperator *op);
@@ -870,14 +871,14 @@ bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalPa
*/
char *WM_operator_pystring_ex(struct bContext *C,
struct wmOperator *op,
- const bool all_args,
- const bool macro_args,
+ bool all_args,
+ bool macro_args,
struct wmOperatorType *ot,
struct PointerRNA *opptr);
char *WM_operator_pystring(struct bContext *C,
struct wmOperator *op,
- const bool all_args,
- const bool macro_args);
+ bool all_args,
+ bool macro_args);
/**
* \return true if the string was shortened.
*/
@@ -1243,7 +1244,7 @@ void wmOrtho2(float x1, float x2, float y1, float y2);
* Default pixel alignment for regions.
*/
void wmOrtho2_region_pixelspace(const struct ARegion *region);
-void wmOrtho2_pixelspace(const float x, const float y);
+void wmOrtho2_pixelspace(float x, float y);
void wmGetProjectionMatrix(float mat[4][4], const struct rcti *winrct);
/* threaded Jobs Manager */
@@ -1481,9 +1482,7 @@ int WM_userdef_event_map(int kmitype);
int WM_userdef_event_type_from_keymap_type(int kmitype);
#ifdef WITH_INPUT_NDOF
-void WM_event_ndof_pan_get(const struct wmNDOFMotionData *ndof,
- float r_pan[3],
- const bool use_zoom);
+void WM_event_ndof_pan_get(const struct wmNDOFMotionData *ndof, float r_pan[3], bool use_zoom);
void WM_event_ndof_rotate_get(const struct wmNDOFMotionData *ndof, float r_rot[3]);
float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]);
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index 4d1f2d979cb..4f1a2c8b923 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -63,10 +63,7 @@ wmKeyMapItem *WM_keymap_add_item(
wmKeyMapItem *WM_keymap_add_item_copy(struct wmKeyMap *keymap, wmKeyMapItem *kmi_src);
bool WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi);
-int WM_keymap_item_to_string(const wmKeyMapItem *kmi,
- const bool compact,
- char *result,
- const int result_len);
+int WM_keymap_item_to_string(const wmKeyMapItem *kmi, bool compact, char *result, int result_len);
wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int regionid);
wmKeyMap *WM_keymap_list_find_spaceid_or_empty(ListBase *lb,
@@ -135,26 +132,20 @@ wmKeyMap *WM_keymap_guess_from_context(const struct bContext *C);
*/
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);
+bool WM_keymap_uses_event_modifier(const wmKeyMap *keymap, int event_modifier);
void WM_keymap_fix_linking(void);
/* Modal Keymap */
-int WM_modalkeymap_items_to_string(const struct wmKeyMap *km,
- const int propvalue,
- const bool compact,
- char *result,
- const int result_len);
-int WM_modalkeymap_operator_items_to_string(struct wmOperatorType *ot,
- const int propvalue,
- const bool compact,
- char *result,
- const int result_len);
+int WM_modalkeymap_items_to_string(
+ const struct wmKeyMap *km, int propvalue, bool compact, char *result, int result_len);
+int WM_modalkeymap_operator_items_to_string(
+ struct wmOperatorType *ot, int propvalue, bool compact, char *result, int result_len);
char *WM_modalkeymap_operator_items_to_string_buf(struct wmOperatorType *ot,
- const int propvalue,
- const bool compact,
- const int max_len,
+ int propvalue,
+ bool compact,
+ int max_len,
int *r_available_len,
char **r_result);
@@ -166,7 +157,7 @@ wmKeyMapItem *WM_modalkeymap_add_item(
struct wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value);
wmKeyMapItem *WM_modalkeymap_add_item_str(
struct wmKeyMap *km, int type, int val, int modifier, int keymodifier, const char *value);
-const wmKeyMapItem *WM_modalkeymap_find_propvalue(const wmKeyMap *km, const int propvalue);
+const wmKeyMapItem *WM_modalkeymap_find_propvalue(const wmKeyMap *km, int propvalue);
void WM_modalkeymap_assign(struct wmKeyMap *km, const char *opname);
/* Keymap Editor */
@@ -183,17 +174,17 @@ int WM_keymap_item_map_type_get(const struct wmKeyMapItem *kmi);
/* Key Event */
-const char *WM_key_event_string(const short type, const bool compact);
-int WM_keymap_item_raw_to_string(const short shift,
- const short ctrl,
- const short alt,
- const short oskey,
- const short keymodifier,
- const short val,
- const short type,
- const bool compact,
+const char *WM_key_event_string(short type, bool compact);
+int WM_keymap_item_raw_to_string(short shift,
+ short ctrl,
+ short alt,
+ short oskey,
+ short keymodifier,
+ short val,
+ short type,
+ bool compact,
char *result,
- const int result_len);
+ int result_len);
/**
* \param include_mask, exclude_mask:
* Event types to include/exclude when looking up keys (#eEventType_Mask).
@@ -202,22 +193,22 @@ wmKeyMapItem *WM_key_event_operator(const struct bContext *C,
const char *opname,
wmOperatorCallContext opcontext,
struct IDProperty *properties,
- const short include_mask,
- const short exclude_mask,
+ short include_mask,
+ short exclude_mask,
struct wmKeyMap **r_keymap);
char *WM_key_event_operator_string(const struct bContext *C,
const char *opname,
wmOperatorCallContext opcontext,
struct IDProperty *properties,
- const bool is_strict,
+ bool is_strict,
char *result,
- const int result_len);
+ int result_len);
wmKeyMapItem *WM_key_event_operator_from_keymap(struct wmKeyMap *keymap,
const char *opname,
struct IDProperty *properties,
- const short include_mask,
- const short exclude_mask);
+ short include_mask,
+ short exclude_mask);
const char *WM_bool_as_string(bool test);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 3d56303a424..d1f790ce3e2 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -118,6 +118,7 @@ struct wmOperator;
struct wmWindowManager;
#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines.h"
#include "DNA_listBase.h"
#include "DNA_uuid_types.h"
#include "DNA_vec_types.h"
@@ -976,6 +977,7 @@ typedef enum eWM_DragFlags {
WM_DRAG_NOP = 0,
WM_DRAG_FREE_DATA = 1,
} eWM_DragFlags;
+ENUM_OPERATORS(eWM_DragFlags, WM_DRAG_FREE_DATA)
/* NOTE: structs need not exported? */
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index 497e4f6e5fc..5bcb9b195bf 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -138,9 +138,9 @@ void WM_gizmo_set_matrix_offset_rotation_from_yz_axis(struct wmGizmo *gz,
const float y_axis[3],
const float z_axis[3]);
-void WM_gizmo_set_flag(struct wmGizmo *gz, const int flag, const bool enable);
-void WM_gizmo_set_scale(struct wmGizmo *gz, const float scale);
-void WM_gizmo_set_line_width(struct wmGizmo *gz, const float line_width);
+void WM_gizmo_set_flag(struct wmGizmo *gz, int flag, bool enable);
+void WM_gizmo_set_scale(struct wmGizmo *gz, float scale);
+void WM_gizmo_set_line_width(struct wmGizmo *gz, float line_width);
void WM_gizmo_get_color(const struct wmGizmo *gz, float color[4]);
void WM_gizmo_set_color(struct wmGizmo *gz, const float color[4]);
@@ -175,7 +175,7 @@ void WM_gizmo_properties_create(struct PointerRNA *ptr, const char *gtstring);
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);
+void WM_gizmo_properties_sanitize(struct PointerRNA *ptr, bool no_context);
/**
* Set all props to their default.
*
@@ -184,7 +184,7 @@ void WM_gizmo_properties_sanitize(struct PointerRNA *ptr, const bool no_context)
* \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);
+bool WM_gizmo_properties_default(struct PointerRNA *ptr, bool do_update);
/**
* Remove all props without #PROP_SKIP_SAVE.
*/
@@ -199,7 +199,7 @@ void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void
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.
+ * Free but don't remove from #GHash.
*/
void WM_gizmotype_free_ptr(struct wmGizmoType *gzt);
/**
@@ -274,7 +274,7 @@ float WM_gizmo_target_property_float_get(const struct wmGizmo *gz,
void WM_gizmo_target_property_float_set(struct bContext *C,
const struct wmGizmo *gz,
struct wmGizmoProperty *gz_prop,
- const float value);
+ float value);
void WM_gizmo_target_property_float_get_array(const struct wmGizmo *gz,
struct wmGizmoProperty *gz_prop,
@@ -376,15 +376,14 @@ struct wmGizmoGroup *WM_gizmomap_group_find_ptr(struct wmGizmoMap *gzmap,
const struct wmGizmoGroupType *gzgt);
eWM_GizmoFlagMapDrawStep WM_gizmomap_drawstep_from_gizmo_group(const struct wmGizmoGroup *gzgroup);
-void WM_gizmomap_tag_refresh_drawstep(struct wmGizmoMap *gzmap,
- const eWM_GizmoFlagMapDrawStep drawstep);
+void WM_gizmomap_tag_refresh_drawstep(struct wmGizmoMap *gzmap, eWM_GizmoFlagMapDrawStep drawstep);
void WM_gizmomap_tag_refresh(struct wmGizmoMap *gzmap);
bool WM_gizmomap_tag_delay_refresh_for_tweak_check(struct wmGizmoMap *gzmap);
void WM_gizmomap_draw(struct wmGizmoMap *gzmap,
const struct bContext *C,
- const eWM_GizmoFlagMapDrawStep drawstep);
+ eWM_GizmoFlagMapDrawStep drawstep);
void WM_gizmomap_add_handlers(struct ARegion *region, struct wmGizmoMap *gzmap);
/**
* Select/Deselect all selectable gizmos in \a gzmap.
@@ -392,7 +391,7 @@ void WM_gizmomap_add_handlers(struct ARegion *region, struct wmGizmoMap *gzmap);
*
* TODO: select all by type.
*/
-bool WM_gizmomap_select_all(struct bContext *C, struct wmGizmoMap *gzmap, const int action);
+bool WM_gizmomap_select_all(struct bContext *C, struct wmGizmoMap *gzmap, int action);
bool WM_gizmomap_cursor_set(const struct wmGizmoMap *gzmap, struct wmWindow *win);
void WM_gizmomap_message_subscribe(const struct bContext *C,
struct wmGizmoMap *gzmap,
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
index b6912d79076..187612f2651 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
@@ -40,7 +40,7 @@ bool wm_gizmo_select_set_ex(
bool wm_gizmo_select_and_highlight(bContext *C, struct wmGizmoMap *gzmap, struct wmGizmo *gz);
void wm_gizmo_calculate_scale(struct wmGizmo *gz, const bContext *C);
-void wm_gizmo_update(struct wmGizmo *gz, const bContext *C, const bool refresh_map);
+void wm_gizmo_update(struct wmGizmo *gz, const bContext *C, bool refresh_map);
int wm_gizmo_is_visible(struct wmGizmo *gz);
enum {
@@ -75,7 +75,7 @@ struct wmGizmoGroup *wm_gizmogroup_find_by_type(const struct wmGizmoMap *gzmap,
struct wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm,
const struct wmGizmoGroup *gzgroup,
struct bContext *C,
- const int event_modifier,
+ int event_modifier,
const int mval[2],
int *r_part);
/**
@@ -84,10 +84,10 @@ struct wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm,
*/
void wm_gizmogroup_intersectable_gizmos_to_list(wmWindowManager *wm,
const struct wmGizmoGroup *gzgroup,
- const int event_modifier,
+ int event_modifier,
struct BLI_Buffer *visible_gizmos);
bool wm_gizmogroup_is_visible_in_drawstep(const struct wmGizmoGroup *gzgroup,
- const eWM_GizmoFlagMapDrawStep drawstep);
+ eWM_GizmoFlagMapDrawStep drawstep);
void wm_gizmogrouptype_setup_keymap(struct wmGizmoGroupType *gzgt, struct wmKeyConfig *keyconf);
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index d3e682f1490..e61de28d0a4 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -38,9 +38,11 @@
#include "ED_select_utils.h"
#include "ED_view3d.h"
+#include "GPU_framebuffer.h"
#include "GPU_matrix.h"
#include "GPU_select.h"
#include "GPU_state.h"
+#include "GPU_viewport.h"
#include "MEM_guardedalloc.h"
@@ -505,8 +507,7 @@ void WM_gizmomap_draw(wmGizmoMap *gzmap,
static void gizmo_draw_select_3d_loop(const bContext *C,
wmGizmo **visible_gizmos,
- const int visible_gizmos_len,
- bool *r_use_select_bias)
+ const int visible_gizmos_len)
{
/* TODO(campbell): this depends on depth buffer being written to,
@@ -542,10 +543,6 @@ static void gizmo_draw_select_3d_loop(const bContext *C,
is_depth_skip_prev = is_depth_skip;
}
- if (gz->select_bias != 0.0) {
- *r_use_select_bias = true;
- }
-
/* pass the selection id shifted by 8 bits. Last 8 bits are used for selected gizmo part id */
gz->type->draw_select(C, gz, select_id << 8);
@@ -563,7 +560,10 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
const int visible_gizmos_len,
const bContext *C,
const int co[2],
- const int hotspot)
+ const int hotspot,
+ const bool use_depth_test,
+ const bool has_3d_select_bias,
+ int *r_hits)
{
const wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *area = CTX_wm_area(C);
@@ -577,30 +577,69 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
BLI_rcti_init_pt_radius(&rect, co, hotspot);
- ED_view3d_draw_setup_view(
- wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
-
- bool use_select_bias = false;
+ /* The selection mode is assigned for the following reasons:
+ *
+ * - #GPU_SELECT_ALL: Use it to check if there is anything at the cursor location
+ * (only ever runs once).
+ * - #GPU_SELECT_PICK_NEAREST: Use if there are more than 1 item at the cursor location,
+ * select the best one.
+ * - #GPU_SELECT_PICK_ALL: Use for the same purpose as #GPU_SELECT_PICK_NEAREST
+ * when the selection depths need to re-ordered based on a bias.
+ * */
+ const int gpu_select_mode = (use_depth_test ?
+ (has_3d_select_bias ?
+ /* Using select bias means the depths need to be
+ * re-calculated based on the bias to pick the best. */
+ GPU_SELECT_PICK_ALL :
+ /* No bias, just pick the closest. */
+ GPU_SELECT_PICK_NEAREST) :
+ /* Fast-path (occlusion queries). */
+ GPU_SELECT_ALL);
+
+ if (GPU_select_is_cached()) {
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0);
+ GPU_select_cache_load_id();
+ hits = GPU_select_end();
+ }
+ else {
+ /* TODO: waiting for the GPU in the middle of the event loop for every
+ * mouse move is bad for performance, we need to find a solution to not
+ * use the GPU or draw something once. (see T61474) */
+
+ ED_view3d_draw_setup_view(
+ wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, &rect);
+
+ /* There is no need to bind to the depth buffer outside this function
+ * because all future passes the will use the cached depths. */
+ GPUFrameBuffer *depth_read_fb = NULL;
+ if (use_depth_test) {
+ GPUViewport *viewport = WM_draw_region_get_viewport(CTX_wm_region(C));
+ GPUTexture *depth_tx = GPU_viewport_depth_texture(viewport);
+ GPU_framebuffer_ensure_config(&depth_read_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(depth_tx),
+ GPU_ATTACHMENT_NONE,
+ });
+ GPU_framebuffer_bind(depth_read_fb);
+ }
- /* TODO: waiting for the GPU in the middle of the event loop for every
- * mouse move is bad for performance, we need to find a solution to not
- * use the GPU or draw something once. (see T61474) */
- GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
- /* do the drawing */
- gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
+ GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, gpu_select_mode, 0);
+ gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len);
+ hits = GPU_select_end();
- hits = GPU_select_end();
+ if (use_depth_test) {
+ GPU_framebuffer_restore();
+ GPU_framebuffer_free(depth_read_fb);
+ }
- if (hits > 0) {
- GPU_select_begin(buffer, ARRAY_SIZE(buffer), &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
- gizmo_draw_select_3d_loop(C, visible_gizmos, visible_gizmos_len, &use_select_bias);
- GPU_select_end();
+ ED_view3d_draw_setup_view(
+ wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
}
- ED_view3d_draw_setup_view(
- wm, CTX_wm_window(C), depsgraph, CTX_data_scene(C), region, v3d, NULL, NULL, NULL);
+ /* When selection bias is needed, this function will run again with `use_depth_test` enabled. */
+ int hit_found = -1;
- if (use_select_bias && (hits > 1)) {
+ if (has_3d_select_bias && use_depth_test && (hits > 1)) {
float co_direction[3];
float co_screen[3] = {co[0], co[1], 0.0f};
ED_view3d_win_to_vector(region, (float[2]){UNPACK2(co)}, co_direction);
@@ -612,7 +651,6 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
GPU_matrix_unproject_3fv(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin);
uint *buf_iter = buffer;
- int hit_found = -1;
float dot_best = FLT_MAX;
for (int i = 0; i < hits; i++, buf_iter += 4) {
@@ -632,11 +670,16 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
hit_found = buf_iter[3];
}
}
- return hit_found;
+ }
+ else {
+ const uint *hit_near = GPU_select_buffer_near(buffer, hits);
+ if (hit_near) {
+ hit_found = hit_near[3];
+ }
}
- const uint *hit_near = GPU_select_buffer_near(buffer, hits);
- return hit_near ? hit_near[3] : -1;
+ *r_hits = hits;
+ return hit_found;
}
/**
@@ -659,6 +702,7 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
/* Search for 3D gizmo's that use the 2D callback for checking intersections. */
bool has_3d = false;
+ bool has_3d_select_bias = false;
{
for (int select_id = 0; select_id < visible_gizmos_len; select_id++) {
wmGizmo *gz = visible_gizmos[select_id];
@@ -674,6 +718,9 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
}
else if (gz->type->draw_select != NULL) {
has_3d = true;
+ if (gz->select_bias != 0.0f) {
+ has_3d_select_bias = true;
+ }
}
}
}
@@ -681,17 +728,78 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
/* Search for 3D intersections if they're before 2D that have been found (if any).
* This way we always use the first hit. */
if (has_3d) {
+
+ /* NOTE(@campbellbarton): The selection logic here uses a fast-path that exits early
+ * where possible. This is important as this runs on cursor-motion in the 3D view-port.
+ *
+ * - First, don't use the depth buffer at all, use occlusion queries to detect any gizmos.
+ * If there are no gizmos or only one - early exit, otherwise.
+ *
+ * - Bind the depth buffer and and use selection picking logic.
+ * This is much slower than occlusion queries (since it's reading depths while drawing).
+ * When there is a single gizmo under the cursor (quite common), early exit, otherwise.
+ *
+ * - Perform another pass at a reduced size (see: `hotspot_radii`),
+ * since the result depths are cached this pass is practically free.
+ *
+ * Other notes:
+ *
+ * - If any of these passes fail, use the nearest result from the previous pass.
+ *
+ * - Drawing is only ever done twice.
+ */
+
+ /* Order largest to smallest so the first pass can be used as cache for
+ * later passes (when `use_depth_test == true`). */
const int hotspot_radii[] = {
- 3 * U.pixelsize,
- /* This runs on mouse move, careful doing too many tests! */
10 * U.pixelsize,
+ /* This runs on mouse move, careful doing too many tests! */
+ 3 * U.pixelsize,
};
+
+ /* Narrowing may assign zero to `hit`, allow falling back to the previous test. */
+ int hit_prev = -1;
+
+ bool use_depth_test = false;
+ bool use_depth_cache = false;
+
for (int i = 0; i < ARRAY_SIZE(hotspot_radii); i++) {
- hit = gizmo_find_intersected_3d_intern(
- visible_gizmos, visible_gizmos_len_trim, C, co, hotspot_radii[i]);
- if (hit != -1) {
+
+ if (use_depth_test && (use_depth_cache == false)) {
+ GPU_select_cache_begin();
+ use_depth_cache = true;
+ }
+
+ int hit_count;
+ hit = gizmo_find_intersected_3d_intern(visible_gizmos,
+ visible_gizmos_len_trim,
+ C,
+ co,
+ hotspot_radii[i],
+ use_depth_test,
+ has_3d_select_bias,
+ &hit_count);
+ /* Only continue searching when there are multiple options to narrow down. */
+ if (hit_count < 2) {
break;
}
+
+ /* Fast path for simple case, one item or nothing. */
+ if (use_depth_test == false) {
+ /* Restart, using depth buffer (slower). */
+ use_depth_test = true;
+ i = -1;
+ }
+ hit_prev = hit;
+ }
+ /* Narrowing the search area may yield no hits,
+ * in this case fall back to the previous search. */
+ if (hit == -1) {
+ hit = hit_prev;
+ }
+
+ if (use_depth_cache) {
+ GPU_select_cache_end();
}
if (hit != -1) {
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index e1017c4236e..96cb66b44ea 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -748,19 +748,19 @@ static void wm_drag_draw_icon(bContext *UNUSED(C),
float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTexScaled(&state,
- x,
- y,
- drag->imb->x,
- drag->imb->y,
- GPU_RGBA8,
- false,
- drag->imb->rect,
- drag->scale,
- drag->scale,
- 1.0f,
- 1.0f,
- col);
+ immDrawPixelsTexTiled_scaling(&state,
+ x,
+ y,
+ drag->imb->x,
+ drag->imb->y,
+ GPU_RGBA8,
+ false,
+ drag->imb->rect,
+ drag->scale,
+ drag->scale,
+ 1.0f,
+ 1.0f,
+ col);
}
else {
int padding = 4 * UI_DPI_FAC;
@@ -884,7 +884,7 @@ void wm_drags_draw(bContext *C, wmWindow *win)
bScreen *screen = CTX_wm_screen(C);
/* To start with, use the area and region under the mouse cursor, just like event handling. The
* operator context may still override it. */
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, UNPACK2(xy));
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, xy);
ARegion *region = ED_area_find_region_xy_visual(area, RGN_TYPE_ANY, xy);
/* Will be overridden and unset eventually. */
BLI_assert(!CTX_wm_area(C) && !CTX_wm_region(C));
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index ab9de6ce4d4..9dfac54a91e 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -1140,7 +1140,7 @@ void WM_redraw_windows(bContext *C)
* This is needed for viewport drawing for operator use
* (where the viewport may not have drawn yet).
*
- * Otherwise avoid using these sine they're exposing low level logic externally.
+ * Otherwise avoid using these since they're exposing low level logic externally.
*
* \{ */
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 1b6df9fb0db..3e30c06ade2 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -51,6 +51,7 @@
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -312,28 +313,39 @@ void WM_main_remove_notifier_reference(const void *reference)
}
}
-void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
+static void wm_main_remap_assetlist(ID *old_id, ID *new_id, void *UNUSED(user_data))
+{
+ ED_assetlist_storage_id_remap(old_id, new_id);
+}
+
+static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data)
+{
+ struct wmMsgBus *mbus = user_data;
+ if (new_id != NULL) {
+ WM_msg_id_update(mbus, old_id, new_id);
+ }
+ else {
+ WM_msg_id_remove(mbus, old_id);
+ }
+}
+
+void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
{
Main *bmain = G_MAIN;
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
- ED_spacedata_id_remap(area, sl, old_id, new_id);
+ ED_spacedata_id_remap(area, sl, mappings);
}
}
}
- ED_assetlist_storage_id_remap(old_id, new_id);
+
+ BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, NULL);
wmWindowManager *wm = bmain->wm.first;
if (wm && wm->message_bus) {
- struct wmMsgBus *mbus = wm->message_bus;
- if (new_id != NULL) {
- WM_msg_id_update(mbus, old_id, new_id);
- }
- else {
- WM_msg_id_remove(mbus, old_id);
- }
+ BKE_id_remapper_iter(mappings, wm_main_remap_msgbus_notify, wm->message_bus);
}
}
@@ -1861,8 +1873,7 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
CTX_wm_area_set(C, area);
if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
- region = BKE_area_find_region_xy(
- area, handler->context.region_type, event->xy[0], event->xy[1]);
+ region = BKE_area_find_region_xy(area, handler->context.region_type, event->xy);
if (region) {
handler->context.region = region;
}
@@ -2264,7 +2275,7 @@ static int wm_handler_operator_call(bContext *C,
CTX_wm_region_set(C, NULL);
}
- /* /update gizmos during modal handlers. */
+ /* Update gizmos during modal handlers. */
wm_gizmomaps_handled_modal_update(C, event, handler);
/* Remove modal handler, operator itself should have been canceled and freed. */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index ddc4692084e..1478712c3cd 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -193,7 +193,6 @@ bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWind
static void wm_window_match_init(bContext *C, ListBase *wmlist)
{
*wmlist = G_MAIN->wm;
- BLI_listbase_clear(&G_MAIN->wm);
wmWindow *active_win = CTX_wm_window(C);
@@ -220,6 +219,8 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
}
}
+ BLI_listbase_clear(&G_MAIN->wm);
+
/* reset active window */
CTX_wm_window_set(C, active_win);
@@ -263,7 +264,7 @@ static void wm_window_substitute_old(wmWindowManager *oldwm,
win->eventstate = oldwin->eventstate;
oldwin->eventstate = NULL;
- /* ensure proper screen rescaling */
+ /* Ensure proper screen re-scaling. */
win->sizex = oldwin->sizex;
win->sizey = oldwin->sizey;
win->posx = oldwin->posx;
@@ -955,14 +956,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.relbase_valid = 1;
- }
- else {
- 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 */
@@ -1149,8 +1142,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);
}
@@ -1530,11 +1521,29 @@ static void wm_history_file_update(void)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Save Main Blend-File (internal) Screen-Shot
+/** \name Thumbnail Generation: Screen-Shot / Camera View
+ *
+ * Thumbnail Sizes
+ * ===============
+ *
+ * - `PREVIEW_RENDER_LARGE_HEIGHT * 2` is used to render a large thumbnail,
+ * giving some over-sampling when scaled down:
+ *
+ * - There are two outputs for this thumbnail:
+ *
+ * - An image is saved to the thumbnail cache, sized at #PREVIEW_RENDER_LARGE_HEIGHT.
+ *
+ * - A smaller thumbnail is stored in the `.blend` file it's self, sized at #BLEN_THUMB_SIZE.
+ * The size is kept small to prevent thumbnails bloating the size of `.blend` files.
+ *
+ * The this thumbnail will be extracted if the file is shared or the local thumbnail cache
+ * is cleared. see: `blendthumb_extract.cc` for logic that extracts the thumbnail.
*
- * Screen-shot the active window.
* \{ */
+/**
+ * Screen-shot the active window.
+ */
static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **r_thumb)
{
*r_thumb = NULL;
@@ -1580,15 +1589,11 @@ static ImBuf *blend_file_thumb_from_screenshot(bContext *C, BlendThumbnail **r_t
return ibuf;
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Save Main Blend-File (internal) Camera View
- *
+/**
* Render the current scene with the active camera.
- * \{ */
-
-/* screen can be NULL */
+ *
+ * \param screen: can be NULL.
+ */
static ImBuf *blend_file_thumb_from_camera(const bContext *C,
Scene *scene,
bScreen *screen,
@@ -1626,7 +1631,6 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C,
return NULL;
}
- /* gets scaled to BLEN_THUMB_SIZE */
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
/* Note that with scaling, this ends up being 0.5,
@@ -1698,6 +1702,12 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C,
return ibuf;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Write Main Blend-File (internal)
+ * \{ */
+
bool write_crash_blend(void)
{
char path[FILE_MAX];
@@ -1823,16 +1833,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)) {
- STRNCPY(bmain->filepath, filepath);
- }
-
/* 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){
@@ -1846,7 +1850,6 @@ 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;
STRNCPY(bmain->filepath, filepath); /* is guaranteed current file */
}
@@ -1898,8 +1901,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);
}
@@ -2028,7 +2036,7 @@ void wm_autosave_delete(void)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Initialize WM_OT_open_xxx properties
+/** \name Initialize `WM_OT_open_*` Properties
*
* Check if load_ui was set by the caller.
* Fall back to user preference when file flags not specified.
@@ -2109,7 +2117,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. */
@@ -2847,7 +2855,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)
@@ -3004,9 +3013,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.relbase_valid == false) {
+ if (bmain->filepath[0] == '\0') {
BLI_path_filename_ensure(filepath, FILE_MAX, "untitled.blend");
}
}
@@ -3017,7 +3026,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.relbase_valid) { /* 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 */
@@ -3034,16 +3044,17 @@ static void save_set_filepath(bContext *C, wmOperator *op)
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;
STRNCPY(filepath, recent->filepath);
}
else {
- STRNCPY(filepath, bmain->filepath);
+ STRNCPY(filepath, blendfile_path);
}
- wm_filepath_default(filepath);
+ wm_filepath_default(bmain, filepath);
RNA_property_string_set(op->ptr, prop, filepath);
}
}
@@ -3076,12 +3087,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;
@@ -3198,14 +3229,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.relbase_valid) {
+ if (blendfile_path[0] != '\0') {
char path[FILE_MAX];
RNA_string_get(op->ptr, "filepath", path);
@@ -3307,6 +3339,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);
@@ -3354,7 +3387,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,
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 1b60167be4f..cf6ecd55757 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -113,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);
}
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 47f51214a8e..7f923d4af60 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -412,7 +412,7 @@ static void draw_filled_lasso(wmGesture *gt)
GPU_shader_uniform_vector(
state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
- immDrawPixelsTex(
+ immDrawPixelsTexTiled(
&state, rect.xmin, rect.ymin, w, h, GPU_R8, false, pixel_buf, 1.0f, 1.0f, NULL);
GPU_shader_unbind();
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 2f87e5789fe..6caac79c4d5 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -252,7 +252,7 @@ void WM_init(bContext *C, int argc, const char **argv)
BKE_region_callback_free_gizmomap_set(wm_gizmomap_remove);
BKE_region_callback_refresh_tag_gizmomap_set(WM_gizmomap_tag_refresh);
BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference);
- BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap);
+ BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap_single);
DEG_editors_set_update_cb(ED_render_id_flush_update, ED_render_scene_update);
ED_spacetypes_init();
@@ -562,6 +562,13 @@ void WM_exit_ex(bContext *C, const bool do_python)
BKE_blender_free(); /* blender.c, does entire library and spacetypes */
// BKE_material_copybuf_free();
+
+ /* Free the GPU subdivision data after the database to ensure that subdivision structs used by
+ * the modifiers were garbage collected. */
+ if (opengl_is_init) {
+ DRW_subdiv_free();
+ }
+
ANIM_fcurves_copybuf_free();
ANIM_drivers_copybuf_free();
ANIM_driver_vars_copybuf_free();
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index 66277ec57f4..e7ad654d3e5 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -381,7 +381,6 @@ static void *do_job_thread(void *job_v)
{
wmJob *wm_job = job_v;
- BLI_thread_put_thread_on_fast_node();
wm_job->startjob(wm_job->run_customdata, &wm_job->stop, &wm_job->do_update, &wm_job->progress);
wm_job->ready = true;
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index a5887fc07b3..ebd6719d54d 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -184,6 +184,9 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
prop = RNA_def_boolean(
ot->srna, "filter_usd", (filter & FILE_TYPE_USD) != 0, "Filter USD files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(
+ ot->srna, "filter_obj", (filter & FILE_TYPE_OBJECT_IO) != 0, "Filter OBJ files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"filter_volume",
(filter & FILE_TYPE_VOLUME) != 0,
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index b2ea99ea854..a1854a8ed86 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -428,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.relbase_valid && BKE_main_blendfile_path_from_global()[0]) {
+ 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);
}
@@ -1032,7 +1033,9 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
}
wm_window_set_drawable(wm, win, true);
+ }
+ if (win->ghostwin) {
/* this can change per window */
WM_window_set_dpi(win);
}
diff --git a/source/blender/windowmanager/message_bus/wm_message_bus.h b/source/blender/windowmanager/message_bus/wm_message_bus.h
index 7ee2e5b6ee6..a93a7bbcea7 100644
--- a/source/blender/windowmanager/message_bus/wm_message_bus.h
+++ b/source/blender/windowmanager/message_bus/wm_message_bus.h
@@ -244,6 +244,17 @@ void WM_msg_subscribe_ID(struct wmMsgBus *mbus,
const char *id_repr);
void WM_msg_publish_ID(struct wmMsgBus *mbus, struct ID *id);
+/* FIXME
+ *
+ * For C++ code, some of the following macros need to be called in functions wrapped in
+ * `extern "C"` blocks. That is, the ones doing `extern PropertyRNA` declarations (trips up the
+ * MSVC linker).
+ * Although this shouldn't cause problems normally, if it does, the bits calling the macros can be
+ * moved to a separate function wrapped in `extern "C"`.
+ *
+ * Obviously this should be fixed properly (by not relying on inline `extern` declarations).
+ */
+
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_) \
{ \
wmMsgParams_RNA msg_key_params_ = {{0}}; \
@@ -270,16 +281,11 @@ void WM_msg_publish_ID(struct wmMsgBus *mbus, struct ID *id);
/* Anonymous variants (for convenience) */
#define WM_msg_subscribe_rna_anon_type(mbus, type_, value) \
{ \
- WM_msg_subscribe_rna_params(mbus, \
- &(const wmMsgParams_RNA){ \
- .ptr = \
- (PointerRNA){ \
- .type = &RNA_##type_, \
- }, \
- .prop = NULL, \
- }, \
- value, \
- __func__); \
+ PointerRNA msg_ptr_ = {0, &RNA_##type_}; \
+ wmMsgParams_RNA msg_key_params_ = {{0}}; \
+ msg_key_params_.ptr = msg_ptr_; \
+\
+ WM_msg_subscribe_rna_params(mbus, &msg_key_params_, value, __func__); \
} \
((void)0)
#define WM_msg_subscribe_rna_anon_prop(mbus, type_, prop_, value) \
@@ -287,16 +293,13 @@ void WM_msg_publish_ID(struct wmMsgBus *mbus, struct ID *id);
_WM_MESSAGE_EXTERN_BEGIN; \
extern PropertyRNA rna_##type_##_##prop_; \
_WM_MESSAGE_EXTERN_END; \
- WM_msg_subscribe_rna_params(mbus, \
- &(const wmMsgParams_RNA){ \
- .ptr = \
- (PointerRNA){ \
- .type = &RNA_##type_, \
- }, \
- .prop = &rna_##type_##_##prop_, \
- }, \
- value, \
- __func__); \
+\
+ PointerRNA msg_ptr_ = {0, &RNA_##type_}; \
+ wmMsgParams_RNA msg_key_params_ = {{0}}; \
+ msg_key_params_.ptr = msg_ptr_; \
+ msg_key_params_.prop = &rna_##type_##_##prop_; \
+\
+ WM_msg_subscribe_rna_params(mbus, &msg_key_params_, value, __func__); \
} \
((void)0)
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 437bd1057c2..a6685e97c4f 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -29,7 +29,7 @@
extern "C" {
#endif
-/* customdata type */
+/** #wmEvent.customdata type */
enum {
EVT_DATA_TIMER = 2,
EVT_DATA_DRAGDROP = 3,
@@ -37,7 +37,11 @@ enum {
EVT_DATA_XR = 5,
};
-/* tablet active, matches GHOST_TTabletMode */
+/**
+ * #wmTabletData.active tablet active, matches #GHOST_TTabletMode.
+ *
+ * Typically access via `event->tablet.active`.
+ */
enum {
EVT_TABLET_NONE = 0,
EVT_TABLET_STYLUS = 1,
@@ -95,10 +99,14 @@ enum {
TABLET_STYLUS = 0x001a,
TABLET_ERASER = 0x001b,
- /* *** Start of keyboard codes. *** */
+/* *** Start of keyboard codes. *** */
+
+/* Minimum keyboard value (inclusive). */
+#define _EVT_KEYBOARD_MIN 0x0020
/* Standard keyboard.
- * From 0x0020 to 0x00ff, and 0x012c to 0x0143 for function keys! */
+ * - 0x0020 to 0x00ff [#_EVT_KEYBOARD_MIN to #_EVT_KEYBOARD_MAX] inclusive - for keys.
+ * - 0x012c to 0x0143 [#EVT_F1KEY to #EVT_F24KEY] inclusive - for function keys. */
EVT_ZEROKEY = 0x0030, /* '0' (48). */
EVT_ONEKEY = 0x0031, /* '1' (49). */
@@ -210,6 +218,12 @@ enum {
EVT_LEFTBRACKETKEY = 0x00eb, /* 235 */
EVT_RIGHTBRACKETKEY = 0x00ec, /* 236 */
+/* Maximum keyboard value (inclusive). */
+#define _EVT_KEYBOARD_MAX 0x00ff /* 255 */
+
+ /* WARNING: 0x010x are used for internal events
+ * (but are still stored in the key-map). */
+
EVT_F1KEY = 0x012c, /* 300 */
EVT_F2KEY = 0x012d, /* 301 */
EVT_F3KEY = 0x012e, /* 302 */
@@ -237,60 +251,65 @@ enum {
/* *** End of keyboard codes. *** */
- /* NDOF (from SpaceNavigator & friends)
- * These should be kept in sync with GHOST_NDOFManager.h
+ /* NDOF (from "Space Navigator" & friends)
+ * These must be kept in sync with `GHOST_NDOFManager.h`.
* Ordering matters, exact values do not. */
+
NDOF_MOTION = 0x0190, /* 400 */
+
+#define _NDOF_MIN NDOF_MOTION
+
/* used internally, never sent */
NDOF_BUTTON_NONE = NDOF_MOTION,
/* these two are available from any 3Dconnexion device */
- NDOF_BUTTON_MENU,
- NDOF_BUTTON_FIT,
+
+ NDOF_BUTTON_MENU = 0x0191, /* 401 */
+ NDOF_BUTTON_FIT = 0x0192, /* 402 */
/* standard views */
- NDOF_BUTTON_TOP,
- NDOF_BUTTON_BOTTOM,
- NDOF_BUTTON_LEFT,
- NDOF_BUTTON_RIGHT,
- NDOF_BUTTON_FRONT,
- NDOF_BUTTON_BACK,
+ NDOF_BUTTON_TOP = 0x0193, /* 403 */
+ NDOF_BUTTON_BOTTOM = 0x0194, /* 404 */
+ NDOF_BUTTON_LEFT = 0x0195, /* 405 */
+ NDOF_BUTTON_RIGHT = 0x0196, /* 406 */
+ NDOF_BUTTON_FRONT = 0x0197, /* 407 */
+ NDOF_BUTTON_BACK = 0x0198, /* 408 */
/* more views */
- NDOF_BUTTON_ISO1,
- NDOF_BUTTON_ISO2,
+ NDOF_BUTTON_ISO1 = 0x0199, /* 409 */
+ NDOF_BUTTON_ISO2 = 0x019a, /* 410 */
/* 90 degree rotations */
- NDOF_BUTTON_ROLL_CW,
- NDOF_BUTTON_ROLL_CCW,
- NDOF_BUTTON_SPIN_CW,
- NDOF_BUTTON_SPIN_CCW,
- NDOF_BUTTON_TILT_CW,
- NDOF_BUTTON_TILT_CCW,
+ NDOF_BUTTON_ROLL_CW = 0x019b, /* 411 */
+ NDOF_BUTTON_ROLL_CCW = 0x019c, /* 412 */
+ NDOF_BUTTON_SPIN_CW = 0x019d, /* 413 */
+ NDOF_BUTTON_SPIN_CCW = 0x019e, /* 414 */
+ NDOF_BUTTON_TILT_CW = 0x019f, /* 415 */
+ NDOF_BUTTON_TILT_CCW = 0x01a0, /* 416 */
/* device control */
- NDOF_BUTTON_ROTATE,
- NDOF_BUTTON_PANZOOM,
- NDOF_BUTTON_DOMINANT,
- NDOF_BUTTON_PLUS,
- NDOF_BUTTON_MINUS,
+ NDOF_BUTTON_ROTATE = 0x01a1, /* 417 */
+ NDOF_BUTTON_PANZOOM = 0x01a2, /* 418 */
+ NDOF_BUTTON_DOMINANT = 0x01a3, /* 419 */
+ NDOF_BUTTON_PLUS = 0x01a4, /* 420 */
+ NDOF_BUTTON_MINUS = 0x01a5, /* 421 */
/* keyboard emulation */
- NDOF_BUTTON_ESC,
- NDOF_BUTTON_ALT,
- NDOF_BUTTON_SHIFT,
- NDOF_BUTTON_CTRL,
+ NDOF_BUTTON_ESC = 0x01a6, /* 422 */
+ NDOF_BUTTON_ALT = 0x01a7, /* 423 */
+ NDOF_BUTTON_SHIFT = 0x01a8, /* 424 */
+ NDOF_BUTTON_CTRL = 0x01a9, /* 425 */
/* general-purpose buttons */
- NDOF_BUTTON_1,
- NDOF_BUTTON_2,
- NDOF_BUTTON_3,
- NDOF_BUTTON_4,
- NDOF_BUTTON_5,
- NDOF_BUTTON_6,
- NDOF_BUTTON_7,
- NDOF_BUTTON_8,
- NDOF_BUTTON_9,
- NDOF_BUTTON_10,
+ NDOF_BUTTON_1 = 0x01aa, /* 426 */
+ NDOF_BUTTON_2 = 0x01ab, /* 427 */
+ NDOF_BUTTON_3 = 0x01ac, /* 428 */
+ NDOF_BUTTON_4 = 0x01ad, /* 429 */
+ NDOF_BUTTON_5 = 0x01ae, /* 430 */
+ NDOF_BUTTON_6 = 0x01af, /* 431 */
+ NDOF_BUTTON_7 = 0x01b0, /* 432 */
+ NDOF_BUTTON_8 = 0x01b1, /* 433 */
+ NDOF_BUTTON_9 = 0x01b2, /* 434 */
+ NDOF_BUTTON_10 = 0x01b3, /* 435 */
/* more general-purpose buttons */
- NDOF_BUTTON_A,
- NDOF_BUTTON_B,
- NDOF_BUTTON_C,
- /* the end */
- NDOF_LAST,
+ NDOF_BUTTON_A = 0x01b4, /* 436 */
+ NDOF_BUTTON_B = 0x01b5, /* 437 */
+ NDOF_BUTTON_C = 0x01b6, /* 438 */
+
+#define _NDOF_MAX NDOF_BUTTON_C
/* ********** End of Input devices. ********** */
@@ -318,13 +337,13 @@ enum {
EVT_ACTIONZONE_REGION = 0x5001, /* 20481 */
EVT_ACTIONZONE_FULLSCREEN = 0x5011, /* 20497 */
- /* NOTE: these values are saved in keymap files, do not change them but just add new ones */
+ /* NOTE: these values are saved in key-map files, do not change them but just add new ones. */
/* Tweak events:
* Sent as additional event with the mouse coordinates
* from where the initial click was placed. */
- /* tweak events for L M R mousebuttons */
+ /* Tweak events for L M R mouse-buttons. */
EVT_TWEAK_L = 0x5002, /* 20482 */
EVT_TWEAK_M = 0x5003, /* 20483 */
EVT_TWEAK_R = 0x5004, /* 20484 */
@@ -348,9 +367,11 @@ enum {
/* ********** End of Blender internal events. ********** */
};
-/* *********** wmEvent.type helpers. ********** */
+/* -------------------------------------------------------------------- */
+/** \name #wmEvent.type Helpers
+ * \{ */
-/* test whether the event is timer event */
+/** Test whether the event is timer event. */
#define ISTIMER(event_type) ((event_type) >= TIMER && (event_type) <= TIMERF)
/* for event checks */
@@ -359,22 +380,24 @@ enum {
// #define ISTEXTINPUT(event_type) ((event_type) >= ' ' && (event_type) <= 255)
/* NOTE: an alternative could be to check `event->utf8_buf`. */
-/* test whether the event is a key on the keyboard */
+/** Test whether the event is a key on the keyboard (including modifier keys). */
#define ISKEYBOARD(event_type) \
- (((event_type) >= 0x0020 && (event_type) <= 0x00ff) || \
- ((event_type) >= 0x012c && (event_type) <= 0x0143))
+ (((event_type) >= _EVT_KEYBOARD_MIN && (event_type) <= _EVT_KEYBOARD_MAX) || \
+ ((event_type) >= EVT_F1KEY && (event_type) <= EVT_F24KEY))
-/* test whether the event is a modifier key */
+/** Test whether the event is a modifier key. */
#define ISKEYMODIFIER(event_type) \
(((event_type) >= EVT_LEFTCTRLKEY && (event_type) <= EVT_LEFTSHIFTKEY) || \
(event_type) == EVT_OSKEY)
-/* test whether the event is a mouse button */
+/** Test whether the event is a mouse button. */
#define ISMOUSE(event_type) \
(((event_type) >= LEFTMOUSE && (event_type) <= BUTTON7MOUSE) || (event_type) == MOUSESMARTZOOM)
-
+/** Test whether the event is a mouse wheel. */
#define ISMOUSE_WHEEL(event_type) ((event_type) >= WHEELUPMOUSE && (event_type) <= WHEELOUTMOUSE)
+/** Test whether the event is a mouse (track-pad) gesture. */
#define ISMOUSE_GESTURE(event_type) ((event_type) >= MOUSEPAN && (event_type) <= MOUSEROTATE)
+/** Test whether the event is a mouse button (excluding mouse-wheel). */
#define ISMOUSE_BUTTON(event_type) \
(ELEM(event_type, \
LEFTMOUSE, \
@@ -385,16 +408,16 @@ enum {
BUTTON6MOUSE, \
BUTTON7MOUSE))
-/* test whether the event is tweak event */
+/** Test whether the event is tweak event. */
#define ISTWEAK(event_type) ((event_type) >= EVT_TWEAK_L && (event_type) <= EVT_TWEAK_R)
-/* test whether the event is a NDOF event */
-#define ISNDOF(event_type) ((event_type) >= NDOF_MOTION && (event_type) < NDOF_LAST)
+/** Test whether the event is a NDOF event. */
+#define ISNDOF(event_type) ((event_type) >= _NDOF_MIN && (event_type) <= _NDOF_MAX)
#define IS_EVENT_ACTIONZONE(event_type) \
ELEM(event_type, EVT_ACTIONZONE_AREA, EVT_ACTIONZONE_REGION, EVT_ACTIONZONE_FULLSCREEN)
-/* test whether event type is acceptable as hotkey, excluding modifiers */
+/** Test whether event type is acceptable as hotkey (excluding modifiers). */
#define ISHOTKEY(event_type) \
((ISKEYBOARD(event_type) || ISMOUSE(event_type) || ISNDOF(event_type)) && \
(ISKEYMODIFIER(event_type) == false))
@@ -409,23 +432,23 @@ enum {
#define IS_EVENT_MOD(...) VA_NARGS_CALL_OVERLOAD(_VA_IS_EVENT_MOD, __VA_ARGS__)
enum eEventType_Mask {
- /* ISKEYMODIFIER */
+ /** #ISKEYMODIFIER */
EVT_TYPE_MASK_KEYBOARD_MODIFIER = (1 << 0),
- /* ISKEYBOARD */
+ /** #ISKEYBOARD */
EVT_TYPE_MASK_KEYBOARD = (1 << 1),
- /* ISMOUSE_WHEEL */
+ /** #ISMOUSE_WHEEL */
EVT_TYPE_MASK_MOUSE_WHEEL = (1 << 2),
- /* ISMOUSE_BUTTON */
+ /** #ISMOUSE_BUTTON */
EVT_TYPE_MASK_MOUSE_GESTURE = (1 << 3),
- /* ISMOUSE_GESTURE */
+ /** #ISMOUSE_GESTURE */
EVT_TYPE_MASK_MOUSE_BUTTON = (1 << 4),
- /* ISMOUSE */
+ /** #ISMOUSE */
EVT_TYPE_MASK_MOUSE = (1 << 5),
- /* ISNDOF */
+ /** #ISNDOF */
EVT_TYPE_MASK_NDOF = (1 << 6),
- /* ISTWEAK */
+ /** #ISTWEAK */
EVT_TYPE_MASK_TWEAK = (1 << 7),
- /* IS_EVENT_ACTIONZONE */
+ /** #IS_EVENT_ACTIONZONE */
EVT_TYPE_MASK_ACTIONZONE = (1 << 8),
};
#define EVT_TYPE_MASK_ALL \
@@ -436,9 +459,13 @@ enum eEventType_Mask {
(EVT_TYPE_MASK_KEYBOARD | EVT_TYPE_MASK_MOUSE | EVT_TYPE_MASK_NDOF)
#define EVT_TYPE_MASK_HOTKEY_EXCLUDE EVT_TYPE_MASK_KEYBOARD_MODIFIER
-bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask mask);
+bool WM_event_type_mask_test(int event_type, enum eEventType_Mask mask);
+
+/** \} */
-/* ********** wmEvent.val ********** */
+/* -------------------------------------------------------------------- */
+/** \name #wmEvent.val Values
+ * \{ */
/* Gestures */
/* NOTE: these values are saved in keymap files, do not change them but just add new ones */
@@ -505,6 +532,8 @@ enum {
GESTURE_MODAL_FLIP = 14,
};
+/** \} */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index e44a39ecf1a..b003a4f92e7 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -58,19 +58,13 @@ wmWindow *wm_window_new(const struct Main *bmain,
/**
* 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);
+wmWindow *wm_window_copy(
+ struct Main *bmain, wmWindowManager *wm, wmWindow *win_src, bool duplicate_layout, 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);
+wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src, bool duplicate_layout, bool child);
/**
* Including window itself.
* \param C: can be NULL.
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
index c503f5d4fee..9c2eaefd61c 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
@@ -956,7 +956,7 @@ static int wm_xr_navigation_fly_modal(bContext *C, wmOperator *op, const wmEvent
const double time_now = PIL_check_seconds_timer();
mode = (eXrFlyMode)RNA_enum_get(op->ptr, "mode");
- turn = (mode == XR_FLY_TURNLEFT || mode == XR_FLY_TURNRIGHT);
+ turn = (ELEM(mode, XR_FLY_TURNLEFT, XR_FLY_TURNRIGHT));
locz_lock = RNA_boolean_get(op->ptr, "lock_location_z");
dir_lock = RNA_boolean_get(op->ptr, "lock_direction");
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 816d3a60fc3..0609b8fd792 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -18,8 +18,6 @@
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
-setup_libdirs()
-
blender_include_dirs(
../../intern/clog
../../intern/glew-mx
@@ -73,8 +71,8 @@ endif()
if(WITH_TBB)
blender_include_dirs(${TBB_INCLUDE_DIRS})
- if(NOT APPLE)
- # APPLE platform uses full paths for linking libraries.
+ if(WIN32)
+ # For pragma that links tbbmalloc_proxy.lib
link_directories(${LIBDIR}/tbb/lib)
endif()
endif()
@@ -658,11 +656,11 @@ if(UNIX AND NOT APPLE)
# Install to the same directory as the source, so debian-like
# distros are happy with their policy.
set(_suffix "site-packages")
- if(${PYTHON_NUMPY_PATH} MATCHES "dist-packages")
+ if(${PYTHON_ZSTANDARD_PATH} MATCHES "dist-packages")
set(_suffix "dist-packages")
endif()
install(
- DIRECTORY ${PYTHON_NUMPY_PATH}/zstandard
+ DIRECTORY ${PYTHON_ZSTANDARD_PATH}/zstandard
DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix}
PATTERN ".svn" EXCLUDE
PATTERN "__pycache__" EXCLUDE # * any cache *
diff --git a/source/creator/blender_launcher_win32.c b/source/creator/blender_launcher_win32.c
index 86b0f4f3b97..f19438ad907 100644
--- a/source/creator/blender_launcher_win32.c
+++ b/source/creator/blender_launcher_win32.c
@@ -79,7 +79,26 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
BOOL success = CreateProcess(
path, buffer, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &siStartInfo, &procInfo);
+ DWORD returnValue = success ? 0 : -1;
+
if (success) {
+ /* If blender-launcher is called with background command line flag,
+ * wait for the blender process to exit and return its return value. */
+ BOOL background = FALSE;
+ int argc = 0;
+ LPWSTR *argv = CommandLineToArgvW(pCmdLine, &argc);
+ for (int i = 0; i < argc; i++) {
+ if ((wcscmp(argv[i], L"-b") == 0) || (wcscmp(argv[i], L"--background") == 0)) {
+ background = TRUE;
+ break;
+ }
+ }
+
+ if (background) {
+ WaitForSingleObject(procInfo.hProcess, INFINITE);
+ GetExitCodeProcess(procInfo.hProcess, &returnValue);
+ }
+
/* Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer
* needed - MSDN. Closing the handles will NOT terminate the thread/process that we just
* started. */
@@ -88,5 +107,5 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
}
free(buffer);
- return success ? 0 : -1;
+ return returnValue;
}
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 975800bb6c7..d69e4d075fd 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -58,6 +58,7 @@
#include "BKE_gpencil_modifier.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
+#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
@@ -407,7 +408,6 @@ int main(int argc,
BKE_appdir_program_path_init(argv[0]);
BLI_threadapi_init();
- BLI_thread_put_process_on_fast_node();
DNA_sdna_current_init();
@@ -553,7 +553,8 @@ int main(int argc,
}
else {
/* When no file is loaded, show the splash screen. */
- if (!G.relbase_valid) {
+ const char *blendfile_path = BKE_main_blendfile_path_from_global();
+ if (blendfile_path[0] == '\0') {
WM_init_splash(C);
}
WM_main(C);
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 2d86587d096..d3cec093980 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -1995,7 +1995,6 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data)
/* Just pretend a file was loaded, so the user can press Save and it'll
* save at the filename from the CLI. */
STRNCPY(G_MAIN->filepath, filename);
- G.relbase_valid = true;
printf("... opened default scene instead; saving will write to: %s\n", filename);
}
else {
diff --git a/source/tools b/source/tools
-Subproject b22d19e47f4d0353082f3d9f30ee8d244c5266d
+Subproject 26bc78162ec89f21453ce3ded7b999bc6649f32